src/js/model.js
changeset 1072 ac1eacb3aa33
parent 1068 7623f9af9272
equal deleted inserted replaced
1071:02c04d2c8fd8 1072:ac1eacb3aa33
     1 
       
     2 /* js is where data is stored in a standard form, whatever the serializer */
     1 /* js is where data is stored in a standard form, whatever the serializer */
     3 
     2 
     4 //TODO: Separate Project-specific data from Source
     3 //TODO: Separate Project-specific data from Source
     5 
     4 import _ from "lodash";
     6 IriSP.Model = (function (ns) {
     5 import jQuery from "jquery";
     7     
     6 
     8     function pad(n, x, b) {
     7 const Model = function (ns) {
     9         b = b || 10;
     8   function pad(n, x, b) {
    10         var s = (x).toString(b);
     9     b = b || 10;
    11         while (s.length < n) {
    10     var s = x.toString(b);
    12             s = "0" + s;
    11     while (s.length < n) {
       
    12       s = "0" + s;
       
    13     }
       
    14     return s;
       
    15   }
       
    16 
       
    17   function rand16(n) {
       
    18     return pad(n, Math.floor(Math.random() * Math.pow(16, n)), 16);
       
    19   }
       
    20 
       
    21   var uidbase = rand16(8) + "-" + rand16(4) + "-",
       
    22     uidincrement = Math.floor(Math.random() * 0x10000);
       
    23 
       
    24   var charsub = ["[aáàâä]", "[cç]", "[eéèêë]", "[iíìîï]", "[oóòôö]", "[uùûü]"];
       
    25 
       
    26   var removeChars = [
       
    27     String.fromCharCode(768),
       
    28     String.fromCharCode(769),
       
    29     String.fromCharCode(770),
       
    30     String.fromCharCode(771),
       
    31     String.fromCharCode(807),
       
    32     "{",
       
    33     "}",
       
    34     "(",
       
    35     ")",
       
    36     "[",
       
    37     "]",
       
    38     "【",
       
    39     "】",
       
    40     "、",
       
    41     "・",
       
    42     "‥",
       
    43     "。",
       
    44     "「",
       
    45     "」",
       
    46     "『",
       
    47     "』",
       
    48     "〜",
       
    49     ":",
       
    50     "!",
       
    51     "?",
       
    52     " ",
       
    53     ",",
       
    54     " ",
       
    55     ";",
       
    56     "(",
       
    57     ")",
       
    58     ".",
       
    59     "*",
       
    60     "+",
       
    61     "\\",
       
    62     "?",
       
    63     "|",
       
    64     "{",
       
    65     "}",
       
    66     "[",
       
    67     "]",
       
    68     "^",
       
    69     "#",
       
    70     "/",
       
    71   ];
       
    72 
       
    73   var Model = {},
       
    74     _SOURCE_STATUS_EMPTY = (Model._SOURCE_STATUS_EMPTY = 0),
       
    75     _SOURCE_STATUS_WAITING = (Model._SOURCE_STATUS_WAITING = 1),
       
    76     _SOURCE_STATUS_READY = (Model._SOURCE_STATUS_READY = 2),
       
    77     extendPrototype = (Model.extendPrototype = function (toClass, fromClass) {
       
    78       var fromP = fromClass.prototype,
       
    79         toP = toClass.prototype;
       
    80       for (var k in fromP) {
       
    81         if (fromP.hasOwnProperty(k)) {
       
    82           toP[k] = fromP[k];
    13         }
    83         }
    14         return s;
    84       }
    15     }
    85     }),
    16     
    86     getUID = (Model.getUID = function () {
    17     function rand16(n) {
    87       return (
    18         return pad(n, Math.floor(Math.random()*Math.pow(16,n)), 16);
    88         uidbase +
    19     }
    89         pad(4, ++uidincrement % 0x10000, 16) +
    20     
    90         "-" +
    21     var uidbase = rand16(8) + "-" + rand16(4) + "-", uidincrement = Math.floor(Math.random()*0x10000);
    91         rand16(4) +
    22     
    92         "-" +
    23     var charsub = [
    93         rand16(6) +
    24         '[aáàâä]',
    94         rand16(6)
    25         '[cç]',
    95       );
    26         '[eéèêë]',
    96     }),
    27         '[iíìîï]',
    97     isLocalURL = (Model.isLocalURL = function (url) {
    28         '[oóòôö]',
    98       var matches = url.match(/^(\w+:)\/\/([^/]+)/);
    29         '[uùûü]'
    99       if (matches) {
    30     ];
   100         return (
    31     
   101           matches[1] === document.location.protocol &&
    32     var removeChars = [
   102           matches[2] === document.location.host
    33         String.fromCharCode(768), String.fromCharCode(769), String.fromCharCode(770), String.fromCharCode(771), String.fromCharCode(807),
   103         );
    34         "{", "}", "(", ")", "[", "]", "【", "】", "、", "・", "‥", "。", "「", "」", "『", "』", "〜", ":", "!", "?", " ",
   104       }
    35         ",", " ", ";", "(", ")", ".", "*", "+", "\\", "?", "|", "{", "}", "[", "]", "^", "#", "/"
   105       return true;
    36     ];
   106     }),
    37     
   107     regexpFromTextOrArray = (Model.regexpFromTextOrArray = function (
    38 var Model = {},
   108       _textOrArray,
    39     _SOURCE_STATUS_EMPTY = Model._SOURCE_STATUS_EMPTY = 0,
   109       _testOnly,
    40     _SOURCE_STATUS_WAITING = Model._SOURCE_STATUS_WAITING = 1,
   110       _iexact
    41     _SOURCE_STATUS_READY = Model._SOURCE_STATUS_READY = 2,
   111     ) {
    42     extendPrototype = Model.extendPrototype = function(toClass, fromClass) {
   112       var _testOnly = _testOnly || false,
    43         var fromP = fromClass.prototype,
   113         _iexact = _iexact || false;
    44             toP = toClass.prototype;
   114       function escapeText(_text) {
    45         for (var k in fromP) {
   115         return _text.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, "\\$1");
    46             if (fromP.hasOwnProperty(k)) {
   116       }
    47                 toP[k] = fromP[k];
   117       var _source =
    48             }
   118           typeof _textOrArray === "string"
       
   119             ? escapeText(_textOrArray)
       
   120             : _(_textOrArray).map(escapeText).join("|"),
       
   121         _flags = "im";
       
   122       if (!_testOnly) {
       
   123         _source = "(" + _source + ")";
       
   124         _flags += "g";
       
   125       }
       
   126       if (_iexact) {
       
   127         _source = "^" + _source + "$";
       
   128       }
       
   129       return new RegExp(_source, _flags);
       
   130     }),
       
   131     fullTextRegexps = (Model.fullTextRegexps = function (_text) {
       
   132       var remsrc = "[\\" + removeChars.join("\\") + "]",
       
   133         remrx = new RegExp(remsrc, "gm"),
       
   134         txt = _text.toLowerCase().replace(remrx, ""),
       
   135         res = [],
       
   136         charsrx = _(charsub).map(function (c) {
       
   137           return new RegExp(c);
       
   138         }),
       
   139         src = "";
       
   140       for (var j = 0; j < txt.length; j++) {
       
   141         if (j) {
       
   142           src += remsrc + "*";
    49         }
   143         }
    50     },
   144         var l = txt[j];
    51     getUID = Model.getUID = function() {
   145         _(charsub).each(function (v, k) {
    52         return uidbase + pad(4, (++uidincrement % 0x10000), 16) + "-" + rand16(4) + "-" + rand16(6) + rand16(6);
   146           l = l.replace(charsrx[k], v);
    53     },
   147         });
    54     isLocalURL = Model.isLocalURL = function(url) {
   148         src += l;
    55         var matches = url.match(/^(\w+:)\/\/([^/]+)/);
   149       }
    56         if (matches) {
   150       return "(" + src + ")";
    57             return(matches[1] === document.location.protocol && matches[2] === document.location.host);
   151     }),
    58         }
   152     isoToDate = (Model.isoToDate = function (_str) {
    59         return true;
   153       // http://delete.me.uk/2005/03/iso8601.html
    60     },
   154       var regexp =
    61     regexpFromTextOrArray = Model.regexpFromTextOrArray = function(_textOrArray, _testOnly, _iexact) {
   155         "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    62         var _testOnly = _testOnly || false,
   156       var d = _str.match(new RegExp(regexp));
    63             _iexact = _iexact || false;
   157 
    64         function escapeText(_text) {
   158       var offset = 0;
    65             return _text.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, '\\$1');
   159       var date = new Date(d[1], 0, 1);
    66         }
   160 
    67         var _source = 
   161       if (d[3]) {
    68             typeof _textOrArray === "string"
   162         date.setMonth(d[3] - 1);
    69             ? escapeText(_textOrArray)
   163       }
    70             : ns._(_textOrArray).map(escapeText).join("|"),
   164       if (d[5]) {
    71             _flags = 'im';
   165         date.setDate(d[5]);
    72         if (!_testOnly) {
   166       }
    73             _source = '(' + _source + ')';
   167       if (d[7]) {
    74             _flags += 'g';
   168         date.setHours(d[7]);
    75         }
   169       }
    76         if (_iexact) {
   170       if (d[8]) {
    77             _source = '^' + _source + '$';
   171         date.setMinutes(d[8]);
    78         }
   172       }
    79         return new RegExp( _source, _flags);
   173       if (d[10]) {
    80     },
   174         date.setSeconds(d[10]);
    81     fullTextRegexps = Model.fullTextRegexps = function(_text) {
   175       }
    82         var remsrc = "[\\" + removeChars.join("\\") + "]",
   176       if (d[12]) {
    83             remrx = new RegExp(remsrc,"gm"),
   177         date.setMilliseconds(Number("0." + d[12]) * 1000);
    84             txt = _text.toLowerCase().replace(remrx,""),
   178       }
    85             res = [],
   179       if (d[14]) {
    86             charsrx = ns._(charsub).map(function(c) {
   180         offset = Number(d[16]) * 60 + Number(d[17]);
    87                 return new RegExp(c);
   181         offset *= d[15] == "-" ? 1 : -1;
    88             }),
   182       }
    89             src = "";
   183 
    90         for (var j = 0; j < txt.length; j++) {
   184       offset -= date.getTimezoneOffset();
    91             if (j) {
   185       const time = Number(date) + offset * 60 * 1000;
    92                 src += remsrc + "*";
   186       var _res = new Date();
    93             }
   187       _res.setTime(Number(time));
    94             var l = txt[j];
   188       return _res;
    95             ns._(charsub).each(function(v, k) {
   189     }),
    96                 l = l.replace(charsrx[k], v);
   190     dateToIso = (Model.dateToIso = function (_d) {
    97             });
   191       var d = _d ? new Date(_d) : new Date();
    98             src += l;
   192       return (
    99         }
   193         d.getUTCFullYear() +
   100         return "(" + src + ")";
   194         "-" +
   101     },
   195         pad(2, d.getUTCMonth() + 1) +
   102     isoToDate = Model.isoToDate = function(_str) {
   196         "-" +
   103         // http://delete.me.uk/2005/03/iso8601.html
   197         pad(2, d.getUTCDate()) +
   104         var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
   198         "T" +
   105         var d = _str.match(new RegExp(regexp));
   199         pad(2, d.getUTCHours()) +
   106     
   200         ":" +
   107         var offset = 0;
   201         pad(2, d.getUTCMinutes()) +
   108         var date = new Date(d[1], 0, 1);
   202         ":" +
   109     
   203         pad(2, d.getUTCSeconds()) +
   110         if (d[3]) { date.setMonth(d[3] - 1); }
   204         "Z"
   111         if (d[5]) { date.setDate(d[5]); }
   205       );
   112         if (d[7]) { date.setHours(d[7]); }
   206     });
   113         if (d[8]) { date.setMinutes(d[8]); }
   207 
   114         if (d[10]) { date.setSeconds(d[10]); }
   208   /*
   115         if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
   209    * List is a class for a list of elements (e.g. annotations, medias, etc. that each have a distinct ID)
   116         if (d[14]) {
   210    */
   117             offset = (Number(d[16]) * 60) + Number(d[17]);
   211   var List = (Model.List = function (_directory) {
   118             offset *= ((d[15] == '-') ? 1 : -1);
       
   119         }
       
   120     
       
   121         offset -= date.getTimezoneOffset();
       
   122         time = (Number(date) + (offset * 60 * 1000));
       
   123         var _res = new Date();
       
   124         _res.setTime(Number(time));
       
   125         return _res;
       
   126     },
       
   127     dateToIso = Model.dateToIso = function(_d) {
       
   128         var d = _d ? new Date(_d) : new Date();
       
   129         return d.getUTCFullYear()+'-'  
       
   130             + pad(2, d.getUTCMonth()+1)+'-'  
       
   131             + pad(2, d.getUTCDate())+'T'  
       
   132             + pad(2, d.getUTCHours())+':'  
       
   133             + pad(2, d.getUTCMinutes())+':'  
       
   134             + pad(2, d.getUTCSeconds())+'Z'  ;
       
   135     };
       
   136 
       
   137 /*
       
   138  * List is a class for a list of elements (e.g. annotations, medias, etc. that each have a distinct ID)
       
   139  */
       
   140 var List = Model.List = function(_directory) {
       
   141     Array.call(this);
   212     Array.call(this);
   142     this.directory = _directory;
   213     this.directory = _directory;
   143     this.idIndex = [];
   214     this.idIndex = [];
   144     this.__events = {};
   215     this.__events = {};
   145     if (typeof _directory == "undefined") {
   216     if (typeof _directory == "undefined") {
   146         console.trace();
   217       console.trace();
   147         throw "Error : new List(directory): directory is undefined";
   218       throw "Error : new List(directory): directory is undefined";
   148     }
   219     }
   149     var _this =  this;
   220     var _this = this;
   150     this.on("clear-search", function() {
   221     this.on("clear-search", function () {
   151         _this.searching = false;
   222       _this.searching = false;
   152         _this.regexp = undefined;
   223       _this.regexp = undefined;
   153         _this.forEach(function(_element) {
   224       _this.forEach(function (_element) {
   154             _element.found = undefined;
   225         _element.found = undefined;
   155         });
   226       });
   156         _this.trigger("search-cleared");
   227       _this.trigger("search-cleared");
   157     });
   228     });
   158 };
   229   });
   159 
   230 
   160 List.prototype = new Array();
   231   List.prototype = new Array();
   161 
   232 
   162 List.prototype.hasId = function(_id) {
   233   List.prototype.hasId = function (_id) {
   163     return ns._(this.idIndex).include(_id);
   234     return _(this.idIndex).includes(_id);
   164 };
   235   };
   165 
   236 
   166 /* On recent browsers, forEach and map are defined and do what we want.
   237   /* On recent browsers, forEach and map are defined and do what we want.
   167  * Otherwise, we'll use the Underscore.js functions
   238    * Otherwise, we'll use the Underscore.js functions
   168  */
   239    */
   169 if (typeof Array.prototype.forEach === "undefined") {
   240   if (typeof Array.prototype.forEach === "undefined") {
   170     List.prototype.forEach = function(_callback) {
   241     List.prototype.forEach = function (_callback) {
   171         var _this = this;
   242       var _this = this;
   172         ns._(this).forEach(function(_value, _key) {
   243       _(this).forEach(function (_value, _key) {
   173             _callback(_value, _key, _this);
   244         _callback(_value, _key, _this);
   174         });
   245       });
   175     };
   246     };
   176 };
   247   }
   177 
   248 
   178 if (typeof Array.prototype.map === "undefined") {
   249   if (typeof Array.prototype.map === "undefined") {
   179     List.prototype.map = function(_callback) {
   250     List.prototype.map = function (_callback) {
   180         var _this = this;
   251       var _this = this;
   181         return ns._(this).map(function(_value, _key) {
   252       return _(this).map(function (_value, _key) {
   182             return _callback(_value, _key, _this);
   253         return _callback(_value, _key, _this);
   183         });
   254       });
   184     };
   255     };
   185 };
   256   }
   186 
   257 
   187 List.prototype.pluck = function(_key) {
   258   List.prototype.pluck = function (_key) {
   188     return this.map(function(_value) {
   259     return this.map(function (_value) {
   189         return _value[_key];
   260       return _value[_key];
   190     });
   261     });
   191 };
   262   };
   192 
   263 
   193 /* We override Array's filter function because it doesn't return an List
   264   /* We override Array's filter function because it doesn't return an List
   194  */
   265    */
   195 List.prototype.filter = function(_callback) {
   266   List.prototype.filter = function (_callback) {
   196     var _this = this,
   267     var _this = this,
   197         _res = new List(this.directory);
   268       _res = new List(this.directory);
   198     _res.addElements(ns._(this).filter(function(_value, _key) {
   269     _res.addElements(
       
   270       _(this).filter(function (_value, _key) {
   199         return _callback(_value, _key, _this);
   271         return _callback(_value, _key, _this);
   200     }));
   272       })
       
   273     );
   201     return _res;
   274     return _res;
   202 };
   275   };
   203 
   276 
   204 List.prototype.slice = function(_start, _end) {
   277   List.prototype.slice = function (_start, _end) {
   205     var _res = new List(this.directory);
   278     var _res = new List(this.directory);
   206     _res.addElements(Array.prototype.slice.call(this, _start, _end));
   279     _res.addElements(Array.prototype.slice.call(this, _start, _end));
   207     return _res;
   280     return _res;
   208 };
   281   };
   209 
   282 
   210 List.prototype.splice = function(_start, _end) {
   283   List.prototype.splice = function (_start, _end) {
   211     var _res = new List(this.directory);
   284     var _res = new List(this.directory);
   212     _res.addElements(Array.prototype.splice.call(this, _start, _end));
   285     _res.addElements(Array.prototype.splice.call(this, _start, _end));
   213     this.idIndex.splice(_start, _end);
   286     this.idIndex.splice(_start, _end);
   214     return _res;
   287     return _res;
   215 };
   288   };
   216 
   289 
   217 /* Array has a sort function, but it's not as interesting as Underscore.js's sortBy
   290   /* Array has a sort function, but it's not as interesting as Underscore.js's sortBy
   218  * and won't return a new List
   291    * and won't return a new List
   219  */
   292    */
   220 List.prototype.sortBy = function(_callback) {
   293   List.prototype.sortBy = function (_callback) {
   221     var _this = this,
   294     var _this = this,
   222         _res = new List(this.directory);
   295       _res = new List(this.directory);
   223     _res.addElements(ns._(this).sortBy(function(_value, _key) {
   296     _res.addElements(
       
   297       _(this).sortBy(function (_value, _key) {
   224         return _callback(_value, _key, _this);
   298         return _callback(_value, _key, _this);
   225     }));
   299       })
       
   300     );
   226     return _res;
   301     return _res;
   227 };
   302   };
   228 
   303 
   229 /* Title and Description are basic information for (almost) all element types,
   304   /* Title and Description are basic information for (almost) all element types,
   230  * here we can search by these criteria
   305    * here we can search by these criteria
   231  */
   306    */
   232 List.prototype.searchByTitle = function(_text, _iexact) {
   307   List.prototype.searchByTitle = function (_text, _iexact) {
   233     var _iexact = _iexact || false,
   308     var _iexact = _iexact || false,
   234         _rgxp = regexpFromTextOrArray(_text, true, _iexact);
   309       _rgxp = regexpFromTextOrArray(_text, true, _iexact);
   235     return this.filter(function(_element) {
   310     return this.filter(function (_element) {
   236         return _rgxp.test(_element.title);
   311       return _rgxp.test(_element.title);
   237     });
   312     });
   238 };
   313   };
   239 
   314 
   240 List.prototype.searchByDescription = function(_text, _iexact) {
   315   List.prototype.searchByDescription = function (_text, _iexact) {
   241     var _iexact = _iexact || false,
   316     var _iexact = _iexact || false,
   242         _rgxp = regexpFromTextOrArray(_text, true, _iexact);
   317       _rgxp = regexpFromTextOrArray(_text, true, _iexact);
   243     return this.filter(function(_element) {
   318     return this.filter(function (_element) {
   244         return _rgxp.test(_element.description);
   319       return _rgxp.test(_element.description);
   245     });
   320     });
   246 };
   321   };
   247 
   322 
   248 List.prototype.searchByTextFields = function(_text, _iexact) {
   323   List.prototype.searchByTextFields = function (_text, _iexact) {
   249     var _iexact = _iexact || false,
   324     var _iexact = _iexact || false,
   250         _rgxp =  regexpFromTextOrArray(_text, true, _iexact);
   325       _rgxp = regexpFromTextOrArray(_text, true, _iexact);
   251     return this.filter(function(_element) {
   326     return this.filter(function (_element) {
   252         var keywords = (_element.keywords || _element.getTagTexts() || []).join(", ");
   327       var keywords = (_element.keywords || _element.getTagTexts() || []).join(
   253         return _rgxp.test(_element.description) || _rgxp.test(_element.title) || _rgxp.test(keywords);
   328         ", "
   254     });
   329       );
   255 };
   330       return (
   256 
   331         _rgxp.test(_element.description) ||
   257 List.prototype.search = function(_text) {
   332         _rgxp.test(_element.title) ||
       
   333         _rgxp.test(keywords)
       
   334       );
       
   335     });
       
   336   };
       
   337 
       
   338   List.prototype.search = function (_text) {
   258     if (!_text) {
   339     if (!_text) {
   259         this.trigger("clear-search");
   340       this.trigger("clear-search");
   260         return this;
   341       return this;
   261     }
   342     }
   262     this.searching = true;
   343     this.searching = true;
   263     this.trigger("search", _text);
   344     this.trigger("search", _text);
   264     var rxsource = fullTextRegexps(_text),
   345     var rxsource = fullTextRegexps(_text),
   265         rgxp = new RegExp(rxsource,"im");
   346       rgxp = new RegExp(rxsource, "im");
   266     this.regexp = new RegExp(rxsource,"gim");
   347     this.regexp = new RegExp(rxsource, "gim");
   267     var res = this.filter(function(_element, _k) {
   348     var res = this.filter(function (_element, _k) {
   268         var titlematch = rgxp.test(_element.title),
   349       var titlematch = rgxp.test(_element.title),
   269             descmatch = rgxp.test(_element.description),
   350         descmatch = rgxp.test(_element.description),
   270             _isfound = !!(titlematch || descmatch);
   351         _isfound = !!(titlematch || descmatch);
   271         _element.found = _isfound;
   352       _element.found = _isfound;
   272         _element.trigger(_isfound ? "found" : "not-found");
   353       _element.trigger(_isfound ? "found" : "not-found");
   273         return _isfound;
   354       return _isfound;
   274     });
   355     });
   275     this.trigger(res.length ? "found" : "not-found",res);
   356     this.trigger(res.length ? "found" : "not-found", res);
   276     return res;
   357     return res;
   277 };
   358   };
   278 
   359 
   279 List.prototype.searchByTags = function(_text) {
   360   List.prototype.searchByTags = function (_text) {
   280     if (!_text) {
   361     if (!_text) {
   281         this.trigger("clear-search");
   362       this.trigger("clear-search");
   282         return this;
   363       return this;
   283     }
   364     }
   284     this.searching = true;
   365     this.searching = true;
   285     this.trigger("search", _text);
   366     this.trigger("search", _text);
   286     var rxsource = fullTextRegexps(_text),
   367     var rxsource = fullTextRegexps(_text),
   287         rgxp = new RegExp(rxsource,"im");
   368       rgxp = new RegExp(rxsource, "im");
   288     this.regexp = new RegExp(rxsource,"gim");
   369     this.regexp = new RegExp(rxsource, "gim");
   289     var res = this.filter(function(_element, _k) {
   370     var res = this.filter(function (_element, _k) {
   290         var _isfound = rgxp.test(_element.getTagTexts());
   371       var _isfound = rgxp.test(_element.getTagTexts());
   291         _element.found = _isfound;
   372       _element.found = _isfound;
   292         _element.trigger(_isfound ? "found" : "not-found");
   373       _element.trigger(_isfound ? "found" : "not-found");
   293         return _isfound;
   374       return _isfound;
   294     });
   375     });
   295     this.trigger(res.length ? "found" : "not-found",res);
   376     this.trigger(res.length ? "found" : "not-found", res);
   296     return res;
   377     return res;
   297 };
   378   };
   298 
   379 
   299 List.prototype.getTitles = function() {
   380   List.prototype.getTitles = function () {
   300     return this.map(function(_el) {
   381     return this.map(function (_el) {
   301         return _el.title;
   382       return _el.title;
   302     });
   383     });
   303 };
   384   };
   304 
   385 
   305 List.prototype.addId = function(_id) {
   386   List.prototype.addId = function (_id) {
   306     var _el = this.directory.getElement(_id);
   387     var _el = this.directory.getElement(_id);
   307     if (!this.hasId(_id) && typeof _el !== "undefined") {
   388     if (!this.hasId(_id) && typeof _el !== "undefined") {
   308         this.idIndex.push(_id);
   389       this.idIndex.push(_id);
   309         Array.prototype.push.call(this, _el);
   390       Array.prototype.push.call(this, _el);
   310     }
   391     }
   311 };
   392   };
   312 
   393 
   313 List.prototype.push = function(_el) {
   394   List.prototype.push = function (_el) {
   314     if (typeof _el === "undefined") {
   395     if (typeof _el === "undefined") {
   315         return;
   396       return;
   316     }
   397     }
   317     var _index = (ns._(this.idIndex).indexOf(_el.id));
   398     var _index = _(this.idIndex).indexOf(_el.id);
   318     if (_index === -1) {
   399     if (_index === -1) {
   319         this.idIndex.push(_el.id);
   400       this.idIndex.push(_el.id);
   320         Array.prototype.push.call(this, _el);
   401       Array.prototype.push.call(this, _el);
   321     } else {
   402     } else {
   322         this[_index] = _el;
   403       this[_index] = _el;
   323     }
   404     }
   324 };
   405   };
   325 
   406 
   326 List.prototype.addIds = function(_array) {
   407   List.prototype.addIds = function (_array) {
   327     var _l = _array.length,
   408     var _l = _array.length,
   328         _this = this;
   409       _this = this;
   329     ns._(_array).forEach(function(_id) {
   410     _(_array).forEach(function (_id) {
   330         _this.addId(_id);
   411       _this.addId(_id);
   331     });
   412     });
   332 };
   413   };
   333 
   414 
   334 List.prototype.addElements = function(_array) {
   415   List.prototype.addElements = function (_array) {
   335     var _this = this;
   416     var _this = this;
   336     ns._(_array).forEach(function(_el) {
   417     _(_array).forEach(function (_el) {
   337         _this.push(_el);
   418       _this.push(_el);
   338     });
   419     });
   339 };
   420   };
   340 
   421 
   341 List.prototype.removeId = function(_id, _deleteFromDirectory) {
   422   List.prototype.removeId = function (_id, _deleteFromDirectory) {
   342     var _deleteFromDirectory = _deleteFromDirectory || false,
   423     var _deleteFromDirectory = _deleteFromDirectory || false,
   343         _index = (ns._(this.idIndex).indexOf(_id));
   424       _index = _(this.idIndex).indexOf(_id);
   344     if (_index !== -1) {
   425     if (_index !== -1) {
   345         this.splice(_index,1);
   426       this.splice(_index, 1);
   346     }
   427     }
   347     if (_deleteFromDirectory) {
   428     if (_deleteFromDirectory) {
   348         delete this.directory.elements[_id];
   429       delete this.directory.elements[_id];
   349     }
   430     }
   350 };
   431   };
   351 
   432 
   352 List.prototype.removeElement = function(_el, _deleteFromDirectory) {
   433   List.prototype.removeElement = function (_el, _deleteFromDirectory) {
   353     var _deleteFromDirectory = _deleteFromDirectory || false;
   434     var _deleteFromDirectory = _deleteFromDirectory || false;
   354     this.removeId(_el.id);
   435     this.removeId(_el.id);
   355 };
   436   };
   356 
   437 
   357 List.prototype.removeIds = function(_list, _deleteFromDirectory) {
   438   List.prototype.removeIds = function (_list, _deleteFromDirectory) {
   358     var _deleteFromDirectory = _deleteFromDirectory || false,
   439     var _deleteFromDirectory = _deleteFromDirectory || false,
   359         _this = this;
   440       _this = this;
   360     ns._(_list).forEach(function(_id) {
   441     _(_list).forEach(function (_id) {
   361         _this.removeId(_id);
   442       _this.removeId(_id);
   362     });
   443     });
   363 };
   444   };
   364 
   445 
   365 List.prototype.removeElements = function(_list, _deleteFromDirectory) {
   446   List.prototype.removeElements = function (_list, _deleteFromDirectory) {
   366     var _deleteFromDirectory = _deleteFromDirectory || false,
   447     var _deleteFromDirectory = _deleteFromDirectory || false,
   367         _this = this;
   448       _this = this;
   368     ns._(_list).forEach(function(_el) {
   449     _(_list).forEach(function (_el) {
   369         _this.removeElement(_el);
   450       _this.removeElement(_el);
   370     });
   451     });
   371 };
   452   };
   372 
   453 
   373 List.prototype.on = function(_event, _callback) {
   454   List.prototype.on = function (_event, _callback) {
   374     if (typeof this.__events[_event] === "undefined") {
   455     if (typeof this.__events[_event] === "undefined") {
   375         this.__events[_event] = [];
   456       this.__events[_event] = [];
   376     }
   457     }
   377     this.__events[_event].push(_callback);
   458     this.__events[_event].push(_callback);
   378 };
   459   };
   379 
   460 
   380 List.prototype.off = function(_event, _callback) {
   461   List.prototype.off = function (_event, _callback) {
   381     if (typeof this.__events[_event] !== "undefined") {
   462     if (typeof this.__events[_event] !== "undefined") {
   382         this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) {
   463       this.__events[_event] = ns
   383             return _fn === _callback;
   464         ._(this.__events[_event])
       
   465         .reject(function (_fn) {
       
   466           return _fn === _callback;
   384         });
   467         });
   385     }
   468     }
   386 };
   469   };
   387 
   470 
   388 List.prototype.trigger = function(_event, _data) {
   471   List.prototype.trigger = function (_event, _data) {
   389     var _list = this;
   472     var _list = this;
   390     ns._(this.__events[_event]).each(function(_callback) {
   473     _(this.__events[_event]).each(function (_callback) {
   391         _callback.call(_list, _data);
   474       _callback.call(_list, _data);
   392     });
   475     });
   393 };
   476   };
   394 
   477 
   395 /* A simple time management object, that helps converting millisecs to seconds and strings,
   478   /* A simple time management object, that helps converting millisecs to seconds and strings,
   396  * without the clumsiness of the original Date object.
   479    * without the clumsiness of the original Date object.
   397  */
   480    */
   398 
   481 
   399 var Time = Model.Time = function(_milliseconds) {
   482   var Time = (Model.Time = function (_milliseconds) {
   400     this.milliseconds = 0;
   483     this.milliseconds = 0;
   401     this.setMilliseconds(_milliseconds);
   484     this.setMilliseconds(_milliseconds);
   402 };
   485   });
   403 
   486 
   404 Time.prototype.setMilliseconds = function(_milliseconds) {
   487   Time.prototype.setMilliseconds = function (_milliseconds) {
   405     var _ante = this.milliseconds;
   488     var _ante = this.milliseconds;
   406     switch(typeof _milliseconds) {
   489     switch (typeof _milliseconds) {
   407         case "string":
   490       case "string":
   408             this.milliseconds = parseInt(_milliseconds);
   491         this.milliseconds = parseInt(_milliseconds);
   409             break;
   492         break;
   410         case "number":
   493       case "number":
   411             this.milliseconds = Math.floor(_milliseconds);
   494         this.milliseconds = Math.floor(_milliseconds);
   412             break;
   495         break;
   413         case "object":
   496       case "object":
   414             this.milliseconds = parseInt(_milliseconds.valueOf());
   497         this.milliseconds = parseInt(_milliseconds.valueOf());
   415             break;
   498         break;
   416         default:
   499       default:
   417             this.milliseconds = 0;
   500         this.milliseconds = 0;
   418     }
   501     }
   419     if (this.milliseconds === NaN) {
   502     if (this.milliseconds === NaN) {
   420         this.milliseconds = _ante;
   503       this.milliseconds = _ante;
   421     }
   504     }
   422 };
   505   };
   423 
   506 
   424 Time.prototype.setSeconds = function(_seconds) {
   507   Time.prototype.setSeconds = function (_seconds) {
   425     this.milliseconds = 1000 * _seconds;
   508     this.milliseconds = 1000 * _seconds;
   426 };
   509   };
   427 
   510 
   428 Time.prototype.getSeconds = function() {
   511   Time.prototype.getSeconds = function () {
   429     return this.milliseconds / 1000;
   512     return this.milliseconds / 1000;
   430 };
   513   };
   431 
   514 
   432 Time.prototype.getHMS = function() {
   515   Time.prototype.getHMS = function () {
   433     var _totalSeconds = Math.abs(Math.floor(this.getSeconds()));
   516     var _totalSeconds = Math.abs(Math.floor(this.getSeconds()));
   434     return {
   517     return {
   435         hours : Math.floor(_totalSeconds / 3600),
   518       hours: Math.floor(_totalSeconds / 3600),
   436         minutes : (Math.floor(_totalSeconds / 60) % 60),
   519       minutes: Math.floor(_totalSeconds / 60) % 60,
   437         seconds : _totalSeconds % 60,
   520       seconds: _totalSeconds % 60,
   438         milliseconds: this.milliseconds % 1000
   521       milliseconds: this.milliseconds % 1000,
   439     };
   522     };
   440 };
   523   };
   441 
   524 
   442 Time.prototype.add = function(_milliseconds) {
   525   Time.prototype.add = function (_milliseconds) {
   443     this.milliseconds += new Time(_milliseconds).milliseconds;
   526     this.milliseconds += new Time(_milliseconds).milliseconds;
   444 };
   527   };
   445 
   528 
   446 Time.prototype.valueOf = function() {
   529   Time.prototype.valueOf = function () {
   447     return this.milliseconds;
   530     return this.milliseconds;
   448 };
   531   };
   449 
   532 
   450 Time.prototype.toString = function(showCs) {
   533   Time.prototype.toString = function (showCs) {
   451     var _hms = this.getHMS(),
   534     var _hms = this.getHMS(),
   452         _res = '';
   535       _res = "";
   453     if (_hms.hours) {
   536     if (_hms.hours) {
   454         _res += _hms.hours + ':';
   537       _res += _hms.hours + ":";
   455     }
   538     }
   456     _res += pad(2, _hms.minutes) + ':' + pad(2, _hms.seconds);
   539     _res += pad(2, _hms.minutes) + ":" + pad(2, _hms.seconds);
   457     if (showCs) {
   540     if (showCs) {
   458         _res += "." + Math.floor(_hms.milliseconds / 100);
   541       _res += "." + Math.floor(_hms.milliseconds / 100);
   459     }
   542     }
   460     return _res;
   543     return _res;
   461 };
   544   };
   462 
   545 
   463 /* Reference handles references between elements
   546   /* Reference handles references between elements
   464  */
   547    */
   465 
   548 
   466 var Reference = Model.Reference = function(_source, _idRef) {
   549   var Reference = (Model.Reference = function (_source, _idRef) {
   467     this.source = _source;
   550     this.source = _source;
   468     this.id = _idRef;
   551     this.id = _idRef;
   469     if (typeof _idRef === "object") {
   552     if (typeof _idRef === "object") {
   470         this.isList = true;
   553       this.isList = true;
   471     } else {
   554     } else {
   472         this.isList = false;
   555       this.isList = false;
   473     }
   556     }
   474     this.refresh();
   557     this.refresh();
   475 };
   558   });
   476 
   559 
   477 Reference.prototype.refresh = function() {
   560   Reference.prototype.refresh = function () {
   478     if (this.isList) {
   561     if (this.isList) {
   479         this.contents = new List(this.source.directory);
   562       this.contents = new List(this.source.directory);
   480         this.contents.addIds(this.id);
   563       this.contents.addIds(this.id);
   481     } else {
   564     } else {
   482         this.contents = this.source.getElement(this.id);
   565       this.contents = this.source.getElement(this.id);
   483     }
   566     }
   484     
   567   };
   485 };
   568 
   486 
   569   Reference.prototype.getContents = function () {
   487 Reference.prototype.getContents = function() {
   570     if (
   488     if (typeof this.contents === "undefined" || (this.isList && this.contents.length != this.id.length)) {
   571       typeof this.contents === "undefined" ||
   489         this.refresh();
   572       (this.isList && this.contents.length != this.id.length)
       
   573     ) {
       
   574       this.refresh();
   490     }
   575     }
   491     return this.contents;
   576     return this.contents;
   492 };
   577   };
   493 
   578 
   494 Reference.prototype.isOrHasId = function(_idRef) {
   579   Reference.prototype.isOrHasId = function (_idRef) {
   495     if (this.isList) {
   580     if (this.isList) {
   496         return (ns._(this.id).indexOf(_idRef) !== -1);
   581       return _(this.id).indexOf(_idRef) !== -1;
   497     } else {
   582     } else {
   498         return (this.id == _idRef);
   583       return this.id == _idRef;
   499     }
   584     }
   500 };
   585   };
   501 
   586 
   502 /* */
   587   /* */
   503 
   588 
   504 var BaseElement = Model.Element = function(_id, _source) {
   589   var BaseElement = (Model.Element = function (_id, _source) {
   505     this.elementType = 'element';
   590     this.elementType = "element";
   506     this.title = "";
   591     this.title = "";
   507     this.description = "";
   592     this.description = "";
   508     this.__events = {};
   593     this.__events = {};
   509     if (typeof _source === "undefined") {
   594     if (typeof _source === "undefined") {
   510         return;
   595       return;
   511     }
   596     }
   512     if (typeof _id === "undefined" || !_id) {
   597     if (typeof _id === "undefined" || !_id) {
   513         _id = getUID();
   598       _id = getUID();
   514     }
   599     }
   515     this.id = _id;
   600     this.id = _id;
   516     this.source = _source;
   601     this.source = _source;
   517     if (_source !== this) {
   602     if (_source !== this) {
   518         this.source.directory.addElement(this);
   603       this.source.directory.addElement(this);
   519     }
   604     }
   520 };
   605   });
   521 
   606 
   522 BaseElement.prototype.toString = function() {
   607   BaseElement.prototype.toString = function () {
   523     return this.elementType + (this.elementType !== 'element' ? ', id=' + this.id + ', title="' + this.title + '"' : '');
   608     return (
   524 };
   609       this.elementType +
   525 
   610       (this.elementType !== "element"
   526 BaseElement.prototype.setReference = function(_elementType, _idRef) {
   611         ? ", id=" + this.id + ', title="' + this.title + '"'
       
   612         : "")
       
   613     );
       
   614   };
       
   615 
       
   616   BaseElement.prototype.setReference = function (_elementType, _idRef) {
   527     this[_elementType] = new Reference(this.source, _idRef);
   617     this[_elementType] = new Reference(this.source, _idRef);
   528 };
   618   };
   529 
   619 
   530 BaseElement.prototype.getReference = function(_elementType) {
   620   BaseElement.prototype.getReference = function (_elementType) {
   531     if (typeof this[_elementType] !== "undefined") {
   621     if (typeof this[_elementType] !== "undefined") {
   532         return this[_elementType].getContents();
   622       return this[_elementType].getContents();
   533     }
   623     }
   534 };
   624   };
   535 
   625 
   536 BaseElement.prototype.getRelated = function(_elementType, _global) {
   626   BaseElement.prototype.getRelated = function (_elementType, _global) {
   537     _global = (typeof _global !== "undefined" && _global);
   627     _global = typeof _global !== "undefined" && _global;
   538     var _this = this;
   628     var _this = this;
   539     return this.source.getList(_elementType, _global).filter(function(_el) {
   629     return this.source.getList(_elementType, _global).filter(function (_el) {
   540         var _ref = _el[_this.elementType];
   630       var _ref = _el[_this.elementType];
   541         return _ref && _ref.isOrHasId(_this.id);
   631       return _ref && _ref.isOrHasId(_this.id);
   542     });
   632     });
   543 };
   633   };
   544 
   634 
   545 BaseElement.prototype.on = function(_event, _callback) {
   635   BaseElement.prototype.on = function (_event, _callback) {
   546     if (typeof this.__events[_event] === "undefined") {
   636     if (typeof this.__events[_event] === "undefined") {
   547         this.__events[_event] = [];
   637       this.__events[_event] = [];
   548     }
   638     }
   549     this.__events[_event].push(_callback);
   639     this.__events[_event].push(_callback);
   550 };
   640   };
   551 
   641 
   552 BaseElement.prototype.off = function(_event, _callback) {
   642   BaseElement.prototype.off = function (_event, _callback) {
   553     if (typeof this.__events[_event] !== "undefined") {
   643     if (typeof this.__events[_event] !== "undefined") {
   554         this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) {
   644       this.__events[_event] = _(this.__events[_event]).reject(function (_fn) {
   555             return _fn === _callback;
   645         return _fn === _callback;
   556         });
   646       });
   557     }
   647     }
   558 };
   648   };
   559 
   649 
   560 BaseElement.prototype.trigger = function(_event, _data) {
   650   BaseElement.prototype.trigger = function (_event, _data) {
   561     var _element = this;
   651     var _element = this;
   562     ns._(this.__events[_event]).each(function(_callback) {
   652     _(this.__events[_event]).each(function (_callback) {
   563         _callback.call(_element, _data);
   653       _callback.call(_element, _data);
   564     });
   654     });
   565 };
   655   };
   566 
   656 
   567 /* */
   657   /* */
   568 
   658 
   569 var Playable = Model.Playable = function(_id, _source) {
   659   var Playable = (Model.Playable = function (_id, _source) {
   570     BaseElement.call(this, _id, _source);
   660     BaseElement.call(this, _id, _source);
   571     if (typeof _source === "undefined") {
   661     if (typeof _source === "undefined") {
   572         return;
   662       return;
   573     }
   663     }
   574     this.elementType = 'playable';
   664     this.elementType = "playable";
   575     this.currentTime = new Time();
   665     this.currentTime = new Time();
   576     this.volume = .5;
   666     this.volume = 0.5;
   577     this.paused = true;
   667     this.paused = true;
   578     this.muted = false;
   668     this.muted = false;
   579     this.timeRange = false;
   669     this.timeRange = false;
   580     this.loadedMetadata = false;
   670     this.loadedMetadata = false;
   581     var _this = this;
   671     var _this = this;
   582     this.on("play", function() {
   672     this.on("play", function () {
   583         _this.paused = false;
   673       _this.paused = false;
   584     });
   674     });
   585     this.on("pause", function() {
   675     this.on("pause", function () {
   586         _this.paused = true;
   676       _this.paused = true;
   587     });
   677     });
   588     this.on("timeupdate", function(_time) {
   678     this.on("timeupdate", function (_time) {
   589         _this.currentTime = _time;
   679       _this.currentTime = _time;
   590         _this.getAnnotations().filter(function(_a) {
   680       _this
   591             return (_a.end <= _time || _a.begin > _time) && _a.playing;
   681         .getAnnotations()
   592         }).forEach(function(_a) {
   682         .filter(function (_a) {
   593             _a.playing = false;
   683           return (_a.end <= _time || _a.begin > _time) && _a.playing;
   594             _a.trigger("leave");
   684         })
   595             _this.trigger("leave-annotation",_a);
   685         .forEach(function (_a) {
       
   686           _a.playing = false;
       
   687           _a.trigger("leave");
       
   688           _this.trigger("leave-annotation", _a);
   596         });
   689         });
   597         _this.getAnnotations().filter(function(_a) {
   690       _this
   598             return _a.begin <= _time && _a.end > _time && !_a.playing;
   691         .getAnnotations()
   599         }).forEach(function(_a) {
   692         .filter(function (_a) {
   600             _a.playing = true;
   693           return _a.begin <= _time && _a.end > _time && !_a.playing;
   601             _a.trigger("enter");
   694         })
   602             _this.trigger("enter-annotation",_a);
   695         .forEach(function (_a) {
       
   696           _a.playing = true;
       
   697           _a.trigger("enter");
       
   698           _this.trigger("enter-annotation", _a);
   603         });
   699         });
   604         
   700 
   605         if (_this.getTimeRange()){
   701       if (_this.getTimeRange()) {
   606             if (_this.getTimeRange()[0] > _time) {
   702         if (_this.getTimeRange()[0] > _time) {
   607                 _this.pause();
   703           _this.pause();
   608                 _this.setCurrentTime(_this.getTimeRange()[0]);
   704           _this.setCurrentTime(_this.getTimeRange()[0]);
   609             }
       
   610             if (_this.getTimeRange()[1] < _time){
       
   611                 _this.pause();
       
   612                 _this.setCurrentTime(_this.getTimeRange()[1]);
       
   613             }
       
   614         }
   705         }
   615         
   706         if (_this.getTimeRange()[1] < _time) {
   616     });
   707           _this.pause();
   617     this.on("loadedmetadata", function() {
   708           _this.setCurrentTime(_this.getTimeRange()[1]);
   618         _this.loadedMetadata = true;
   709         }
   619     });
   710       }
   620 };
   711     });
   621 
   712     this.on("loadedmetadata", function () {
   622 extendPrototype(Playable, BaseElement);
   713       _this.loadedMetadata = true;
   623 
   714     });
   624 Playable.prototype.getCurrentTime = function() { 
   715   });
       
   716 
       
   717   extendPrototype(Playable, BaseElement);
       
   718 
       
   719   Playable.prototype.getCurrentTime = function () {
   625     return this.currentTime;
   720     return this.currentTime;
   626 };
   721   };
   627 
   722 
   628 Playable.prototype.getVolume = function() {
   723   Playable.prototype.getVolume = function () {
   629     return this.volume;
   724     return this.volume;
   630 };
   725   };
   631 
   726 
   632 Playable.prototype.getPaused = function() {
   727   Playable.prototype.getPaused = function () {
   633     return this.paused;
   728     return this.paused;
   634 };
   729   };
   635 
   730 
   636 Playable.prototype.getMuted = function() {
   731   Playable.prototype.getMuted = function () {
   637     return this.muted;
   732     return this.muted;
   638 };
   733   };
   639 
   734 
   640 Playable.prototype.getTimeRange = function() {
   735   Playable.prototype.getTimeRange = function () {
   641     return this.timeRange;
   736     return this.timeRange;
   642 }
   737   };
   643 
   738 
   644 Playable.prototype.setCurrentTime = function(_time) {
   739   Playable.prototype.setCurrentTime = function (_time) {
   645     this.trigger("setcurrenttime",_time);
   740     this.trigger("setcurrenttime", _time);
   646 };
   741   };
   647 
   742 
   648 Playable.prototype.setVolume = function(_vol) {
   743   Playable.prototype.setVolume = function (_vol) {
   649     this.trigger("setvolume",_vol);
   744     this.trigger("setvolume", _vol);
   650 };
   745   };
   651 
   746 
   652 Playable.prototype.setMuted = function(_muted) {
   747   Playable.prototype.setMuted = function (_muted) {
   653     this.trigger("setmuted",_muted);
   748     this.trigger("setmuted", _muted);
   654 };
   749   };
   655 
   750 
   656 Playable.prototype.setTimeRange = function(_timeBegin, _timeEnd) {
   751   Playable.prototype.setTimeRange = function (_timeBegin, _timeEnd) {
   657     if ((_timeBegin < _timeEnd)&&(_timeBegin >= 0)&&(_timeEnd>0)){
   752     if (_timeBegin < _timeEnd && _timeBegin >= 0 && _timeEnd > 0) {
   658         return this.trigger("settimerange", [_timeBegin, _timeEnd]);
   753       return this.trigger("settimerange", [_timeBegin, _timeEnd]);
   659     }
   754     }
   660 }
   755   };
   661 
   756 
   662 Playable.prototype.resetTimeRange = function() {
   757   Playable.prototype.resetTimeRange = function () {
   663     return this.trigger("resettimerange");
   758     return this.trigger("resettimerange");
   664 }
   759   };
   665 
   760 
   666 Playable.prototype.play = function() {
   761   Playable.prototype.play = function () {
   667     this.trigger("setplay");
   762     this.trigger("setplay");
   668 };
   763   };
   669 
   764 
   670 Playable.prototype.pause = function() {
   765   Playable.prototype.pause = function () {
   671     this.trigger("setpause");
   766     this.trigger("setpause");
   672 };
   767   };
   673 
   768 
   674 Playable.prototype.show = function() {};
   769   Playable.prototype.show = function () {};
   675 
   770 
   676 Playable.prototype.hide = function() {};
   771   Playable.prototype.hide = function () {};
   677 
   772 
   678 /* */
   773   /* */
   679 
   774 
   680 var Media = Model.Media = function(_id, _source) {
   775   var Media = (Model.Media = function (_id, _source) {
   681     Playable.call(this, _id, _source);
   776     Playable.call(this, _id, _source);
   682     this.elementType = 'media';
   777     this.elementType = "media";
   683     this.duration = new Time();
   778     this.duration = new Time();
   684     this.video = '';
   779     this.video = "";
   685     var _this = this;
   780     var _this = this;
   686 };
   781   });
   687 
   782 
   688 extendPrototype(Media, Playable);
   783   extendPrototype(Media, Playable);
   689 /* */
   784   /* */
   690 
   785 
   691 var Media = Model.Media = function(_id, _source) {
   786   var Media = (Model.Media = function (_id, _source) {
   692     Playable.call(this, _id, _source);
   787     Playable.call(this, _id, _source);
   693     this.elementType = 'media';
   788     this.elementType = "media";
   694     this.duration = new Time();
   789     this.duration = new Time();
   695     this.video = '';
   790     this.video = "";
   696     var _this = this;
   791     var _this = this;
   697 };
   792   });
   698 
   793 
   699 extendPrototype(Media, Playable);
   794   extendPrototype(Media, Playable);
   700 
   795 
   701 /* Default functions to be overriden by players */
   796   /* Default functions to be overriden by players */
   702     
   797 
   703 Media.prototype.setDuration = function(_durationMs) {
   798   Media.prototype.setDuration = function (_durationMs) {
   704     this.duration.setMilliseconds(_durationMs);
   799     this.duration.setMilliseconds(_durationMs);
   705 };
   800   };
   706 
   801 
   707 Media.prototype.getAnnotations = function() {
   802   Media.prototype.getAnnotations = function () {
   708     return this.getRelated("annotation");
   803     return this.getRelated("annotation");
   709 };
   804   };
   710 
   805 
   711 Media.prototype.getAnnotationsByTypeTitle = function(_title) {
   806   Media.prototype.getAnnotationsByTypeTitle = function (_title) {
   712     var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id");
   807     var _annTypes = this.source
       
   808       .getAnnotationTypes()
       
   809       .searchByTitle(_title)
       
   810       .pluck("id");
   713     if (_annTypes.length) {
   811     if (_annTypes.length) {
   714         return this.getAnnotations().filter(function(_annotation) {
   812       return this.getAnnotations().filter(function (_annotation) {
   715             return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
   813         return _(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
   716         });
   814       });
   717     } else {
   815     } else {
   718         return new List(this.source.directory);
   816       return new List(this.source.directory);
   719     }
   817     }
   720 };
   818   };
   721 
   819 
   722 /* */
   820   /* */
   723 
   821 
   724 var Tag = Model.Tag = function(_id, _source) {
   822   var Tag = (Model.Tag = function (_id, _source) {
   725     BaseElement.call(this, _id, _source);
   823     BaseElement.call(this, _id, _source);
   726     this.elementType = 'tag';
   824     this.elementType = "tag";
   727 };
   825   });
   728 
   826 
   729 extendPrototype(Tag, BaseElement);
   827   extendPrototype(Tag, BaseElement);
   730 
   828 
   731 Tag.prototype.getAnnotations = function() {
   829   Tag.prototype.getAnnotations = function () {
   732     return this.getRelated("annotation");
   830     return this.getRelated("annotation");
   733 };
   831   };
   734 
   832 
   735 /* */
   833   /* */
   736 var AnnotationType = Model.AnnotationType = function(_id, _source) {
   834   var AnnotationType = (Model.AnnotationType = function (_id, _source) {
   737     BaseElement.call(this, _id, _source);
   835     BaseElement.call(this, _id, _source);
   738     this.elementType = 'annotationType';
   836     this.elementType = "annotationType";
   739 };
   837   });
   740 
   838 
   741 extendPrototype(AnnotationType, BaseElement);
   839   extendPrototype(AnnotationType, BaseElement);
   742 
   840 
   743 AnnotationType.prototype.getAnnotations = function() {
   841   AnnotationType.prototype.getAnnotations = function () {
   744     return this.getRelated("annotation");
   842     return this.getRelated("annotation");
   745 };
   843   };
   746 
   844 
   747 /* Annotation
   845   /* Annotation
   748  * */
   846    * */
   749 
   847 
   750 var Annotation = Model.Annotation = function(_id, _source) {
   848   var Annotation = (Model.Annotation = function (_id, _source) {
   751     BaseElement.call(this, _id, _source);
   849     BaseElement.call(this, _id, _source);
   752     this.elementType = 'annotation';
   850     this.elementType = "annotation";
   753     this.begin = new Time();
   851     this.begin = new Time();
   754     this.end = new Time();
   852     this.end = new Time();
   755     this.tag = new Reference(_source, []);
   853     this.tag = new Reference(_source, []);
   756     this.playing = false;
   854     this.playing = false;
   757     var _this = this;
   855     var _this = this;
   758     this.on("click", function() {
   856     this.on("click", function () {
   759         _this.getMedia().setCurrentTime(_this.begin);
   857       _this.getMedia().setCurrentTime(_this.begin);
   760     });
   858     });
   761 };
   859   });
   762 
   860 
   763 extendPrototype(Annotation, BaseElement);
   861   extendPrototype(Annotation, BaseElement);
   764 
   862 
   765 /* Set begin and end in one go, to avoid undesired side-effects in
   863   /* Set begin and end in one go, to avoid undesired side-effects in
   766  * setBegin/setEnd interaction */
   864    * setBegin/setEnd interaction */
   767 Annotation.prototype.setBeginEnd = function(_beginMs, _endMs) {
   865   Annotation.prototype.setBeginEnd = function (_beginMs, _endMs) {
   768     _beginMs = Math.max(0,_beginMs);
   866     _beginMs = Math.max(0, _beginMs);
   769     _endMs = Math.max(0,_endMs);
   867     _endMs = Math.max(0, _endMs);
   770     if (_endMs < _beginMs)
   868     if (_endMs < _beginMs) _endMs = _beginMs;
   771         _endMs = _beginMs;
       
   772     this.begin.setMilliseconds(_beginMs);
   869     this.begin.setMilliseconds(_beginMs);
   773     this.end.setMilliseconds(_endMs);
   870     this.end.setMilliseconds(_endMs);
   774     this.trigger("change-begin");
   871     this.trigger("change-begin");
   775     this.trigger("change-end");
   872     this.trigger("change-end");
   776 };
   873   };
   777 
   874 
   778 Annotation.prototype.setBegin = function(_beginMs) {
   875   Annotation.prototype.setBegin = function (_beginMs) {
   779     this.begin.setMilliseconds(Math.max(0,_beginMs));
   876     this.begin.setMilliseconds(Math.max(0, _beginMs));
   780     this.trigger("change-begin");
   877     this.trigger("change-begin");
   781     if (this.end < this.begin) {
   878     if (this.end < this.begin) {
   782         this.setEnd(this.begin);
   879       this.setEnd(this.begin);
   783     }
   880     }
   784 };
   881   };
   785 
   882 
   786 Annotation.prototype.setEnd = function(_endMs) {
   883   Annotation.prototype.setEnd = function (_endMs) {
   787     this.end.setMilliseconds(Math.min(_endMs, this.getMedia().duration.milliseconds));
   884     this.end.setMilliseconds(
       
   885       Math.min(_endMs, this.getMedia().duration.milliseconds)
       
   886     );
   788     this.trigger("change-end");
   887     this.trigger("change-end");
   789     if (this.end < this.begin) {
   888     if (this.end < this.begin) {
   790         this.setBegin(this.end);
   889       this.setBegin(this.end);
   791     }
   890     }
   792 };
   891   };
   793 
   892 
   794 Annotation.prototype.setDuration = function(_durMs) {
   893   Annotation.prototype.setDuration = function (_durMs) {
   795     this.setEnd(_durMs + this.begin.milliseconds);
   894     this.setEnd(_durMs + this.begin.milliseconds);
   796 };
   895   };
   797 
   896 
   798 Annotation.prototype.setMedia = function(_idRef) {
   897   Annotation.prototype.setMedia = function (_idRef) {
   799     this.setReference("media", _idRef);
   898     this.setReference("media", _idRef);
   800 };
   899   };
   801 
   900 
   802 Annotation.prototype.getMedia = function() {
   901   Annotation.prototype.getMedia = function () {
   803     return this.getReference("media");
   902     return this.getReference("media");
   804 };
   903   };
   805 
   904 
   806 Annotation.prototype.setAnnotationType = function(_idRef) {
   905   Annotation.prototype.setAnnotationType = function (_idRef) {
   807     this.setReference("annotationType", _idRef);
   906     this.setReference("annotationType", _idRef);
   808 };
   907   };
   809 
   908 
   810 Annotation.prototype.getAnnotationType = function() {
   909   Annotation.prototype.getAnnotationType = function () {
   811     return this.getReference("annotationType");
   910     return this.getReference("annotationType");
   812 };
   911   };
   813 
   912 
   814 Annotation.prototype.setTags = function(_idRefs) {
   913   Annotation.prototype.setTags = function (_idRefs) {
   815     this.setReference("tag", _idRefs);
   914     this.setReference("tag", _idRefs);
   816 };
   915   };
   817 
   916 
   818 Annotation.prototype.getTags = function() {
   917   Annotation.prototype.getTags = function () {
   819     return this.getReference("tag");
   918     return this.getReference("tag");
   820 };
   919   };
   821 
   920 
   822 Annotation.prototype.getTagTexts = function() {
   921   Annotation.prototype.getTagTexts = function () {
   823     return this.getTags().getTitles();
   922     return this.getTags().getTitles();
   824 };
   923   };
   825 
   924 
   826 Annotation.prototype.getDuration = function() {
   925   Annotation.prototype.getDuration = function () {
   827     return new Time(this.end.milliseconds - this.begin.milliseconds);
   926     return new Time(this.end.milliseconds - this.begin.milliseconds);
   828 };
   927   };
   829 
   928 
   830 /* */
   929   /* */
   831 
   930 
   832 var MashedAnnotation = Model.MashedAnnotation = function(_mashup, _annotation) {
   931   var MashedAnnotation = (Model.MashedAnnotation = function (
   833     BaseElement.call(this, _mashup.id + "_" + _annotation.id, _annotation.source);
   932     _mashup,
   834     this.elementType = 'mashedAnnotation';
   933     _annotation
       
   934   ) {
       
   935     BaseElement.call(
       
   936       this,
       
   937       _mashup.id + "_" + _annotation.id,
       
   938       _annotation.source
       
   939     );
       
   940     this.elementType = "mashedAnnotation";
   835     this.annotation = _annotation;
   941     this.annotation = _annotation;
   836     this.begin = new Time();
   942     this.begin = new Time();
   837     this.end = new Time();
   943     this.end = new Time();
   838     this.duration = new Time();
   944     this.duration = new Time();
   839     this.title = this.annotation.title;
   945     this.title = this.annotation.title;
   840     this.description = this.annotation.description;
   946     this.description = this.annotation.description;
   841     this.color = this.annotation.color;
   947     this.color = this.annotation.color;
   842     var _this = this;
   948     var _this = this;
   843     this.on("click", function() {
   949     this.on("click", function () {
   844         _mashup.setCurrentTime(_this.begin);
   950       _mashup.setCurrentTime(_this.begin);
   845     });
   951     });
   846     this.on("enter", function() {
   952     this.on("enter", function () {
   847         _this.annotation.trigger("enter");
   953       _this.annotation.trigger("enter");
   848     });
   954     });
   849     this.on("leave", function() {
   955     this.on("leave", function () {
   850         _this.annotation.trigger("leave");
   956       _this.annotation.trigger("leave");
   851     });
   957     });
   852 };
   958   });
   853 
   959 
   854 extendPrototype(MashedAnnotation, BaseElement);
   960   extendPrototype(MashedAnnotation, BaseElement);
   855 
   961 
   856 MashedAnnotation.prototype.getMedia = function() {
   962   MashedAnnotation.prototype.getMedia = function () {
   857     return this.annotation.getReference("media");
   963     return this.annotation.getReference("media");
   858 };
   964   };
   859 
   965 
   860 MashedAnnotation.prototype.getAnnotationType = function() {
   966   MashedAnnotation.prototype.getAnnotationType = function () {
   861     return this.annotation.getReference("annotationType");
   967     return this.annotation.getReference("annotationType");
   862 };
   968   };
   863 
   969 
   864 MashedAnnotation.prototype.getTags = function() {
   970   MashedAnnotation.prototype.getTags = function () {
   865     return this.annotation.getReference("tag");
   971     return this.annotation.getReference("tag");
   866 };
   972   };
   867 
   973 
   868 MashedAnnotation.prototype.getTagTexts = function() {
   974   MashedAnnotation.prototype.getTagTexts = function () {
   869     return this.annotation.getTags().getTitles();
   975     return this.annotation.getTags().getTitles();
   870 };
   976   };
   871 
   977 
   872 MashedAnnotation.prototype.getDuration = function() {
   978   MashedAnnotation.prototype.getDuration = function () {
   873     return this.annotation.getDuration();
   979     return this.annotation.getDuration();
   874 };
   980   };
   875 
   981 
   876 MashedAnnotation.prototype.setBegin = function(_begin) {
   982   MashedAnnotation.prototype.setBegin = function (_begin) {
   877     this.begin.setMilliseconds(_begin);
   983     this.begin.setMilliseconds(_begin);
   878     this.duration.setMilliseconds(this.annotation.getDuration());
   984     this.duration.setMilliseconds(this.annotation.getDuration());
   879     this.end.setMilliseconds(_begin + this.duration);
   985     this.end.setMilliseconds(_begin + this.duration);
   880 };
   986   };
   881 
   987 
   882 /* */
   988   /* */
   883 
   989 
   884 var Mashup = Model.Mashup = function(_id, _source) {
   990   var Mashup = (Model.Mashup = function (_id, _source) {
   885     Playable.call(this, _id, _source);
   991     Playable.call(this, _id, _source);
   886     this.elementType = 'mashup';
   992     this.elementType = "mashup";
   887     this.duration = new Time();
   993     this.duration = new Time();
   888     this.segments = new List(_source.directory);
   994     this.segments = new List(_source.directory);
   889     this.loaded = false;
   995     this.loaded = false;
   890     var _this = this;
   996     var _this = this;
   891     this._updateTimes = function() {
   997     this._updateTimes = function () {
   892         _this.updateTimes();
   998       _this.updateTimes();
   893         _this.trigger("change");
   999       _this.trigger("change");
   894     };
  1000     };
   895     this.on("add", this._updateTimes);
  1001     this.on("add", this._updateTimes);
   896     this.on("remove", this._updateTimes);
  1002     this.on("remove", this._updateTimes);
   897 };
  1003   });
   898 
  1004 
   899 extendPrototype(Mashup, Playable);
  1005   extendPrototype(Mashup, Playable);
   900 
  1006 
   901 Mashup.prototype.updateTimes = function() {
  1007   Mashup.prototype.updateTimes = function () {
   902     var _time = 0;
  1008     var _time = 0;
   903     this.segments.forEach(function(_segment) {
  1009     this.segments.forEach(function (_segment) {
   904         _segment.setBegin(_time);
  1010       _segment.setBegin(_time);
   905         _time = _segment.end;
  1011       _time = _segment.end;
   906     });
  1012     });
   907     this.duration.setMilliseconds(_time);
  1013     this.duration.setMilliseconds(_time);
   908 };
  1014   };
   909 
  1015 
   910 Mashup.prototype.addAnnotation = function(_annotation, _defer) {
  1016   Mashup.prototype.addAnnotation = function (_annotation, _defer) {
   911     var _mashedAnnotation = new MashedAnnotation(this, _annotation),
  1017     var _mashedAnnotation = new MashedAnnotation(this, _annotation),
   912         _defer = _defer || false;
  1018       _defer = _defer || false;
   913     this.segments.push(_mashedAnnotation);
  1019     this.segments.push(_mashedAnnotation);
   914     _annotation.on("change-begin", this._updateTimes);
  1020     _annotation.on("change-begin", this._updateTimes);
   915     _annotation.on("change-end", this._updateTimes);
  1021     _annotation.on("change-end", this._updateTimes);
   916     if (!_defer) {
  1022     if (!_defer) {
   917         this.trigger("add");
  1023       this.trigger("add");
   918     }
  1024     }
   919 };
  1025   };
   920 
  1026 
   921 Mashup.prototype.addAnnotationById = function(_elId, _defer) {
  1027   Mashup.prototype.addAnnotationById = function (_elId, _defer) {
   922     var _annotation = this.source.getElement(_elId),
  1028     var _annotation = this.source.getElement(_elId),
   923         _defer = _defer || false;
  1029       _defer = _defer || false;
   924     if (typeof _annotation !== "undefined") {
  1030     if (typeof _annotation !== "undefined") {
   925         this.addAnnotation(_annotation, _defer);
  1031       this.addAnnotation(_annotation, _defer);
   926     }
  1032     }
   927 };
  1033   };
   928 
  1034 
   929 Mashup.prototype.addAnnotations = function(_segments) {
  1035   Mashup.prototype.addAnnotations = function (_segments) {
   930     var _this = this;
  1036     var _this = this;
   931     ns._(_segments).forEach(function(_segment) {
  1037     _(_segments).forEach(function (_segment) {
   932         _this.addAnnotation(_segment, true);
  1038       _this.addAnnotation(_segment, true);
   933     });
  1039     });
   934     this.trigger("add");
  1040     this.trigger("add");
   935 };
  1041   };
   936 
  1042 
   937 Mashup.prototype.addAnnotationsById = function(_segments) {
  1043   Mashup.prototype.addAnnotationsById = function (_segments) {
   938     var _this = this;
  1044     var _this = this;
   939     ns._(_segments).forEach(function(_segment) {
  1045     _(_segments).forEach(function (_segment) {
   940         _this.addAnnotationById(_segment, true);
  1046       _this.addAnnotationById(_segment, true);
   941     });
  1047     });
   942     this.trigger("add");
  1048     this.trigger("add");
   943 };
  1049   };
   944 
  1050 
   945 Mashup.prototype.removeAnnotation = function(_annotation, _defer) {
  1051   Mashup.prototype.removeAnnotation = function (_annotation, _defer) {
   946     var _defer = _defer || false;
  1052     var _defer = _defer || false;
   947     _annotation.off("change-begin", this._updateTimes);
  1053     _annotation.off("change-begin", this._updateTimes);
   948     _annotation.off("change-end", this._updateTimes);
  1054     _annotation.off("change-end", this._updateTimes);
   949     this.segments.removeId(this.id + "_" + _annotation.id);
  1055     this.segments.removeId(this.id + "_" + _annotation.id);
   950     if (!_defer) {
  1056     if (!_defer) {
   951         this.trigger("remove");
  1057       this.trigger("remove");
   952     }
  1058     }
   953 };
  1059   };
   954 
  1060 
   955 Mashup.prototype.removeAnnotationById = function(_annId, _defer) {
  1061   Mashup.prototype.removeAnnotationById = function (_annId, _defer) {
   956     var _defer = _defer || false;
  1062     var _defer = _defer || false;
   957     var _annotation = this.source.getElement(_annId);
  1063     var _annotation = this.source.getElement(_annId);
   958 
  1064 
   959     if (_annotation) {
  1065     if (_annotation) {
   960         this.removeAnnotation(_annotation, _defer);
  1066       this.removeAnnotation(_annotation, _defer);
   961     }
  1067     }
   962     if (!_defer) {
  1068     if (!_defer) {
   963         this.trigger("remove");
  1069       this.trigger("remove");
   964     }
  1070     }
   965 };
  1071   };
   966 
  1072 
   967 Mashup.prototype.setAnnotations = function(_segments) {
  1073   Mashup.prototype.setAnnotations = function (_segments) {
   968     while (this.segments.length) {
  1074     while (this.segments.length) {
   969         this.removeAnnotation(this.segments[0].annotation, true);
  1075       this.removeAnnotation(this.segments[0].annotation, true);
   970     }
  1076     }
   971     this.addAnnotations(_segments);
  1077     this.addAnnotations(_segments);
   972 };
  1078   };
   973 
  1079 
   974 Mashup.prototype.setAnnotationsById = function(_segments) {
  1080   Mashup.prototype.setAnnotationsById = function (_segments) {
   975     while (this.segments.length) {
  1081     while (this.segments.length) {
   976         this.removeAnnotation(this.segments[0].annotation, true);
  1082       this.removeAnnotation(this.segments[0].annotation, true);
   977     }
  1083     }
   978     this.addAnnotationsById(_segments);
  1084     this.addAnnotationsById(_segments);
   979 };
  1085   };
   980 
  1086 
   981 Mashup.prototype.hasAnnotation = function(_annotation) {
  1087   Mashup.prototype.hasAnnotation = function (_annotation) {
   982     return !!ns._(this.segments).find(function(_s) {
  1088     return !!_(this.segments).find(function (_s) {
   983         return _s.annotation === _annotation;
  1089       return _s.annotation === _annotation;
   984     });
  1090     });
   985 };
  1091   };
   986 
  1092 
   987 Mashup.prototype.getAnnotation = function(_annotation) {
  1093   Mashup.prototype.getAnnotation = function (_annotation) {
   988     return ns._(this.segments).find(function(_s) {
  1094     return _(this.segments).find(function (_s) {
   989         return _s.annotation === _annotation;
  1095       return _s.annotation === _annotation;
   990     });
  1096     });
   991 };
  1097   };
   992 
  1098 
   993 Mashup.prototype.getAnnotationById = function(_id) {
  1099   Mashup.prototype.getAnnotationById = function (_id) {
   994     return ns._(this.segments).find(function(_s) {
  1100     return _(this.segments).find(function (_s) {
   995         return _s.annotation.id === _id;
  1101       return _s.annotation.id === _id;
   996     });
  1102     });
   997 };
  1103   };
   998 
  1104 
   999 Mashup.prototype.getAnnotations = function() {
  1105   Mashup.prototype.getAnnotations = function () {
  1000     return this.segments;
  1106     return this.segments;
  1001 };
  1107   };
  1002 
  1108 
  1003 Mashup.prototype.getOriginalAnnotations = function() {
  1109   Mashup.prototype.getOriginalAnnotations = function () {
  1004     var annotations = new List(this.source.directory);
  1110     var annotations = new List(this.source.directory);
  1005     this.segments.forEach(function(_s) {
  1111     this.segments.forEach(function (_s) {
  1006         annotations.push(_s.annotation);
  1112       annotations.push(_s.annotation);
  1007     });
  1113     });
  1008     return annotations;
  1114     return annotations;
  1009 };
  1115   };
  1010 
  1116 
  1011 Mashup.prototype.getMedias = function() {
  1117   Mashup.prototype.getMedias = function () {
  1012     var medias = new List(this.source.directory);
  1118     var medias = new List(this.source.directory);
  1013     this.segments.forEach(function(_annotation) {
  1119     this.segments.forEach(function (_annotation) {
  1014         medias.push(_annotation.getMedia());
  1120       medias.push(_annotation.getMedia());
  1015     });
  1121     });
  1016     return medias;
  1122     return medias;
  1017 };
  1123   };
  1018 
  1124 
  1019 Mashup.prototype.getAnnotationsByTypeTitle = function(_title) {
  1125   Mashup.prototype.getAnnotationsByTypeTitle = function (_title) {
  1020     var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id");
  1126     var _annTypes = this.source
       
  1127       .getAnnotationTypes()
       
  1128       .searchByTitle(_title)
       
  1129       .pluck("id");
  1021     if (_annTypes.length) {
  1130     if (_annTypes.length) {
  1022         return this.getAnnotations().filter(function(_annotation) {
  1131       return this.getAnnotations().filter(function (_annotation) {
  1023             return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
  1132         return _(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1;
  1024         });
  1133       });
  1025     } else {
  1134     } else {
  1026         return new List(this.source.directory);
  1135       return new List(this.source.directory);
  1027     }
  1136     }
  1028 };
  1137   };
  1029 
  1138 
  1030 Mashup.prototype.getAnnotationAtTime = function(_time) {
  1139   Mashup.prototype.getAnnotationAtTime = function (_time) {
  1031     var _list = this.segments.filter(function(_annotation) {
  1140     var _list = this.segments.filter(function (_annotation) {
  1032         return _annotation.begin <= _time && _annotation.end > _time;
  1141       return _annotation.begin <= _time && _annotation.end > _time;
  1033     });
  1142     });
  1034     if (_list.length) {
  1143     if (_list.length) {
  1035         return _list[0];
  1144       return _list[0];
  1036     } else {
  1145     } else {
  1037         return undefined;
  1146       return undefined;
  1038     }
  1147     }
  1039 };
  1148   };
  1040 
  1149 
  1041 Mashup.prototype.getMediaAtTime = function(_time) {
  1150   Mashup.prototype.getMediaAtTime = function (_time) {
  1042     var _annotation = this.getAnnotationAtTime(_time);
  1151     var _annotation = this.getAnnotationAtTime(_time);
  1043     if (typeof _annotation !== "undefined") {
  1152     if (typeof _annotation !== "undefined") {
  1044         return _annotation.getMedia();
  1153       return _annotation.getMedia();
  1045     } else {
  1154     } else {
  1046         return undefined;
  1155       return undefined;
  1047     }
  1156     }
  1048 };
  1157   };
  1049 
  1158 
  1050 /* */
  1159   /* */
  1051 
  1160 
  1052 var Source = Model.Source = function(_config) {
  1161   var Source = (Model.Source = function (_config) {
  1053     BaseElement.call(this, false, this);
  1162     BaseElement.call(this, false, this);
  1054     this.status = _SOURCE_STATUS_EMPTY;
  1163     this.status = _SOURCE_STATUS_EMPTY;
  1055     this.elementType = "source";
  1164     this.elementType = "source";
  1056     if (typeof _config !== "undefined") {
  1165     if (typeof _config !== "undefined") {
  1057         var _this = this;
  1166       var _this = this;
  1058         ns._(_config).forEach(function(_v, _k) {
  1167       _(_config).forEach(function (_v, _k) {
  1059             _this[_k] = _v;
  1168         _this[_k] = _v;
  1060         });
  1169       });
  1061         this.callbackQueue = [];
  1170       this.callbackQueue = [];
  1062         this.contents = {};
  1171       this.contents = {};
  1063         this.get();
  1172       this.get();
  1064     }
  1173     }
  1065 };
  1174   });
  1066 
  1175 
  1067 extendPrototype(Source, BaseElement);
  1176   extendPrototype(Source, BaseElement);
  1068 
  1177 
  1069 Source.prototype.addList = function(_listId, _contents) {
  1178   Source.prototype.addList = function (_listId, _contents) {
  1070     if (typeof this.contents[_listId] === "undefined") {
  1179     if (typeof this.contents[_listId] === "undefined") {
       
  1180       this.contents[_listId] = new List(this.directory);
       
  1181     }
       
  1182     this.contents[_listId].addElements(_contents);
       
  1183   };
       
  1184 
       
  1185   Source.prototype.getList = function (_listId, _global) {
       
  1186     _global = typeof _global !== "undefined" && _global;
       
  1187     if (_global) {
       
  1188       return this.directory.getGlobalList().filter(function (_e) {
       
  1189         return _e.elementType === _listId;
       
  1190       });
       
  1191     } else {
       
  1192       if (typeof this.contents[_listId] === "undefined") {
  1071         this.contents[_listId] = new List(this.directory);
  1193         this.contents[_listId] = new List(this.directory);
  1072     }
  1194       }
  1073     this.contents[_listId].addElements(_contents);
  1195       return this.contents[_listId];
  1074 };
  1196     }
  1075 
  1197   };
  1076 Source.prototype.getList = function(_listId, _global) {
  1198 
  1077     _global = (typeof _global !== "undefined" && _global);
  1199   Source.prototype.forEach = function (_callback) {
  1078     if (_global) {
       
  1079         return this.directory.getGlobalList().filter(function(_e) {
       
  1080             return (_e.elementType === _listId);
       
  1081         });
       
  1082     } else {
       
  1083         if (typeof this.contents[_listId] === "undefined") {
       
  1084             this.contents[_listId] = new List(this.directory);
       
  1085         }
       
  1086         return this.contents[_listId];
       
  1087     }
       
  1088 };
       
  1089 
       
  1090 Source.prototype.forEach = function(_callback) {
       
  1091     var _this = this;
  1200     var _this = this;
  1092     ns._(this.contents).forEach(function(_value, _key) {
  1201     _(this.contents).forEach(function (_value, _key) {
  1093         _callback.call(_this, _value, _key);
  1202       _callback.call(_this, _value, _key);
  1094     });
  1203     });
  1095 };
  1204   };
  1096 
  1205 
  1097 Source.prototype.getElement = function(_elId) {
  1206   Source.prototype.getElement = function (_elId) {
  1098     return this.directory.getElement(_elId);
  1207     return this.directory.getElement(_elId);
  1099 };
  1208   };
  1100 
  1209 
  1101 Source.prototype.get = function() {
  1210   Source.prototype.get = function () {
  1102     this.status = _SOURCE_STATUS_WAITING;
  1211     this.status = _SOURCE_STATUS_WAITING;
  1103     this.handleCallbacks();
  1212     this.handleCallbacks();
  1104 };
  1213   };
  1105 
  1214 
  1106 /* We defer the callbacks calls so they execute after the queue is cleared */
  1215   /* We defer the callbacks calls so they execute after the queue is cleared */
  1107 Source.prototype.deferCallback = function(_callback) {
  1216   Source.prototype.deferCallback = function (_callback) {
  1108     var _this = this;
  1217     var _this = this;
  1109     ns._.defer(function() {
  1218     _.defer(function () {
  1110         _callback.call(_this);
  1219       _callback.call(_this);
  1111     });
  1220     });
  1112 };
  1221   };
  1113 
  1222 
  1114 Source.prototype.handleCallbacks = function() {
  1223   Source.prototype.handleCallbacks = function () {
  1115     this.status = _SOURCE_STATUS_READY;
  1224     this.status = _SOURCE_STATUS_READY;
  1116     while (this.callbackQueue.length) {
  1225     while (this.callbackQueue.length) {
  1117         this.deferCallback(this.callbackQueue.splice(0,1)[0]);
  1226       this.deferCallback(this.callbackQueue.splice(0, 1)[0]);
  1118     }
  1227     }
  1119 };
  1228   };
  1120 Source.prototype.onLoad = function(_callback) {
  1229   Source.prototype.onLoad = function (_callback) {
  1121     if (this.status === _SOURCE_STATUS_READY) {
  1230     if (this.status === _SOURCE_STATUS_READY) {
  1122         this.deferCallback(_callback);
  1231       this.deferCallback(_callback);
  1123     } else {
  1232     } else {
  1124         this.callbackQueue.push(_callback);
  1233       this.callbackQueue.push(_callback);
  1125     }
  1234     }
  1126 };
  1235   };
  1127 
  1236 
  1128 Source.prototype.serialize = function() {
  1237   Source.prototype.serialize = function () {
  1129     return this.serializer.serialize(this);
  1238     return this.serializer.serialize(this);
  1130 };
  1239   };
  1131 
  1240 
  1132 Source.prototype.deSerialize = function(_data) {
  1241   Source.prototype.deSerialize = function (_data) {
  1133     this.serializer.deSerialize(_data, this);
  1242     this.serializer.deSerialize(_data, this);
  1134 };
  1243   };
  1135 
  1244 
  1136 Source.prototype.getAnnotations = function(_global) {
  1245   Source.prototype.getAnnotations = function (_global) {
  1137     _global = (typeof _global !== "undefined" && _global);
  1246     _global = typeof _global !== "undefined" && _global;
  1138     return this.getList("annotation", _global);
  1247     return this.getList("annotation", _global);
  1139 };
  1248   };
  1140 
  1249 
  1141 Source.prototype.getMedias = function(_global) {
  1250   Source.prototype.getMedias = function (_global) {
  1142     _global = (typeof _global !== "undefined" && _global);
  1251     _global = typeof _global !== "undefined" && _global;
  1143     return this.getList("media", _global);
  1252     return this.getList("media", _global);
  1144 };
  1253   };
  1145 
  1254 
  1146 Source.prototype.getTags = function(_global) {
  1255   Source.prototype.getTags = function (_global) {
  1147     _global = (typeof _global !== "undefined" && _global);
  1256     _global = typeof _global !== "undefined" && _global;
  1148     return this.getList("tag", _global);
  1257     return this.getList("tag", _global);
  1149 };
  1258   };
  1150 
  1259 
  1151 Source.prototype.getMashups = function(_global) {
  1260   Source.prototype.getMashups = function (_global) {
  1152     _global = (typeof _global !== "undefined" && _global);
  1261     _global = typeof _global !== "undefined" && _global;
  1153     return this.getList("mashup", _global);
  1262     return this.getList("mashup", _global);
  1154 };
  1263   };
  1155 
  1264 
  1156 Source.prototype.getAnnotationTypes = function(_global) {
  1265   Source.prototype.getAnnotationTypes = function (_global) {
  1157     _global = (typeof _global !== "undefined" && _global);
  1266     _global = typeof _global !== "undefined" && _global;
  1158     return this.getList("annotationType", _global);
  1267     return this.getList("annotationType", _global);
  1159 };
  1268   };
  1160 
  1269 
  1161 Source.prototype.getAnnotationsByTypeTitle = function(_title, _global) {
  1270   Source.prototype.getAnnotationsByTypeTitle = function (_title, _global) {
  1162     _global = (typeof _global !== "undefined" && _global);
  1271     _global = typeof _global !== "undefined" && _global;
  1163     var _res = new List(this.directory),
  1272     var _res = new List(this.directory),
  1164         _annTypes = this.getAnnotationTypes(_global).searchByTitle(_title);
  1273       _annTypes = this.getAnnotationTypes(_global).searchByTitle(_title);
  1165     _annTypes.forEach(function(_annType) {
  1274     _annTypes.forEach(function (_annType) {
  1166         _res.addElements(_annType.getAnnotations(_global));
  1275       _res.addElements(_annType.getAnnotations(_global));
  1167     });
  1276     });
  1168     return _res;
  1277     return _res;
  1169 };
  1278   };
  1170 
  1279 
  1171 Source.prototype.getDuration = function() {
  1280   Source.prototype.getDuration = function () {
  1172     var _m = this.currentMedia;
  1281     var _m = this.currentMedia;
  1173     if (typeof _m !== "undefined") {
  1282     if (typeof _m !== "undefined") {
  1174         return this.currentMedia.duration;
  1283       return this.currentMedia.duration;
  1175     }
  1284     }
  1176 };
  1285   };
  1177 
  1286 
  1178 Source.prototype.getCurrentMedia = function(_opts) {
  1287   Source.prototype.getCurrentMedia = function (_opts) {
  1179     if (typeof this.currentMedia === "undefined") {
  1288     if (typeof this.currentMedia === "undefined") {
  1180         if (_opts.is_mashup) {
  1289       if (_opts.is_mashup) {
  1181             var _mashups = this.getMashups();
  1290         var _mashups = this.getMashups();
  1182             if (_mashups.length) {
  1291         if (_mashups.length) {
  1183                 this.currentMedia = _mashups[0];
  1292           this.currentMedia = _mashups[0];
  1184             }
       
  1185         } else {
       
  1186             var _medias = this.getMedias();
       
  1187             if (_medias.length) {
       
  1188                 this.currentMedia = _medias[0];
       
  1189             }
       
  1190         }
  1293         }
       
  1294       } else {
       
  1295         var _medias = this.getMedias();
       
  1296         if (_medias.length) {
       
  1297           this.currentMedia = _medias[0];
       
  1298         }
       
  1299       }
  1191     }
  1300     }
  1192     return this.currentMedia;
  1301     return this.currentMedia;
  1193 };
  1302   };
  1194 
  1303 
  1195 Source.prototype.merge = function(_source) {
  1304   Source.prototype.merge = function (_source) {
  1196     var _this = this;
  1305     var _this = this;
  1197     _source.forEach(function(_value, _key) {
  1306     _source.forEach(function (_value, _key) {
  1198         _this.getList(_key).addElements(_value);
  1307       _this.getList(_key).addElements(_value);
  1199     });
  1308     });
  1200 };
  1309   };
  1201 
  1310 
  1202 /* */
  1311   /* */
  1203 
  1312 
  1204 var RemoteSource = Model.RemoteSource = function(_config) {
  1313   var RemoteSource = (Model.RemoteSource = function (_config) {
  1205     Source.call(this, _config);
  1314     Source.call(this, _config);
  1206 };
  1315   });
  1207 
  1316 
  1208 extendPrototype(RemoteSource, Source);
  1317   extendPrototype(RemoteSource, Source);
  1209 
  1318 
  1210 RemoteSource.prototype.get = function() {
  1319   RemoteSource.prototype.get = function () {
  1211     this.status = _SOURCE_STATUS_WAITING;
  1320     this.status = _SOURCE_STATUS_WAITING;
  1212     var _this = this,
  1321     var _this = this,
  1213         urlparams = this.url_params || {},
  1322       urlparams = this.url_params || {},
  1214         dataType = (isLocalURL(this.url) ? "json" : "jsonp");
  1323       dataType = this.dataType || "json";
  1215     urlparams.format = dataType;
  1324     urlparams.format = dataType;
  1216     ns.jQuery.ajax({
  1325     jQuery.ajax({
  1217         url: this.url,
  1326       url: this.url,
  1218         dataType: dataType,
  1327       dataType: dataType,
  1219         data: urlparams,
  1328       data: urlparams,
  1220         traditional: true,
  1329       traditional: true,
  1221         success: function(_result) {
  1330       success: function (_result) {
  1222             _this.deSerialize(_result);
  1331         _this.deSerialize(_result);
  1223             _this.handleCallbacks();
  1332         _this.handleCallbacks();
  1224         }
  1333       },
  1225     });
  1334     });
  1226 };
  1335   };
  1227 
  1336 
  1228 /* */
  1337   /* */
  1229 
  1338 
  1230 var Directory = Model.Directory = function() {
  1339   var Directory = (Model.Directory = function () {
  1231     this.remoteSources = {};
  1340     this.remoteSources = {};
  1232     this.elements = {};
  1341     this.elements = {};
       
  1342   });
       
  1343 
       
  1344   Directory.prototype.remoteSource = function (_properties) {
       
  1345     if (
       
  1346       typeof _properties !== "object" ||
       
  1347       typeof _properties.url === "undefined"
       
  1348     ) {
       
  1349       throw "Error : Directory.remoteSource(configuration): configuration.url is undefined";
       
  1350     }
       
  1351     var _config = _({ directory: this }).extend(_properties);
       
  1352     _config.url_params = _config.url_params || {};
       
  1353     var _hash = _config.url + "?" + jQuery.param(_config.url_params);
       
  1354     if (typeof this.remoteSources[_hash] === "undefined") {
       
  1355       this.remoteSources[_hash] = new RemoteSource(_config);
       
  1356     }
       
  1357     return this.remoteSources[_hash];
       
  1358   };
       
  1359 
       
  1360   Directory.prototype.newLocalSource = function (_properties) {
       
  1361     var _config = _({ directory: this }).extend(_properties),
       
  1362       _res = new Source(_config);
       
  1363     return _res;
       
  1364   };
       
  1365 
       
  1366   Directory.prototype.getElement = function (_id) {
       
  1367     return this.elements[_id];
       
  1368   };
       
  1369 
       
  1370   Directory.prototype.addElement = function (_element) {
       
  1371     this.elements[_element.id] = _element;
       
  1372   };
       
  1373 
       
  1374   Directory.prototype.getGlobalList = function () {
       
  1375     var _res = new List(this);
       
  1376     _res.addIds(_(this.elements).keys());
       
  1377     return _res;
       
  1378   };
       
  1379   return Model;
  1233 };
  1380 };
  1234 
  1381 
  1235 Directory.prototype.remoteSource = function(_properties) {
  1382 export default Model;
  1236     if (typeof _properties !== "object" || typeof _properties.url === "undefined") {
       
  1237         throw "Error : Directory.remoteSource(configuration): configuration.url is undefined";
       
  1238     }
       
  1239     var _config = ns._({ directory: this }).extend(_properties);
       
  1240     _config.url_params = _config.url_params || {};
       
  1241     var _hash = _config.url + "?" + ns.jQuery.param(_config.url_params);
       
  1242     if (typeof this.remoteSources[_hash] === "undefined") {
       
  1243         this.remoteSources[_hash] = new RemoteSource(_config);
       
  1244     }
       
  1245     return this.remoteSources[_hash];
       
  1246 };
       
  1247 
       
  1248 Directory.prototype.newLocalSource = function(_properties) {
       
  1249     var _config = ns._({ directory: this }).extend(_properties),
       
  1250         _res = new Source(_config);
       
  1251     return _res;
       
  1252 };
       
  1253 
       
  1254 Directory.prototype.getElement = function(_id) {
       
  1255     return this.elements[_id];
       
  1256 };
       
  1257 
       
  1258 Directory.prototype.addElement = function(_element) {
       
  1259     this.elements[_element.id] = _element;
       
  1260 };
       
  1261 
       
  1262 Directory.prototype.getGlobalList = function() {
       
  1263     var _res = new List(this);
       
  1264     _res.addIds(ns._(this.elements).keys());
       
  1265     return _res;
       
  1266 };
       
  1267 return Model;
       
  1268 
       
  1269 })(IriSP);
       
  1270 
  1383 
  1271 /* END js */
  1384 /* END js */
  1272