1/*! LAB.js (LABjs :: Loading And Blocking JavaScript) 2 v2.0.3 (c) Kyle Simpson 3 MIT License 4*/ 5(function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a.charAt(0)!="/"){a=(c||"")+a}return b.test(a)?a:((a.charAt(0)=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){a.finished_listeners[c]()}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g()}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){d=null;I(b)}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){e.ready_listeners[a]()}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){j()}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j++]()}catch(err){}continue}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.unshift(d,1);[].splice.apply(c,b);d--;continue}
5if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this); 6/* 7 * 8 __ __ _ _ _ _ 9 | \/ | ___| |_ __ _ __| | __ _| |_ __ _ _ __ | | __ _ _ _ ___ _ __ 10 | |\/| |/ _ \ __/ _` |/ _` |/ _` | __/ _` | '_ \| |/ _` | | | |/ _ \ '__| 11 | | | | __/ || (_| | (_| | (_| | || (_| | |_) | | (_| | |_| | __/ | 12 |_| |_|\___|\__\__,_|\__,_|\__,_|\__\__,_| .__/|_|\__,_|\__, |\___|_| 13 |_| |___/ 14 15 * Copyright 2010-2012 Institut de recherche et d'innovation 16 * contributor(s) : Karim Hamidou, Samuel Huron, Raphael Velt, Thibaut Cavalie, Yves-Marie Haussonne, Nicolas Durand, Olivier Aubert 17 * 18 * [email protected] 19 * http://www.iri.centrepompidou.fr 20 * 21 * This software is a computer program whose purpose is to show and add annotations on a video . 22 * This software is governed by the CeCILL-C license under French law and 23 * abiding by the rules of distribution of free software. You can use, 24 * modify and/ or redistribute the software under the terms of the CeCILL-C 25 * license as circulated by CEA, CNRS and INRIA at the following URL 26 * "http://www.cecill.info". 27 * 28 * The fact that you are presently reading this means that you have had 29 * knowledge of the CeCILL-C license and that you accept its terms. 30*/ 31// Metadataplayer - version 0.1/* Initialization of the namespace */ 32 33if (typeof window.IriSP === "undefined") { 34 window.IriSP = { 35 VERSION: "0.3.2" 36 }; 37} 38 39if (typeof IriSP.jQuery === "undefined" && typeof window.jQuery !== "undefined") { 40 var jvp = window.jQuery().jquery.split("."), 41 jv = 100 * parseInt(jvp[0]) + parseInt(jvp[1]); 42 if (jv > 170) { 43 IriSP.jQuery = window.jQuery; 44 } 45} 46 47if (typeof IriSP._ === "undefined" && typeof window._ !== "undefined" && parseFloat(window._.VERSION) >= 1.4) { 48 IriSP._ = window._; 49} 50/* utils.js - various utils that don't belong anywhere else */ 51 52IriSP.jqEscape = function(_text) { 53 return _text.replace(/(:|\.)/g, '\\$1'); 54}; 55 56IriSP.getLib = function(lib) { 57 if (IriSP.libFiles.useCdn && typeof IriSP.libFiles.cdn[lib] == "string") { 58 return IriSP.libFiles.cdn[lib]; 59 } 60 if (typeof IriSP.libFiles.locations[lib] == "string") { 61 return IriSP.libFiles.locations[lib]; 62 } 63 if (typeof IriSP.libFiles.inDefaultDir[lib] == "string") { 64 return IriSP.libFiles.defaultDir + '/' + IriSP.libFiles.inDefaultDir[lib]; 65 } 66}; 67 68IriSP._cssCache = []; 69 70IriSP.loadCss = function(_cssFile) { 71 if (IriSP._(IriSP._cssCache).indexOf(_cssFile) === -1) { 72 IriSP.jQuery("<link>", { 73 rel : "stylesheet", 74 type : "text/css", 75 href : _cssFile 76 }).appendTo('head'); 77 IriSP._cssCache.push(_cssFile); 78 } 79}; 80 81IriSP.textFieldHtml = function(_text, _regexp, _extend) { 82 var list = [], 83 positions = [], 84 text = _text.trim(); 85 86 function addToList(_rx, _startHtml, _endHtml) { 87 while (true) { 88 var result = _rx.exec(text); 89 if (!result) { 90 break; 91 } 92 var end = _rx.lastIndex, 93 start = result.index; 94 list.push({ 95 start: start, 96 end: end, 97 startHtml: (typeof _startHtml === "function" ? _startHtml(result) : _startHtml), 98 endHtml: (typeof _endHtml === "function" ? _endHtml(result) : _endHtml) 99 }); 100 positions.push(start); 101 positions.push(end); 102 } 103 } 104 105 if (_regexp) { 106 addToList(_regexp, '<span class="Ldt-Highlight">', '</span>'); 107 } 108 109 addToList(/(https?:\/\/)?[\w\d\-]+\.\w[\w\d\-]+\S+/gm, function(matches) { 110 return '<a href="' + (matches[1] ? '' : 'http://') + matches[0] + '" target="_blank">'; 111 }, '</a>'); 112 addToList(/@([\d\w]{1,15})/gm, function(matches) { 113 return '<a href="http://twitter.com/' + matches[1] + '" target="_blank">'; 114 }, '</a>'); 115 addToList(/\*[^*]+\*/gm, '<b>', '</b>'); 116 addToList(/[\n\r]+/gm, '', '<br />'); 117 118 IriSP._(_extend).each(function(x) { 119 addToList.apply(null, x); 120 }); 121 122 positions = IriSP._(positions) 123 .chain() 124 .uniq() 125 .sortBy(function(p) { return parseInt(p); }) 126 .value(); 127 128 var res = "", lastIndex = 0; 129 130 for (var i = 0; i < positions.length; i++) { 131 var pos = positions[i]; 132 res += text.substring(lastIndex, pos); 133 for (var j = list.length - 1; j >= 0; j--) { 134 var item = list[j]; 135 if (item.start < pos && item.end >= pos) { 136 res += item.endHtml; 137 } 138 } 139 for (var j = 0; j < list.length; j++) { 140 var item = list[j]; 141 if (item.start <= pos && item.end > pos) { 142 res += item.startHtml; 143 } 144 } 145 lastIndex = pos; 146 } 147 148 res += text.substring(lastIndex); 149 150 return res; 151 152}; 153 154IriSP.log = function() { 155 if (typeof console !== "undefined" && typeof IriSP.logging !== "undefined" && IriSP.logging) { 156 console.log.apply(console, arguments); 157 } 158}; 159 160IriSP.attachDndData = function(jqSel, data) { 161 jqSel.attr("draggable", "true").on("dragstart", function(_event) { 162 var d = (typeof data === "function" ? data.call(this) : data); 163 try { 164 if (d.html === undefined && d.uri && d.text) { 165 d.html = '<a href="' + d.uri + '">' + d.text + '</a>'; 166 } 167 IriSP._(d).each(function(v, k) { 168 if (v && k != 'text' && k != 'html') { 169 _event.originalEvent.dataTransfer.setData("text/x-iri-" + k, v); 170 } 171 }); 172 if (d.uri && d.text) { 173 _event.originalEvent.dataTransfer.setData("text/x-moz-url", d.uri + "\n" + d.text.replace("\n", " ")); 174 _event.originalEvent.dataTransfer.setData("text/plain", d.text + " " + d.uri); 175 } 176 // Define generic text/html and text/plain last (least 177 // specific types, see 178 // https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#Drag_Data) 179 if (d.html !== undefined) { 180 _event.originalEvent.dataTransfer.setData("text/html", d.html); 181 } 182 if (d.text !== undefined && !d.uri) { 183 _event.originalEvent.dataTransfer.setData("text/plain", d.text); 184 } 185 } catch (err) { 186 _event.originalEvent.dataTransfer.setData("Text", JSON.stringify(d)); 187 } 188 }); 189}; 190 191IriSP.FakeClass = function(properties) { 192 var _this = this, 193 noop = (function() {}); 194 IriSP._(properties).each(function(p) { 195 _this[p] = noop; 196 }); 197}; 198 199IriSP.timestamp2ms = function(t) { 200 // Convert timestamp to numeric value 201 // It accepts the following forms: 202 // [h:mm:ss] [mm:ss] [ss] 203 var s = t.split(":").reverse(); 204 while (s.length < 3) { 205 s.push("0"); 206 } 207 return 1000 * (3600 * parseInt(s[2], 10) + 60 * parseInt(s[1], 10) + parseInt(s[0], 10)); 208}; 209 210IriSP.setFullScreen = function(elem, value) { 211 // Set fullscreen on or off 212 if (value) { 213 if (elem.requestFullscreen) { 214 elem.requestFullscreen(); 215 } else if (elem.mozRequestFullScreen) { 216 elem.mozRequestFullScreen(); 217 } else if (elem.webkitRequestFullscreen) { 218 elem.webkitRequestFullscreen(); 219 } else if (elem.msRequestFullscreen) { 220 elem.msRequestFullscreen(); 221 } 222 } else { 223 if (document.exitFullscreen) { 224 document.exitFullscreen(); 225 } else if (document.msExitFullscreen) { 226 document.msExitFullscreen(); 227 } else if (document.mozCancelFullScreen) { 228 document.mozCancelFullScreen(); 229 } else if (document.webkitExitFullscreen) { 230 document.webkitExitFullscreen(); 231 } 232 } 233}; 234 235IriSP.isFullscreen = function() { 236 return (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement); 237}; 238 239IriSP.getFullscreenElement = function () { 240 return (document.fullscreenElement 241 || document.webkitFullscreenElement 242 || document.mozFullScreenElement 243 || document.msFullscreenElement 244 || undefined); 245}; 246 247IriSP.getFullscreenEventname = function () { 248 return ((document.exitFullscreen && "fullscreenchange") 249 || (document.webkitExitFullscreen && "webkitfullscreenchange") 250 || (document.mozExitFullScreen && "mozfullscreenchange") 251 || (document.msExitFullscreen && "msfullscreenchange") 252 || ""); 253}; 254 255/** 256 * Generate a UUID 257 * Source: http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript 258 */ 259IriSP.generateUuid = function () { 260 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 261 var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); 262 return v.toString(16); 263 }); 264}; 265 266/**
267 * Return a non-accentuated version of the given string 268 */ 269IriSP.unaccent = function (s) { 270 return s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); 271}; 272 273/* js is where data is stored in a standard form, whatever the serializer */ 274 275//TODO: Separate Project-specific data from Source 276 277IriSP.Model = (function (ns) { 278 279 function pad(n, x, b) { 280 b = b || 10; 281 var s = (x).toString(b); 282 while (s.length < n) { 283 s = "0" + s; 284 } 285 return s; 286 } 287 288 function rand16(n) { 289 return pad(n, Math.floor(Math.random() * Math.pow(16, n)), 16); 290 } 291 292 var uidbase = rand16(8) + "-" + rand16(4) + "-", uidincrement = Math.floor(Math.random() * 0x10000); 293 294 var charsub = [ 295 '[aáà âä]', 296 '[cç]', 297 '[eéèêë]', 298 '[iÃìîï]', 299 '[oóòôö]', 300 '[uùûü]' 301 ]; 302 303 var removeChars = [ 304 String.fromCharCode(768), String.fromCharCode(769), String.fromCharCode(770), String.fromCharCode(771), String.fromCharCode(807), 305 "ï½", "ï½", "ï¼", "ï¼", "ï¼»", "ï¼½", "ã", "ã", "ã", "ã»", "â¥", "ã", "ã", "ã", "ã", "ã", "ã", "ï¼", "ï¼", "ï¼", "ã", 306 ",", " ", ";", "(", ")", ".", "*", "+", "\\", "?", "|", "{", "}", "[", "]", "^", "#", "/" 307 ]; 308 309 var Model = {}, 310 _SOURCE_STATUS_EMPTY = Model._SOURCE_STATUS_EMPTY = 0, 311 _SOURCE_STATUS_WAITING = Model._SOURCE_STATUS_WAITING = 1, 312 _SOURCE_STATUS_READY = Model._SOURCE_STATUS_READY = 2, 313 extendPrototype = Model.extendPrototype = function(toClass, fromClass) { 314 var fromP = fromClass.prototype, 315 toP = toClass.prototype; 316 for (var k in fromP) { 317 if (fromP.hasOwnProperty(k)) { 318 toP[k] = fromP[k]; 319 } 320 } 321 }, 322 getUID = Model.getUID = function() { 323 return uidbase + pad(4, (++uidincrement % 0x10000), 16) + "-" + rand16(4) + "-" + rand16(6) + rand16(6); 324 }, 325 isLocalURL = Model.isLocalURL = function(url) { 326 var matches = url.match(/^(\w+:)\/\/([^/]+)/); 327 if (matches) { 328 return (matches[1] === document.location.protocol && matches[2] === document.location.host); 329 } 330 return true; 331 }, 332 regexpFromTextOrArray = Model.regexpFromTextOrArray = function(_textOrArray, _testOnly, _iexact) { 333 var _testOnly = _testOnly || false, 334 _iexact = _iexact || false; 335 function escapeText(_text) { 336 return _text.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, '\\$1'); 337 } 338 var _source = 339 typeof _textOrArray === "string" 340 ? escapeText(_textOrArray) 341 : ns._(_textOrArray).map(escapeText).join("|"), 342 _flags = 'im'; 343 if (!_testOnly) { 344 _source = '(' + _source + ')'; 345 _flags += 'g'; 346 } 347 if (_iexact) { 348 _source = '^' + _source + '$'; 349 } 350 return new RegExp(_source, _flags); 351 }, 352 fullTextRegexps = Model.fullTextRegexps = function(_text) { 353 var remsrc = "[\\" + removeChars.join("\\") + "]", 354 remrx = new RegExp(remsrc, "gm"), 355 txt = _text.toLowerCase().replace(remrx, ""), 356 res = [], 357 charsrx = ns._(charsub).map(function(c) { 358 return new RegExp(c); 359 }), 360 src = ""; 361 for (var j = 0; j < txt.length; j++) { 362 if (j) { 363 src += remsrc + "*"; 364 } 365 var l = txt[j]; 366 ns._(charsub).each(function(v, k) { 367 l = l.replace(charsrx[k], v); 368 }); 369 src += l; 370 } 371 return "(" + src + ")"; 372 }, 373 isoToDate = Model.isoToDate = function(_str) { 374 // http://delete.me.uk/2005/03/iso8601.html 375 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})))?)?)?)?"; 376 var d = _str.match(new RegExp(regexp)); 377 378 var offset = 0; 379 var date = new Date(d[1], 0, 1); 380 381 if (d[3]) { date.setMonth(d[3] - 1); } 382 if (d[5]) { date.setDate(d[5]); } 383 if (d[7]) { date.setHours(d[7]); } 384 if (d[8]) { date.setMinutes(d[8]); } 385 if (d[10]) { date.setSeconds(d[10]); } 386 if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } 387 if (d[14]) { 388 offset = (Number(d[16]) * 60) + Number(d[17]); 389 offset *= ((d[15] == '-') ? 1 : -1); 390 } 391 392 offset -= date.getTimezoneOffset(); 393 time = (Number(date) + (offset * 60 * 1000)); 394 var _res = new Date(); 395 _res.setTime(Number(time)); 396 return _res; 397 }, 398 dateToIso = Model.dateToIso = function(_d) { 399 var d = _d ? new Date(_d) : new Date(); 400 return d.getUTCFullYear() + '-' 401 + pad(2, d.getUTCMonth() + 1) + '-' 402 + pad(2, d.getUTCDate()) + 'T' 403 + pad(2, d.getUTCHours()) + ':' 404 + pad(2, d.getUTCMinutes()) + ':' 405 + pad(2, d.getUTCSeconds()) + 'Z' ; 406 }; 407 408 /* 409 * List is a class for a list of elements (e.g. annotations, medias, etc. that each have a distinct ID) 410 */ 411 var List = Model.List = function(_directory) { 412 Array.call(this); 413 this.directory = _directory; 414 this.idIndex = []; 415 this.__events = {}; 416 if (typeof _directory == "undefined") { 417 console.trace(); 418 throw "Error : new List(directory): directory is undefined"; 419 } 420 var _this = this; 421 this.on("clear-search", function() { 422 _this.searching = false;
423 _this.regexp = undefined; 424 _this.forEach(function(_element) { 425 _element.found = undefined; 426 }); 427 _this.trigger("search-cleared"); 428 }); 429 }; 430 431 List.prototype = new Array(); 432 433 List.prototype.hasId = function(_id) { 434 return ns._(this.idIndex).include(_id); 435 }; 436 437 /* On recent browsers, forEach and map are defined and do what we want. 438 * Otherwise, we'll use the Underscore.js functions 439 */ 440 if (typeof Array.prototype.forEach === "undefined") { 441 List.prototype.forEach = function(_callback) { 442 var _this = this; 443 ns._(this).forEach(function(_value, _key) { 444 _callback(_value, _key, _this); 445 }); 446 }; 447 }; 448 449 if (typeof Array.prototype.map === "undefined") { 450 List.prototype.map = function(_callback) { 451 var _this = this; 452 return ns._(this).map(function(_value, _key) { 453 return _callback(_value, _key, _this); 454 }); 455 }; 456 }; 457 458 List.prototype.pluck = function(_key) { 459 return this.map(function(_value) { 460 return _value[_key]; 461 }); 462 }; 463 464 /* We override Array's filter function because it doesn't return an List 465 */ 466 List.prototype.filter = function(_callback) { 467 var _this = this, 468 _res = new List(this.directory); 469 _res.addElements(ns._(this).filter(function(_value, _key) { 470 return _callback(_value, _key, _this); 471 })); 472 return _res; 473 }; 474 475 List.prototype.slice = function(_start, _end) { 476 var _res = new List(this.directory); 477 _res.addElements(Array.prototype.slice.call(this, _start, _end)); 478 return _res; 479 }; 480 481 List.prototype.splice = function(_start, _end) { 482 var _res = new List(this.directory); 483 _res.addElements(Array.prototype.splice.call(this, _start, _end)); 484 this.idIndex.splice(_start, _end); 485 return _res; 486 }; 487 488 /* Array has a sort function, but it's not as interesting as Underscore.js's sortBy 489 * and won't return a new List 490 */ 491 List.prototype.sortBy = function(_callback) { 492 var _this = this, 493 _res = new List(this.directory); 494 _res.addElements(ns._(this).sortBy(function(_value, _key) { 495 return _callback(_value, _key, _this); 496 })); 497 return _res; 498 }; 499 500 /* Title and Description are basic information for (almost) all element types, 501 * here we can search by these criteria 502 */ 503 List.prototype.searchByTitle = function(_text, _iexact) { 504 var _iexact = _iexact || false, 505 _rgxp = regexpFromTextOrArray(_text, true, _iexact); 506 return this.filter(function(_element) { 507 return _rgxp.test(_element.title); 508 }); 509 }; 510 511 List.prototype.searchByDescription = function(_text, _iexact) { 512 var _iexact = _iexact || false, 513 _rgxp = regexpFromTextOrArray(_text, true, _iexact); 514 return this.filter(function(_element) { 515 return _rgxp.test(_element.description); 516 }); 517 }; 518 519 List.prototype.searchByTextFields = function(_text, _iexact) { 520 var _iexact = _iexact || false, 521 _rgxp = regexpFromTextOrArray(_text, true, _iexact); 522 return this.filter(function(_element) { 523 var keywords = (_element.keywords || _element.getTagTexts() || []).join(", "); 524 return _rgxp.test(_element.description) || _rgxp.test(_element.title) || _rgxp.test(keywords); 525 }); 526 }; 527 528 List.prototype.search = function(_text) { 529 if (!_text) { 530 this.trigger("clear-search"); 531 return this; 532 } 533 this.searching = true; 534 this.trigger("search", _text); 535 var rxsource = fullTextRegexps(_text), 536 rgxp = new RegExp(rxsource,"im"); 537 this.regexp = new RegExp(rxsource,"gim"); 538 var res = this.filter(function(_element, _k) { 539 var titlematch = rgxp.test(_element.title), 540 descmatch = rgxp.test(_element.description), 541 _isfound = !!(titlematch || descmatch); 542 _element.found = _isfound; 543 _element.trigger(_isfound ? "found" : "not-found"); 544 return _isfound; 545 }); 546 this.trigger(res.length ? "found" : "not-found", res); 547 return res; 548 }; 549 550 List.prototype.searchByTags = function(_text) { 551 if (!_text) { 552 this.trigger("clear-search"); 553 return this; 554 } 555 this.searching = true; 556 this.trigger("search", _text); 557 var rxsource = fullTextRegexps(_text), 558 rgxp = new RegExp(rxsource,"im"); 559 this.regexp = new RegExp(rxsource,"gim"); 560 var res = this.filter(function(_element, _k) { 561 var _isfound = rgxp.test(_element.getTagTexts()); 562 _element.found = _isfound; 563 _element.trigger(_isfound ? "found" : "not-found"); 564 return _isfound; 565 }); 566 this.trigger(res.length ? "found" : "not-found", res); 567 return res; 568 }; 569 570 List.prototype.getTitles = function() { 571 return this.map(function(_el) { 572 return _el.title; 573 }); 574 }; 575 576 List.prototype.addId = function(_id) { 577 var _el = this.directory.getElement(_id);
578 if (!this.hasId(_id) && typeof _el !== "undefined") { 579 this.idIndex.push(_id); 580 Array.prototype.push.call(this, _el); 581 } 582 }; 583 584 List.prototype.push = function(_el) { 585 if (typeof _el === "undefined") { 586 return; 587 } 588 var _index = (ns._(this.idIndex).indexOf(_el.id)); 589 if (_index === -1) { 590 this.idIndex.push(_el.id); 591 Array.prototype.push.call(this, _el); 592 } else { 593 this[_index] = _el; 594 } 595 }; 596 597 List.prototype.addIds = function(_array) { 598 var _l = _array.length, 599 _this = this; 600 ns._(_array).forEach(function(_id) { 601 _this.addId(_id); 602 }); 603 }; 604 605 List.prototype.addElements = function(_array) { 606 var _this = this; 607 ns._(_array).forEach(function(_el) { 608 _this.push(_el); 609 }); 610 }; 611 612 List.prototype.removeId = function(_id, _deleteFromDirectory) { 613 var _deleteFromDirectory = _deleteFromDirectory || false, 614 _index = (ns._(this.idIndex).indexOf(_id)); 615 if (_index !== -1) { 616 this.splice(_index, 1); 617 } 618 if (_deleteFromDirectory) { 619 delete this.directory.elements[_id]; 620 } 621 }; 622 623 List.prototype.removeElement = function(_el, _deleteFromDirectory) { 624 var _deleteFromDirectory = _deleteFromDirectory || false; 625 this.removeId(_el.id, _deleteFromDirectory); 626 }; 627 628 List.prototype.removeIds = function(_list, _deleteFromDirectory) { 629 var _deleteFromDirectory = _deleteFromDirectory || false, 630 _this = this; 631 ns._(_list).forEach(function(_id) { 632 _this.removeId(_id, _deleteFromDirectory); 633 }); 634 }; 635 636 List.prototype.removeElements = function(_list, _deleteFromDirectory) { 637 var _deleteFromDirectory = _deleteFromDirectory || false, 638 _this = this; 639 ns._(_list).forEach(function(_el) { 640 _this.removeElement(_el, _deleteFromDirectory); 641 }); 642 }; 643 644 List.prototype.on = function(_event, _callback) { 645 if (typeof this.__events[_event] === "undefined") { 646 this.__events[_event] = []; 647 } 648 this.__events[_event].push(_callback); 649 }; 650 651 List.prototype.off = function(_event, _callback) { 652 if (typeof this.__events[_event] !== "undefined") { 653 this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) { 654 return _fn === _callback; 655 }); 656 } 657 }; 658 659 List.prototype.trigger = function(_event, _data) { 660 var _list = this; 661 ns._(this.__events[_event]).each(function(_callback) { 662 _callback.call(_list, _data); 663 }); 664 }; 665 666 /* A simple time management object, that helps converting millisecs to seconds and strings, 667 * without the clumsiness of the original Date object. 668 */ 669 670 var Time = Model.Time = function(_milliseconds) { 671 this.milliseconds = 0; 672 this.setMilliseconds(_milliseconds); 673 }; 674 675 Time.prototype.setMilliseconds = function(_milliseconds) { 676 var _ante = this.milliseconds; 677 switch (typeof _milliseconds) { 678 case "string": 679 this.milliseconds = parseInt(_milliseconds); 680 break; 681 case "number": 682 this.milliseconds = Math.floor(_milliseconds); 683 break; 684 case "object": 685 this.milliseconds = parseInt(_milliseconds.valueOf()); 686 break; 687 default: 688 this.milliseconds = 0; 689 } 690 if (this.milliseconds === NaN) { 691 this.milliseconds = _ante; 692 } 693 }; 694 695 Time.prototype.setSeconds = function(_seconds) { 696 this.milliseconds = 1000 * _seconds; 697 }; 698 699 Time.prototype.getSeconds = function() { 700 return this.milliseconds / 1000; 701 }; 702 703 Time.prototype.getHMS = function() { 704 var _totalSeconds = Math.abs(Math.floor(this.getSeconds())); 705 return { 706 hours : Math.floor(_totalSeconds / 3600), 707 minutes : (Math.floor(_totalSeconds / 60) % 60), 708 seconds : _totalSeconds % 60, 709 milliseconds: this.milliseconds % 1000 710 }; 711 }; 712 713 Time.prototype.add = function(_milliseconds) { 714 this.milliseconds += new Time(_milliseconds).milliseconds; 715 }; 716 717 Time.prototype.valueOf = function() { 718 return this.milliseconds; 719 }; 720 721 Time.prototype.toString = function(showCs) { 722 var _hms = this.getHMS(), 723 _res = ''; 724 if (_hms.hours) { 725 _res += _hms.hours + ':'; 726 } 727 _res += pad(2, _hms.minutes) + ':' + pad(2, _hms.seconds); 728 if (showCs) { 729 _res += "." + Math.floor(_hms.milliseconds / 100); 730 } 731 return _res; 732 }; 733 734 /* Reference handles references between elements 735 */ 736 737 var Reference = Model.Reference = function(_source, _idRef) { 738 this.source = _source; 739 this.id = _idRef; 740 if (typeof _idRef === "object") { 741 this.isList = true; 742 } else { 743 this.isList = false;
744 } 745 this.refresh(); 746 }; 747 748 Reference.prototype.refresh = function() { 749 if (this.isList) { 750 this.contents = new List(this.source.directory); 751 this.contents.addIds(this.id); 752 } else { 753 this.contents = this.source.getElement(this.id); 754 } 755 756 }; 757 758 Reference.prototype.getContents = function() { 759 if (typeof this.contents === "undefined" || (this.isList && this.contents.length != this.id.length)) { 760 this.refresh(); 761 } 762 return this.contents; 763 }; 764 765 Reference.prototype.isOrHasId = function(_idRef) { 766 if (this.isList) { 767 return (ns._(this.id).indexOf(_idRef) !== -1); 768 } else { 769 return (this.id == _idRef); 770 } 771 }; 772 773 /* */ 774 775 var BaseElement = Model.Element = function(_id, _source) { 776 this.elementType = 'element'; 777 this.title = ""; 778 this.description = ""; 779 this.__events = {}; 780 if (typeof _source === "undefined") { 781 return; 782 } 783 if (typeof _id === "undefined" || !_id) { 784 _id = getUID(); 785 } 786 this.id = _id; 787 this.source = _source; 788 if (_source !== this) { 789 this.source.directory.addElement(this); 790 } 791 }; 792 793 BaseElement.prototype.toString = function() { 794 return this.elementType + (this.elementType !== 'element' ? ', id=' + this.id + ', title="' + this.title + '"' : ''); 795 }; 796 797 BaseElement.prototype.setReference = function(_elementType, _idRef) { 798 this[_elementType] = new Reference(this.source, _idRef); 799 }; 800 801 BaseElement.prototype.getReference = function(_elementType) { 802 if (typeof this[_elementType] !== "undefined") { 803 return this[_elementType].getContents(); 804 } 805 }; 806 807 BaseElement.prototype.getRelated = function(_elementType, _global) { 808 _global = (typeof _global !== "undefined" && _global); 809 var _this = this; 810 return this.source.getList(_elementType, _global).filter(function(_el) { 811 var _ref = _el[_this.elementType]; 812 return _ref && _ref.isOrHasId(_this.id); 813 }); 814 }; 815 816 /** 817 * Return a short surrogate for the element: 818 * either its title or the first line of its description 819 */ 820 BaseElement.prototype.getTitleOrDescription = function () { 821 var t = this.title || this.description || ""; 822 t = t.split(/\n/)[0]; 823 return t; 824 }; 825 826 BaseElement.prototype.on = function(_event, _callback) { 827 if (typeof this.__events[_event] === "undefined") { 828 this.__events[_event] = []; 829 } 830 this.__events[_event].push(_callback); 831 }; 832 833 BaseElement.prototype.off = function(_event, _callback) { 834 if (typeof this.__events[_event] !== "undefined") { 835 this.__events[_event] = ns._(this.__events[_event]).reject(function(_fn) { 836 return _fn === _callback; 837 }); 838 } 839 }; 840 841 BaseElement.prototype.trigger = function(_event, _data) { 842 var _element = this; 843 ns._(this.__events[_event]).each(function(_callback) { 844 _callback.call(_element, _data); 845 }); 846 }; 847 848 /* */ 849 850 var Playable = Model.Playable = function(_id, _source) { 851 BaseElement.call(this, _id, _source); 852 if (typeof _source === "undefined") { 853 return; 854 } 855 this.elementType = 'playable'; 856 this.currentTime = new Time(); 857 this.volume = .5; 858 this.paused = true; 859 this.muted = false; 860 this.timeRange = false; 861 this.loadedMetadata = false; 862 var _this = this; 863 this.on("play", function() { 864 _this.paused = false; 865 }); 866 this.on("pause", function() { 867 _this.paused = true; 868 }); 869 this.on("timeupdate", function(_time) { 870 _this.currentTime = _time; 871 _this.getAnnotations().filter(function(_a) { 872 return (_a.end <= _time || _a.begin > _time) && _a.playing; 873 }
873).forEach(function(_a) { 874 _a.playing = false; 875 _a.trigger("leave"); 876 _this.trigger("leave-annotation", _a); 877 }); 878 _this.getAnnotations().filter(function(_a) { 879 return _a.begin <= _time && _a.end > _time && !_a.playing; 880 }).forEach(function(_a) { 881 _a.playing = true; 882 _a.trigger("enter"); 883 _this.trigger("enter-annotation", _a); 884 }); 885 886 if (_this.getTimeRange()) { 887 if (_this.getTimeRange()[0] > _time) { 888 _this.pause(); 889 _this.setCurrentTime(_this.getTimeRange()[0]); 890 } 891 if (_this.getTimeRange()[1] < _time) { 892 _this.pause(); 893 _this.setCurrentTime(_this.getTimeRange()[1]); 894 } 895 } 896 897 }); 898 this.on("loadedmetadata", function() { 899 _this.loadedMetadata = true; 900 }); 901 }; 902 903 extendPrototype(Playable, BaseElement); 904 905 Playable.prototype.getCurrentTime = function() { 906 return this.currentTime; 907 }; 908 909 Playable.prototype.getVolume = function() { 910 return this.volume; 911 }; 912 913 Playable.prototype.getPaused = function() { 914 return this.paused; 915 }; 916 917 Playable.prototype.getMuted = function() { 918 return this.muted; 919 }; 920 921 Playable.prototype.getTimeRange = function() { 922 return this.timeRange; 923 }; 924 925 Playable.prototype.setCurrentTime = function(_time) { 926 this.trigger("setcurrenttime", _time); 927 }; 928 929 Playable.prototype.setVolume = function(_vol) { 930 this.trigger("setvolume", _vol); 931 }; 932 933 Playable.prototype.setMuted = function(_muted) { 934 this.trigger("setmuted", _muted); 935 }; 936 937 Playable.prototype.setTimeRange = function(_timeBegin, _timeEnd) { 938 if ((_timeBegin < _timeEnd) && (_timeBegin >= 0) && (_timeEnd > 0)) { 939 return this.trigger("settimerange", [_timeBegin, _timeEnd]); 940 } 941 }; 942 943 Playable.prototype.resetTimeRange = function() { 944 return this.trigger("resettimerange"); 945 }; 946 947 Playable.prototype.play = function() { 948 this.trigger("setplay"); 949 }; 950 951 Playable.prototype.pause = function() { 952 this.trigger("setpause"); 953 }; 954 955 Playable.prototype.togglePlayPause = function () { 956 if (this.getPaused()) { 957 this.play(); 958 } else { 959 this.pause(); 960 }; 961 }; 962 963 Playable.prototype.show = function() {}; 964 965 Playable.prototype.hide = function() {}; 966 967 /* */ 968 969 var Media = Model.Media = function(_id, _source) { 970 Playable.call(this, _id, _source); 971 this.elementType = 'media'; 972 this.duration = new Time(); 973 this.video = ''; 974 var _this = this; 975 }; 976 977 extendPrototype(Media, Playable); 978 /* */ 979 980 var Media = Model.Media = function(_id, _source) { 981 Playable.call(this, _id, _source); 982 this.elementType = 'media'; 983 this.duration = new Time(); 984 this.video = ''; 985 var _this = this; 986 }; 987 988 extendPrototype(Media, Playable); 989 990 /* Default functions to be overriden by players */ 991 992 Media.prototype.setDuration = function(_durationMs) { 993 this.duration.setMilliseconds(_durationMs); 994 }; 995 996 Media.prototype.getAnnotations = function() { 997 return this.getRelated("annotation"); 998 }; 999 1000 Media.prototype.getAnnotationsByTypeTitle = function(_title) { 1001 var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id"); 1002 if (_annTypes.length) { 1003 return this.getAnnotations().filter(function(_annotation) { 1004 return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1; 1005 }); 1006 } else { 1007 return new List(this.source.directory); 1008 } 1009 }; 1010 1011 /* */ 1012 1013 var Tag = Model.Tag = function(_id, _source) { 1014 BaseElement.call(this, _id, _source); 1015 this.elementType = 'tag'; 1016 }; 1017 1018 extendPrototype(Tag, BaseElement); 1019 1020 Tag.prototype.getAnnotations = function() { 1021 return this.getRelated("annotation"); 1022 }; 1023 1024 /* */ 1025 var AnnotationType = Model.AnnotationType = function(_id, _source) { 1026 BaseElement.call(this, _id, _source); 1027 this.elementType = 'annotationType'; 1028 }; 1029 1030 extendPrototype(AnnotationType, BaseElement); 1031 1032 AnnotationType.prototype.getAnnotations = function() { 1033 return this.getRelated("annotation"); 1034 }; 1035 1036 /* Annotation 1037 * */ 1038 1039 var Annotation = Model.Annotation = function(_id, _source) { 1040 BaseElement.call(this, _id, _source); 1041 this.elementType = 'annotation'; 1042 this.begin = new Time(); 1043 this.end = new Time(); 1044 this.tag = new Reference(_source, []); 1045 this.playing = false;
1046 var _this = this; 1047 this.on("click", function() { 1048 _this.getMedia().setCurrentTime(_this.begin); 1049 }); 1050 }; 1051 1052 extendPrototype(Annotation, BaseElement); 1053 1054 /* Set begin and end in one go, to avoid undesired side-effects in 1055 * setBegin/setEnd interaction */ 1056 Annotation.prototype.setBeginEnd = function(_beginMs, _endMs) { 1057 _beginMs = Math.max(0, _beginMs); 1058 _endMs = Math.max(0, _endMs); 1059 if (_endMs < _beginMs) { 1060 _endMs = _beginMs; 1061 } 1062 this.begin.setMilliseconds(_beginMs); 1063 this.end.setMilliseconds(_endMs); 1064 this.trigger("change-begin"); 1065 this.trigger("change-end"); 1066 }; 1067 1068 Annotation.prototype.setBegin = function(_beginMs) { 1069 this.begin.setMilliseconds(Math.max(0, _beginMs)); 1070 this.trigger("change-begin"); 1071 if (this.end < this.begin) { 1072 this.setEnd(this.begin); 1073 } 1074 }; 1075 1076 Annotation.prototype.setEnd = function(_endMs) { 1077 this.end.setMilliseconds(Math.min(_endMs, this.getMedia().duration.milliseconds)); 1078 this.trigger("change-end"); 1079 if (this.end < this.begin) { 1080 this.setBegin(this.end); 1081 } 1082 }; 1083 1084 Annotation.prototype.setDuration = function(_durMs) { 1085 this.setEnd(_durMs + this.begin.milliseconds); 1086 }; 1087 1088 Annotation.prototype.setMedia = function(_idRef) { 1089 this.setReference("media", _idRef); 1090 }; 1091 1092 Annotation.prototype.getMedia = function() { 1093 return this.getReference("media"); 1094 }; 1095 1096 Annotation.prototype.setAnnotationType = function(_idRef) { 1097 this.setReference("annotationType", _idRef); 1098 }; 1099 1100 Annotation.prototype.getAnnotationType = function() { 1101 return this.getReference("annotationType"); 1102 }; 1103 1104 Annotation.prototype.setTags = function(_idRefs) { 1105 this.setReference("tag", _idRefs); 1106 }; 1107 1108 Annotation.prototype.getTags = function() { 1109 return this.getReference("tag"); 1110 }; 1111 1112 Annotation.prototype.getTagTexts = function() { 1113 return this.getTags().getTitles(); 1114 }; 1115 1116 Annotation.prototype.getDuration = function() { 1117 return new Time(this.end.milliseconds - this.begin.milliseconds); 1118 }; 1119 1120 /* */ 1121 1122 var MashedAnnotation = Model.MashedAnnotation = function(_mashup, _annotation) { 1123 BaseElement.call(this, _mashup.id + "_" + _annotation.id, _annotation.source); 1124 this.elementType = 'mashedAnnotation'; 1125 this.annotation = _annotation; 1126 this.begin = new Time(); 1127 this.end = new Time(); 1128 this.duration = new Time(); 1129 this.title = this.annotation.title; 1130 this.description = this.annotation.description; 1131 this.color = this.annotation.color; 1132 var _this = this; 1133 this.on("click", function() { 1134 _mashup.setCurrentTime(_this.begin); 1135 }); 1136 this.on("enter", function() { 1137 _this.annotation.trigger("enter"); 1138 }); 1139 this.on("leave", function() { 1140 _this.annotation.trigger("leave"); 1141 }); 1142 }; 1143 1144 extendPrototype(MashedAnnotation, BaseElement); 1145 1146 MashedAnnotation.prototype.getMedia = function() { 1147 return this.annotation.getReference("media"); 1148 }; 1149 1150 MashedAnnotation.prototype.getAnnotationType = function() { 1151 return this.annotation.getReference("annotationType"); 1152 }; 1153 1154 MashedAnnotation.prototype.getTags = function() { 1155 return this.annotation.getReference("tag"); 1156 }; 1157 1158 MashedAnnotation.prototype.getTagTexts = function() { 1159 return this.annotation.getTags().getTitles(); 1160 }; 1161 1162 MashedAnnotation.prototype.getDuration = function() { 1163 return this.annotation.getDuration(); 1164 }; 1165 1166 MashedAnnotation.prototype.setBegin = function(_begin) { 1167 this.begin.setMilliseconds(_begin); 1168 this.duration.setMilliseconds(this.annotation.getDuration()); 1169 this.end.setMilliseconds(_begin + this.duration); 1170 }; 1171 1172 /* */ 1173 1174 var Mashup = Model.Mashup = function(_id, _source) { 1175 Playable.call(this, _id, _source); 1176 this.elementType = 'mashup'; 1177 this.duration = new Time(); 1178 this.segments = new List(_source.directory); 1179 this.loaded = false;
1180 var _this = this; 1181 this._updateTimes = function() { 1182 _this.updateTimes(); 1183 _this.trigger("change"); 1184 }; 1185 this.on("add", this._updateTimes); 1186 this.on("remove", this._updateTimes); 1187 }; 1188 1189 extendPrototype(Mashup, Playable); 1190 1191 Mashup.prototype.updateTimes = function() { 1192 var _time = 0; 1193 this.segments.forEach(function(_segment) { 1194 _segment.setBegin(_time); 1195 _time = _segment.end; 1196 }); 1197 this.duration.setMilliseconds(_time); 1198 }; 1199 1200 Mashup.prototype.addAnnotation = function(_annotation, _defer) { 1201 var _mashedAnnotation = new MashedAnnotation(this, _annotation), 1202 _defer = _defer || false; 1203 this.segments.push(_mashedAnnotation); 1204 _annotation.on("change-begin", this._updateTimes); 1205 _annotation.on("change-end", this._updateTimes); 1206 if (!_defer) { 1207 this.trigger("add"); 1208 } 1209 }; 1210 1211 Mashup.prototype.addAnnotationById = function(_elId, _defer) { 1212 var _annotation = this.source.getElement(_elId), 1213 _defer = _defer || false; 1214 if (typeof _annotation !== "undefined") { 1215 this.addAnnotation(_annotation, _defer); 1216 } 1217 }; 1218 1219 Mashup.prototype.addAnnotations = function(_segments) { 1220 var _this = this; 1221 ns._(_segments).forEach(function(_segment) { 1222 _this.addAnnotation(_segment, true); 1223 }); 1224 this.trigger("add"); 1225 }; 1226 1227 Mashup.prototype.addAnnotationsById = function(_segments) { 1228 var _this = this; 1229 ns._(_segments).forEach(function(_segment) { 1230 _this.addAnnotationById(_segment, true); 1231 }); 1232 this.trigger("add"); 1233 }; 1234 1235 Mashup.prototype.removeAnnotation = function(_annotation, _defer) { 1236 var _defer = _defer || false; 1237 _annotation.off("change-begin", this._updateTimes); 1238 _annotation.off("change-end", this._updateTimes); 1239 this.segments.removeId(this.id + "_" + _annotation.id); 1240 if (!_defer) { 1241 this.trigger("remove"); 1242 } 1243 }; 1244 1245 Mashup.prototype.removeAnnotationById = function(_annId, _defer) { 1246 var _defer = _defer || false; 1247 var _annotation = this.source.getElement(_annId); 1248 1249 if (_annotation) { 1250 this.removeAnnotation(_annotation, _defer); 1251 } 1252 if (!_defer) { 1253 this.trigger("remove"); 1254 } 1255 }; 1256 1257 Mashup.prototype.setAnnotations = function(_segments) { 1258 while (this.segments.length) { 1259 this.removeAnnotation(this.segments[0].annotation, true); 1260 } 1261 this.addAnnotations(_segments); 1262 }; 1263 1264 Mashup.prototype.setAnnotationsById = function(_segments) { 1265 while (this.segments.length) { 1266 this.removeAnnotation(this.segments[0].annotation, true); 1267 } 1268 this.addAnnotationsById(_segments); 1269 }; 1270 1271 Mashup.prototype.hasAnnotation = function(_annotation) { 1272 return !!ns._(this.segments).find(function(_s) { 1273 return _s.annotation === _annotation; 1274 }); 1275 }; 1276 1277 Mashup.prototype.getAnnotation = function(_annotation) { 1278 return ns._(this.segments).find(function(_s) { 1279 return _s.annotation === _annotation; 1280 }); 1281 }; 1282 1283 Mashup.prototype.getAnnotationById = function(_id) { 1284 return ns._(this.segments).find(function(_s) { 1285 return _s.annotation.id === _id; 1286 }); 1287 }; 1288 1289 Mashup.prototype.getAnnotations = function() { 1290 return this.segments; 1291 }; 1292 1293 Mashup.prototype.getOriginalAnnotations = function() { 1294 var annotations = new List(this.source.directory); 1295 this.segments.forEach(function(_s) { 1296 annotations.push(_s.annotation); 1297 }); 1298 return annotations; 1299 }; 1300 1301 Mashup.prototype.getMedias = function() { 1302 var medias = new List(this.source.directory); 1303 this.segments.forEach(function(_annotation) { 1304 medias.push(_annotation.getMedia()); 1305 }); 1306 return medias; 1307 }; 1308 1309 Mashup.prototype.getAnnotationsByTypeTitle = function(_title) { 1310 var _annTypes = this.source.getAnnotationTypes().searchByTitle(_title).pluck("id"); 1311 if (_annTypes.length) { 1312 return this.getAnnotations().filter(function(_annotation) { 1313 return ns._(_annTypes).indexOf(_annotation.getAnnotationType().id) !== -1; 1314 }); 1315 } else { 1316 return new List(this.source.directory); 1317 } 1318 }; 1319 1320 Mashup.prototype.getAnnotationAtTime = function(_time) { 1321 var _list = this.segments.filter(function(_annotation) { 1322 return _annotation.begin <= _time && _annotation.end > _time; 1323 }); 1324 if (_list.length) { 1325 return _list[0]; 1326 } else { 1327 return undefined; 1328 } 1329 }; 1330 1331 Mashup.prototype.getMediaAtTime = function(_time) { 1332 var _annotation = this.getAnnotationAtTime(_time); 1333 if (typeof _annotation !== "undefined") { 1334 return _annotation.getMedia(); 1335 } else { 1336 return undefined; 1337 } 1338 }; 1339 1340 /* */ 1341 1342 var Source = Model.Source = function(_config) { 1343 BaseElement.call(this, false, this); 1344 this.status = _SOURCE_STATUS_EMPTY; 1345 this.elementType = "source"; 1346 if (typeof _config !== "undefined") { 1347 var _this = this; 1348 ns._(_config).forEach(function(_v, _k) { 1349 _this[_k] = _v; 1350 }); 1351 this.callbackQueue = []; 1352 this.contents = {}; 1353 this.get(); 1354 } 1355 }; 1356 1357 extendPrototype(Source, BaseElement); 1358 1359 Source.prototype.addList = function(_listId, _contents) { 1360 if (typeof this.contents[_listId] === "undefined") { 1361 this.contents[_listId] = new List(this.directory); 1362 } 1363 this.contents[_listId].addElements(_contents); 1364 }; 1365 1366 Source.prototype.getList = function(_listId, _global) { 1367 _global = (typeof _global !== "undefined" && _global); 1368 if (_global) { 1369 return this.directory.getGlobalList().filter(function(_e) { 1370 return (_e.elementType === _listId); 1371 }); 1372 } else { 1373 if (typeof this.contents[_listId] === "undefined") { 1374 this.contents[_listId] = new List(this.directory); 1375 } 1376 return this.contents[_listId]; 1377 } 1378 }; 1379 1380 Source.prototype.forEach = function(_callback) { 1381 var _this = this;
1382 ns._(this.contents).forEach(function(_value, _key) { 1383 _callback.call(_this, _value, _key); 1384 }); 1385 }; 1386 1387 Source.prototype.getElement = function(_elId) { 1388 return this.directory.getElement(_elId); 1389 }; 1390 1391 Source.prototype.get = function() { 1392 this.status = _SOURCE_STATUS_WAITING; 1393 this.handleCallbacks(); 1394 }; 1395 1396 /* We defer the callbacks calls so they execute after the queue is cleared */ 1397 Source.prototype.deferCallback = function(_callback) { 1398 var _this = this; 1399 ns._.defer(function() { 1400 _callback.call(_this); 1401 }); 1402 }; 1403 1404 Source.prototype.handleCallbacks = function() { 1405 this.status = _SOURCE_STATUS_READY; 1406 while (this.callbackQueue.length) { 1407 this.deferCallback(this.callbackQueue.splice(0, 1)[0]); 1408 } 1409 }; 1410 Source.prototype.onLoad = function(_callback) { 1411 if (this.status === _SOURCE_STATUS_READY) { 1412 this.deferCallback(_callback); 1413 } else { 1414 this.callbackQueue.push(_callback); 1415 } 1416 }; 1417 1418 Source.prototype.serialize = function() { 1419 return this.serializer.serialize(this); 1420 }; 1421 1422 Source.prototype.deSerialize = function(_data) { 1423 this.serializer.deSerialize(_data, this); 1424 }; 1425 1426 Source.prototype.getAnnotations = function(_global) { 1427 _global = (typeof _global !== "undefined" && _global); 1428 return this.getList("annotation", _global); 1429 }; 1430 1431 Source.prototype.getMedias = function(_global) { 1432 _global = (typeof _global !== "undefined" && _global); 1433 return this.getList("media", _global); 1434 }; 1435 1436 Source.prototype.getTags = function(_global) { 1437 _global = (typeof _global !== "undefined" && _global); 1438 return this.getList("tag", _global); 1439 }; 1440 1441 Source.prototype.getMashups = function(_global) { 1442 _global = (typeof _global !== "undefined" && _global); 1443 return this.getList("mashup", _global); 1444 }; 1445 1446 Source.prototype.getAnnotationTypes = function(_global) { 1447 _global = (typeof _global !== "undefined" && _global); 1448 return this.getList("annotationType", _global); 1449 }; 1450 1451 Source.prototype.getAnnotationsByTypeTitle = function(_title, _global) { 1452 _global = (typeof _global !== "undefined" && _global); 1453 var _res = new List(this.directory), 1454 _annTypes = this.getAnnotationTypes(_global).searchByTitle(_title); 1455 _annTypes.forEach(function(_annType) { 1456 _res.addElements(_annType.getAnnotations(_global)); 1457 }); 1458 return _res; 1459 }; 1460 1461 Source.prototype.getDuration = function() { 1462 var _m = this.currentMedia; 1463 if (typeof _m !== "undefined") { 1464 return this.currentMedia.duration; 1465 } 1466 }; 1467 1468 Source.prototype.getCurrentMedia = function(_opts) { 1469 if (typeof this.currentMedia === "undefined") { 1470 if (_opts.is_mashup) { 1471 var _mashups = this.getMashups(); 1472 if (_mashups.length) { 1473 this.currentMedia = _mashups[0]; 1474 } 1475 } else { 1476 var _medias = this.getMedias(); 1477 if (_medias.length) { 1478 this.currentMedia = _medias[0]; 1479 } 1480 } 1481 } 1482 return this.currentMedia; 1483 }; 1484 1485 Source.prototype.merge = function(_source) { 1486 var _this = this; 1487 _source.forEach(function(_value, _key) { 1488 _this.getList(_key).addElements(_value); 1489 }); 1490 }; 1491 1492 /* */ 1493 1494 var RemoteSource = Model.RemoteSource = function(_config) { 1495 Source.call(this, _config); 1496 }; 1497 1498 extendPrototype(RemoteSource, Source); 1499 1500 RemoteSource.prototype.get = function() { 1501 this.status = _SOURCE_STATUS_WAITING; 1502 var _this = this, 1503 urlparams = this.url_params || {}, 1504 dataType = (isLocalURL(this.url) ? "json" : "jsonp"); 1505 urlparams.format = dataType; 1506 ns.jQuery.ajax({ 1507 url: this.url, 1508 dataType: dataType, 1509 data: urlparams, 1510 traditional: true, 1511 success: function(_result) { 1512 _this.deSerialize(_result); 1513 _this.handleCallbacks(); 1514 } 1515 }); 1516 }; 1517 1518 /* */ 1519 1520 var Directory = Model.Directory = function() { 1521 this.remoteSources = {}; 1522 this.elements = {}; 1523 }; 1524 1525 Directory.prototype.remoteSource = function(_properties) { 1526 if (typeof _properties !== "object" || typeof _properties.url === "undefined") { 1527 throw "Error : Directory.remoteSource(configuration): configuration.url is undefined"; 1528 } 1529 var _config = ns._({ directory: this }).extend(_properties); 1530 _config.url_params = _config.url_params || {};
1531 var _hash = _config.url + "?" + ns.jQuery.param(_config.url_params); 1532 if (typeof this.remoteSources[_hash] === "undefined") { 1533 this.remoteSources[_hash] = new RemoteSource(_config); 1534 } 1535 return this.remoteSources[_hash]; 1536 }; 1537 1538 Directory.prototype.newLocalSource = function(_properties) { 1539 var _config = ns._({ directory: this }).extend(_properties), 1540 _res = new Source(_config); 1541 return _res; 1542 }; 1543 1544 Directory.prototype.getElement = function(_id) { 1545 return this.elements[_id]; 1546 }; 1547 1548 Directory.prototype.addElement = function(_element) { 1549 this.elements[_element.id] = _element; 1550 }; 1551 1552 Directory.prototype.getGlobalList = function() { 1553 var _res = new List(this); 1554 _res.addIds(ns._(this.elements).keys()); 1555 return _res; 1556 }; 1557 return Model; 1558 1559})(IriSP); 1560 1561/* END js */ 1562/* HTML player, to be reused in a widget, or elsewhere */ 1563 1564IriSP.htmlPlayer = function (media, jqselector, options) { 1565 1566 var opts = options || {}, 1567 videoURL = opts.video || media.video; 1568 1569 if (typeof opts.url_transform === "function") { 1570 videoURL = opts.url_transform(videoURL); 1571 } 1572 1573 var videoEl = IriSP.jQuery('<video>'); 1574 1575 videoEl.attr({ 1576 width : opts.width || undefined, 1577 height : opts.height || undefined, 1578 controls : opts.controls || undefined, 1579 autoplay : opts.autostart || opts.autoplay || undefined, 1580 preload: "metadata" 1581 }); 1582 1583 if (typeof videoURL === "string") { 1584 videoEl.attr("src", videoURL); 1585 } else { 1586 for (var i = 0; i < videoURL.length; i++) { 1587 var _srcNode = IriSP.jQuery('<source>'); 1588 _srcNode.attr({ 1589 src: videoURL[i].src, 1590 type: videoURL[i].type 1591 }); 1592 videoEl.append(_srcNode); 1593 } 1594 } 1595 if (opts.subtitle) { 1596 var _trackNode = IriSP.jQuery('<track>'); 1597 _trackNode.attr({ 1598 label: "Subtitles", 1599 kind: "subtitles", 1600 srclang: "fr", 1601 src: opts.subtitle, 1602 default: "" 1603 }); 1604 videoEl.append(_trackNode); 1605 } 1606 jqselector.prepend(videoEl); 1607 1608 var mediaEl = videoEl[0]; 1609 1610 // Binding HTML video functions to media events 1611 media.on("setcurrenttime", function (_milliseconds) { 1612 try { 1613 mediaEl.currentTime = (_milliseconds / 1000); 1614 } catch (err) { 1615 1616 } 1617 }); 1618 1619 media.on("setvolume", function (_vol) { 1620 media.volume = _vol; 1621 try { 1622 mediaEl.volume = _vol; 1623 } catch (err) { 1624 1625 } 1626 }); 1627 1628 media.on("setmuted", function (_muted) { 1629 media.muted = _muted; 1630 try { 1631 mediaEl.muted = _muted; 1632 } catch (err) { 1633 1634 } 1635 }); 1636 1637 media.on("settimerange", function (_timeRange) { 1638 media.timeRange = _timeRange; 1639 try { 1640 if (media.getCurrentTime() > _timeRange[0] || media.getCurrentTime() < _timeRange) { 1641 mediaEl.currentTime = (_timeRange[0] / 1000); 1642 } 1643 } catch (err) { 1644 } 1645 }); 1646 1647 media.on("resettimerange", function () { 1648 media.timeRange = false; 1649 }); 1650 1651 media.on("setplay", function () { 1652 try { 1653 mediaEl.play(); 1654 } catch (err) { 1655 1656 } 1657 }); 1658 1659 media.on("setpause", function () { 1660 try { 1661 mediaEl.pause(); 1662 } catch (err) { 1663 1664 } 1665 }); 1666 1667 // Binding DOM events to media 1668 function getVolume() { 1669 media.muted = mediaEl.muted; 1670 media.volume = mediaEl.volume; 1671 } 1672 1673 videoEl.on("loadedmetadata", function () { 1674 getVolume(); 1675 media.trigger("loadedmetadata"); 1676 media.trigger("volumechange"); 1677 }); 1678 1679 videoEl.on("timeupdate", function () { 1680 media.trigger("timeupdate", new IriSP.Model.Time(1000 * mediaEl.currentTime)); 1681 }); 1682 1683 videoEl.on("volumechange", function () { 1684 getVolume(); 1685 media.trigger("volumechange"); 1686 }); 1687 1688 videoEl.on("play", function () { 1689 media.trigger("play"); 1690 }); 1691 1692 videoEl.on("pause", function () { 1693 media.trigger("pause"); 1694 }); 1695 1696 videoEl.on("seeking", function () { 1697 media.trigger("seeking"); 1698 }); 1699 1700 videoEl.on("seeked", function () { 1701 media.trigger("seeked"); 1702 }); 1703 1704 videoEl.on("click", function () { 1705 if (mediaEl.paused) { 1706 media.play(); 1707 } else { 1708 media.pause(); 1709 }; 1710 }); 1711}; 1712/* START contentapi-serializer.js */ 1713 1714if (typeof IriSP.serializers === "undefined") { 1715 IriSP.serializers = {}; 1716} 1717 1718IriSP.serializers.content = { 1719 deSerialize : function(_data, _source) { 1720 var _medialist = new IriSP.Model.List(_source.directory); 1721 1722 function deserializeObject(_m, i) { 1723 var _media = new IriSP.Model.Media(_m.iri_id, _source); 1724 _media.video = _m.media_url; 1725 _media.title = _m.title; 1726 _media.description = _m.description; 1727 _media.setDuration(_m.duration); 1728 _media.thumbnail = _m.image; 1729 _media.color = IriSP.vizcolors[i % IriSP.vizcolors.length]; 1730 _media.keywords = _m.tags; 1731 _medialist.push(_media); 1732 } 1733 1734 if (typeof _data.objects !== "undefined") { 1735 IriSP._(_data.objects).each(deserializeObject); 1736 } else { 1737 deserializeObject(_data, 0); 1738 } 1739 1740 _source.addList("media", _medialist); 1741 } 1742}; 1743 1744/* END contentapi-serializer.js */ 1745/* Start ldt-serializer.js */ 1746 1747if (typeof IriSP.serializers === "undefined") { 1748 IriSP.serializers = {}; 1749} 1750 1751IriSP.serializers.ldt = { 1752 types : { 1753 media : { 1754 serialized_name : "medias", 1755 deserializer : function(_data, _source) { 1756 var _res = new IriSP.Model.Media(_data.id, _source); 1757 _res.video = ( 1758 typeof _data.url !== "undefined" 1759 ? _data.url 1760 : ( 1761 typeof _data.href !== "undefined" 1762 ? _data.href 1763 : null 1764 ) 1765 ); 1766 if (typeof _data.meta.item !== "undefined" && _data.meta.item.name === "streamer") { 1767 _res.streamer = _data.meta.item.value; 1768 } 1769 _res.title = _data.meta["dc:title"]; 1770 _res.description = _data.meta["dc:description"]; 1771 _res.setDuration(_data.meta["dc:duration"]); 1772 _res.url = _data.meta.url; 1773 _res.meta = _data.meta; 1774 if (typeof _data.meta.img !== "undefined" && _data.meta.img.src !== "undefined") { 1775 _res.thumbnail = _data.meta.img.src; 1776 } 1777 return _res; 1778 }, 1779 serializer : function(_data, _source, _dest) { 1780 var _res = { 1781 id : _data.id, 1782 url : _data.video, 1783 meta : { 1784 "dc:title": _data.title || "", 1785 "dc:description": _data.description || "", 1786 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1787 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1788 "dc:creator" : _data.creator || _source.creator, 1789 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator, 1790 "dc:duration" : _data.duration.milliseconds 1791 } 1792 }; 1793 IriSP._.defaults(_res.meta, _data.meta); 1794 _dest.medias.push(_res); 1795 var _list = { 1796 id: IriSP.Model.getUID(), 1797 meta : { 1798 "dc:title": _data.title || "", 1799 "dc:description": _data.description || "", 1800 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1801 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1802 "dc:creator" : _data.creator || _source.creator, 1803 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator, 1804 "id-ref": _data.id 1805 }, 1806 items: _source.getAnnotationTypes().filter(function(_at) { 1807 switch (typeof _at.media) { 1808 case "object": 1809 return (_at.media === _data); 1810 case "string": 1811 return (_at.media === _data.id); 1812 default: 1813 var _ann = _at.getAnnotations(); 1814 if (_ann) { 1815 for (var i = 0; i < _ann.length; i++) { 1816 if (_ann[i].getMedia() === _data) { 1817 return true; 1818 } 1819 } 1820 } 1821 } 1822 return false;
1823 }).map(function(_at) { 1824 return { 1825 "id-ref": _at.id 1826 }; 1827 }) 1828 }; 1829 _dest.lists.push(_list); 1830 _dest.views[0].contents.push(_data.id); 1831 } 1832 }, 1833 tag : { 1834 serialized_name : "tags", 1835 deserializer : function(_data, _source) { 1836 var _res = new IriSP.Model.Tag(_data.id, _source); 1837 _res.title = _data.meta["dc:title"]; 1838 return _res; 1839 }, 1840 serializer : function(_data, _source, _dest) { 1841 if (_source.regenerateTags && !_data.regenerated) { 1842 return; 1843 } 1844 var _res = { 1845 id : _data.id, 1846 meta : { 1847 "dc:title": _data.title || "", 1848 "dc:description": _data.description || "", 1849 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1850 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1851 "dc:creator" : _data.creator || _source.creator, 1852 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator 1853 } 1854 }; 1855 _dest.tags.push(_res); 1856 } 1857 }, 1858 annotationType : { 1859 serialized_name : "annotation-types", 1860 deserializer : function(_data, _source) { 1861 var _res = new IriSP.Model.AnnotationType(_data.id, _source); 1862 _res.title = _data["dc:title"]; 1863 _res.description = _data["dc:description"]; 1864 return _res; 1865 }, 1866 serializer : function(_data, _source, _dest) { 1867 var _res = { 1868 id : _data.id, 1869 "dc:title": _data.title || "", 1870 "dc:description": _data.description || "", 1871 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1872 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1873 "dc:creator" : _data.creator || _source.creator, 1874 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator 1875 }; 1876 _dest["annotation-types"].push(_res); 1877 _dest.views[0].annotation_types.push(_data.id); 1878 } 1879 }, 1880 annotation : { 1881 serialized_name : "annotations", 1882 deserializer : function(_data, _source) { 1883 var _res = new IriSP.Model.Annotation(_data.id, _source); 1884 _res.title = _data.content.title || ""; 1885 _res.description = _data.content.description || ""; 1886 if (typeof _data.content.img !== "undefined" && _data.content.img.src !== "undefined") { 1887 _res.thumbnail = _data.content.img.src; 1888 } 1889 _res.created = IriSP.Model.isoToDate(_data.created ? _data.created : _data.meta? _data.meta["dc:created"] : ""); 1890 if (typeof _data.color !== "undefined") { 1891 var _c = parseInt(_data.color).toString(16); 1892 while (_c.length < 6) { 1893 _c = '0' + _c; 1894 } 1895 _res.color = '#' + _c; 1896 } 1897 _res.content = _data.content; 1898 _res.setMedia(_data.media); 1899 _res.setAnnotationType(_data.meta["id-ref"]); 1900 _res.setTags(IriSP._(_data.tags).pluck("id-ref")); 1901 _res.keywords = _res.getTagTexts(); 1902 _res.setBegin(_data.begin); 1903 _res.setEnd(_data.end); 1904 _res.creator = _data.meta["dc:creator"] || ""; 1905 _res.project = _data.meta.project || ""; 1906 if (typeof _data.meta["dc:source"] !== "undefined" && typeof _data.meta["dc:source"].content !== "undefined") { 1907 _res.source = JSON.parse(_data.meta["dc:source"].content); 1908 } 1909 if (typeof _data.content.audio !== "undefined" && _data.content.audio.href) { 1910 _res.audio = _data.content.audio; 1911 } 1912 _res.meta = _data.meta; 1913 return _res; 1914 }, 1915 serializer : function(_data, _source, _dest) { 1916 var _color = parseInt(_data.color.replace(/^#/,''),16).toString(); 1917 var _res = { 1918 id : _data.id, 1919 begin : _data.begin.milliseconds, 1920 end : _data.end.milliseconds, 1921 content : IriSP._.defaults( 1922 {}, 1923 { 1924 title : _data.title, 1925 description : _data.description, 1926 audio : _data.audio, 1927 img: { 1928 src: _data.thumbnail 1929 } 1930 }, 1931 _data.content, 1932 { 1933 title: "", 1934 description: "" 1935 } 1936 ), 1937 color: _color, 1938 media : _data.media.id, 1939 meta : { 1940 "id-ref" : _data.getAnnotationType().id, 1941 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1942 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1943 "dc:creator" : _data.creator || _source.creator, 1944 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator 1945// project : _source.projectId 1946 } 1947 }; 1948 if (_source.regenerateTags) { 1949 _res.tags = IriSP._(_data.keywords).map(function(_kw) { 1950 return { 1951 "id-ref": _source.__keywords[_kw.toLowerCase()].id 1952 }; 1953 }); 1954 } else { 1955 _res.tags = IriSP._(_data.tag.id).map(function(_id) { 1956 return { 1957 "id-ref" : _id 1958 }; 1959 }); 1960 } 1961 _res.content.title = _data.title || _res.content.title || ""; 1962 IriSP._.defaults(_res.meta, _data.meta); 1963 _dest.annotations.push(_res); 1964 } 1965 }, 1966 mashup : { 1967 serialized_name : "lists", 1968 deserializer : function(_data, _source) { 1969 if (typeof _data.meta !== "object" || typeof _data.meta.listtype !== "string" || _data.meta.listtype !== "mashup") { 1970 return undefined; 1971 } 1972 var _res = new IriSP.Model.Mashup(_data.id, _source); 1973 _res.title = _data.meta["dc:title"]; 1974 _res.description = _data.meta["dc:description"]; 1975 _res.creator = _data.meta["dc:creator"]; 1976 _res.setAnnotationsById(_data.items); 1977 return _res; 1978 }, 1979 serializer : function(_data, _source, _dest) { 1980 var _res = { 1981 meta : { 1982 "dc:title": _data.title || "", 1983 "dc:description": _data.description || "", 1984 "dc:created" : IriSP.Model.dateToIso(_data.created || _source.created), 1985 "dc:modified" : IriSP.Model.dateToIso(_data.modified || _source.modified), 1986 "dc:creator" : _data.creator || _source.creator, 1987 "dc:contributor" : _data.contributor || _source.contributor || _data.creator || _source.creator, 1988 listtype: "mashup" 1989 }, 1990 items: _data.segments.map(function(_annotation) { 1991 return _annotation.annotation.id; 1992 }), 1993 id: _data.id 1994 }; 1995 _dest.lists.push(_res); 1996 } 1997 } 1998 }, 1999 serialize : function(_source) { 2000 var _res = { 2001 meta: { 2002 "dc:creator": _source.creator, 2003 "dc:contributor" : _source.contributor || _source.creator, 2004 "dc:created": IriSP.Model.dateToIso(_source.created), 2005 "dc:modified" : IriSP.Model.dateToIso(_source.modified), 2006 "dc:title": _source.title || "", 2007 "dc:description": _source.description || "", 2008 id: _source.projectId || _source.id 2009 }, 2010 views: [ 2011 { 2012 id: IriSP.Model.getUID(), 2013 contents: [], 2014 annotation_types: [] 2015 } 2016 ], 2017 lists: [], 2018 "annotation-types": [], 2019 medias: [], 2020 tags: [], 2021 annotations: [] 2022 }, 2023 _this = this; 2024 if (_source.regenerateTags) { 2025 _source.__keywords = {};
2026 _source.getAnnotations().forEach(function(a) { 2027 IriSP._(a.keywords).each(function(kw) { 2028 var lkw = kw.toLowerCase(); 2029 if (typeof _source.__keywords[lkw] === "undefined") { 2030 _source.__keywords[lkw] = { 2031 id: IriSP.Model.getUID(), 2032 title: kw, 2033 regenerated: true 2034 }; 2035 } 2036 }); 2037 }); 2038 IriSP._(_source.__keywords).each(function(kw) { 2039 _this.types.tag.serializer(kw, _source, _res); 2040 }); 2041 } 2042 _source.forEach(function(_list, _typename) { 2043 if (typeof _this.types[_typename] !== "undefined") { 2044 _list.forEach(function(_el) { 2045 _this.types[_typename].serializer(_el, _source, _res); 2046 }); 2047 } 2048 }); 2049 return JSON.stringify(_res); 2050 }, 2051 deSerialize : function(_data, _source) { 2052 if (typeof _data !== "object" || _data === null) { 2053 return; 2054 } 2055 IriSP._(this.types).forEach(function(_type, _typename) { 2056 var _listdata = _data[_type.serialized_name], 2057 _list = new IriSP.Model.List(_source.directory); 2058 if (typeof _listdata !== "undefined" && _listdata !== null) { 2059 if (_listdata.hasOwnProperty("length")) { 2060 var _l = _listdata.length; 2061 for (var _i = 0; _i < _l; _i++) { 2062 var _element = _type.deserializer(_listdata[_i], _source); 2063 if (typeof _element !== "undefined" && _element) { 2064 _list.push(_element); 2065 } 2066 } 2067 } else { 2068 var _element = _type.deserializer(_listdata, _source); 2069 if (typeof _element !== "undefined" && _element) { 2070 _list.push(_element); 2071 } 2072 } 2073 } 2074 _source.addList(_typename, _list); 2075 }); 2076 2077 if (typeof _data.meta !== "undefined") { 2078 _source.projectId = _data.meta.id; 2079 _source.title = _data.meta["dc:title"] || _data.meta.title || ""; 2080 _source.description = _data.meta["dc:description"] || _data.meta.description || ""; 2081 _source.creator = _data.meta["dc:creator"] || _data.meta.creator || ""; 2082 _source.contributor = _data.meta["dc:contributor"] || _data.meta.contributor || _source.creator; 2083 _source.created = IriSP.Model.isoToDate(_data.meta["dc:created"] || _data.meta.created); 2084 } 2085 2086 if (typeof _data.meta !== "undefined" && typeof _data.meta.main_media !== "undefined" && typeof _data.meta.main_media["id-ref"] !== "undefined") { 2087 _source.currentMedia = _source.getElement(_data.meta.main_media["id-ref"]); 2088 } 2089 } 2090}; 2091 2092/* End of LDT Platform Serializer */ 2093/* ldt_annotate serializer: Used when Putting annotations on the platform */ 2094 2095if (typeof IriSP.serializers === "undefined") { 2096 IriSP.serializers = {}; 2097} 2098 2099IriSP.serializers.ldt_annotate = { 2100 serializeAnnotation : function(_data, _source) { 2101 var _annType = _data.getAnnotationType(); 2102 return { 2103 id: _data.id, 2104 begin: _data.begin.milliseconds, 2105 end: _data.end.milliseconds, 2106 content: { 2107 data: (_data.content ? _data.content.data || {} : {}), 2108 description: _data.description, 2109 title: _data.title, 2110 audio: _data.audio 2111 }, 2112 id: _data.id ? _data.id : "", // If annotation is new, id will be undefined 2113 tags: _data.getTagTexts(), 2114 media: _data.getMedia().id, 2115 project: _data.project_id, 2116 type_title: _annType.title, 2117 sharing: _data.sharing || "private", 2118 type: (typeof _annType.dont_send_id !== "undefined" && _annType.dont_send_id ? "" : _annType.id), 2119 meta: { 2120 created: _data.created,
2121 creator: _data.creator, 2122 modified: _data.modified, 2123 contributor: _data.contributor 2124 } 2125 }; 2126 }, 2127 deserializeAnnotation : function(_anndata, _source) { 2128 var _ann = new IriSP.Model.Annotation(_anndata.id, _source); 2129 _ann.description = _anndata.content.description || ""; 2130 _ann.title = _anndata.content.title || ""; 2131 _ann.creator = _anndata.meta.creator || ""; 2132 _ann.created = new Date(_anndata.meta.created); 2133 _ann.setMedia(_anndata.media, _source); 2134 var _anntype = _source.getElement(_anndata.type); 2135 if (!_anntype) { 2136 _anntype = new IriSP.Model.AnnotationType(_anndata.type, _source); 2137 _anntype.title = _anndata.type_title; 2138 _source.getAnnotationTypes().push(_anntype); 2139 } 2140 _ann.meta = _anndata.meta; 2141 _ann.setAnnotationType(_anntype.id); 2142 var _tagIds = IriSP._(_anndata.tags).map(function(_title) { 2143 var _tags = _source.getTags(true).searchByTitle(_title, true); 2144 if (_tags.length) { 2145 var _tag = _tags[0]; 2146 } else { 2147 _tag = new IriSP.Model.Tag(_title.replace(/\W/g, '_'), _source); 2148 _tag.title = _title; 2149 _source.getTags().push(_tag); 2150 } 2151 return _tag.id; 2152 }); 2153 _ann.setTags(_tagIds); 2154 _ann.setBeginEnd(_anndata.begin, _anndata.end); 2155 if (typeof _anndata.content.audio !== "undefined" && _anndata.content.audio.href) { 2156 _ann.audio = _anndata.content.audio; 2157 }; 2158 if (_anndata.content.data) { 2159 _ann.content = { data: _anndata.content.data }; 2160 }; 2161 _source.getAnnotations().push(_ann); 2162 }, 2163 serialize : function(_source) { 2164 return JSON.stringify(this.serializeAnnotation(_source.getAnnotations()[0], _source)); 2165 }, 2166 deSerialize : function(_data, _source) { 2167 if (typeof _data == "string") { 2168 _data = JSON.parse(_data); 2169 } 2170 2171 _source.addList('tag', new IriSP.Model.List(_source.directory)); 2172 _source.addList('annotationType', new IriSP.Model.List(_source.directory)); 2173 _source.addList('annotation', new IriSP.Model.List(_source.directory)); 2174 this.deserializeAnnotation(_data, _source); 2175 } 2176}; 2177 2178/* End ldt_annotate serializer */ 2179/* ldt_localstorage serializer: Used to store personal annotations in local storage */ 2180 2181if (typeof IriSP.serializers === "undefined") { 2182 IriSP.serializers = {}; 2183} 2184 2185IriSP.serializers.ldt_localstorage = { 2186 serializeAnnotation : function(_data, _source) { 2187 var _annType = _data.getAnnotationType(); 2188 return { 2189 id: _data.id, 2190 begin: _data.begin.milliseconds, 2191 end: _data.end.milliseconds, 2192 content: { 2193 data: (_data.content ? _data.content.data || {} : {}), 2194 description: _data.description, 2195 title: _data.title, 2196 audio: _data.audio 2197 }, 2198 tags: _data.getTagTexts(), 2199 media: _data.getMedia().id, 2200 type_title: _annType.title, 2201 type: ( typeof _annType.dont_send_id !== "undefined" && _annType.dont_send_id ? "" : _annType.id ), 2202 meta: { 2203 created: _data.created,
2204 creator: _data.creator, 2205 modified: _data.modified, 2206 contributor: _data.contributor 2207 } 2208 }; 2209 }, 2210 deserializeAnnotation : function(_anndata, _source) { 2211 var _ann = new IriSP.Model.Annotation(_anndata.id, _source); 2212 _ann.description = _anndata.content.description || ""; 2213 _ann.title = _anndata.content.title || ""; 2214 _ann.creator = _anndata.meta.creator || ""; 2215 _ann.created = new Date(_anndata.meta.created); 2216 _ann.contributor = _anndata.meta.contributor || ""; 2217 _ann.modified = new Date(_anndata.meta.modified); 2218 _ann.setMedia(_anndata.media, _source); 2219 var _anntype = _source.getElement(_anndata.type); 2220 if (!_anntype) { 2221 _anntype = new IriSP.Model.AnnotationType(_anndata.type, _source); 2222 _anntype.title = _anndata.type_title; 2223 _source.getAnnotationTypes().push(_anntype); 2224 } 2225 _ann.setAnnotationType(_anntype.id); 2226 var _tagIds = IriSP._(_anndata.tags).map(function(_title) { 2227 var _tags = _source.getTags(true).searchByTitle(_title, true); 2228 if (_tags.length) { 2229 var _tag = _tags[0]; 2230 } 2231 else { 2232 _tag = new IriSP.Model.Tag(_title.replace(/\W/g,'_'),_source); 2233 _tag.title = _title; 2234 _source.getTags().push(_tag); 2235 } 2236 return _tag.id; 2237 }); 2238 _ann.setTags(_tagIds); 2239 _ann.setBeginEnd(_anndata.begin, _anndata.end); 2240 if (typeof _anndata.content.audio !== "undefined" && _anndata.content.audio.href) { 2241 _ann.audio = _anndata.content.audio; 2242 }; 2243 if (_anndata.content.data) { 2244 _ann.content = { data: _anndata.content.data }; 2245 }; 2246 _source.getAnnotations().push(_ann); 2247 }, 2248 serialize : function(_source) { 2249 var _this = this; 2250 return JSON.stringify(_source.getAnnotations().map(function (a) { return _this.serializeAnnotation(a, _source); })); 2251 }, 2252 deSerialize : function(_data, _source) { 2253 var _this = this; 2254 if (typeof _data == "string") { 2255 _data = JSON.parse(_data); 2256 } 2257 2258 _source.addList('tag', new IriSP.Model.List(_source.directory)); 2259 _source.addList('annotationType', new IriSP.Model.List(_source.directory)); 2260 _source.addList('annotation', new IriSP.Model.List(_source.directory)); 2261 _data.map( function (a) { _this.deserializeAnnotation(a, _source); }); 2262 } 2263}; 2264 2265/* End ldt_localstorage serializer */ 2266/* START segmentapi-serializer.js */ 2267 2268if (typeof IriSP.serializers === "undefined") { 2269 IriSP.serializers = {}; 2270} 2271 2272IriSP.serializers.segmentapi = { 2273 deSerialize : function(_data, _source) { 2274 var _annotationlist = new IriSP.Model.List(_source.directory), 2275 _medialist = new IriSP.Model.List(_source.directory); 2276 _source.addList("media", _medialist); 2277 2278 function deserializeObject(_s) { 2279 var _ann = new IriSP.Model.Annotation(_s.element_id, _source), 2280 _media = _source.getElement(_s.iri_id); 2281 if (!_media) { 2282 _media = new IriSP.Model.Media(_s.iri_id, _source); 2283 _source.getMedias().push(_media); 2284 } 2285 _ann.setMedia(_s.iri_id); 2286 _ann.title = _s.title; 2287 _ann.description = _s['abstract']; 2288 _ann.begin = new IriSP.Model.Time(_s.start_ts); 2289 _ann.end = new IriSP.Model.Time(_s.start_ts + _s.duration); 2290 _ann.keywords = (_s.tags ? _s.tags.split(",") : []); 2291 _ann.project_id = _s.project_id; 2292 _annotationlist.push(_ann); 2293 } 2294 2295 if (typeof _data.objects !== "undefined") { 2296 IriSP._(_data.objects).each(deserializeObject); 2297 } else { 2298 deserializeObject(_data); 2299 } 2300 _source.addList("annotation", _annotationlist); 2301 } 2302}; 2303 2304/* END segmentapi-serializer.js */ 2305/* Start of defaults.js */ 2306 2307IriSP.language = 'en'; 2308 2309IriSP.libFiles = { 2310 defaultDir : "js/libs/", 2311 inDefaultDir : { 2312 underscore : "underscore-min.js", 2313 Mustache : "mustache.js", 2314 jQuery : "jquery.min.js", 2315 jQueryUI : "jquery-ui.min.js", 2316 swfObject : "swfobject.js", 2317 cssjQueryUI : "jquery-ui.css", 2318 popcorn : "popcorn-complete.min.js", 2319 jwplayer : "jwplayer.js", 2320 raphael : "raphael-min.js", 2321 tracemanager : "tracemanager.js", 2322 jwPlayerSWF : "player.swf", 2323 json : "json2.js", 2324 zeroClipboardJs: "ZeroClipboard.js", 2325 zeroClipboardSwf: "ZeroClipboard.swf", 2326 backbone: "backbone.js", 2327 backboneRelational: "backbone-relational.js", 2328 paper: "paper.js", 2329 jqueryMousewheel: "jquery.mousewheel.min.js", 2330 splitter: "jquery.touchsplitter.js", 2331 cssSplitter: "jquery.touchsplitter.css", 2332 renkanPublish: "renkan.js", 2333 processing: "processing-1.3.6.min.js", 2334 recordMicSwf: "record_mic.swf", 2335 mousetrap: "mousetrap.min.js", 2336 mousetrapGlobal: "mousetrap-global-bind.js", 2337 markjs: "jquery.mark.min.js" 2338 }, 2339 locations : { 2340 // use to define locations outside default_dir 2341 }, 2342 cdn : { 2343 jQuery : "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js", 2344 jQueryUI : "http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.22/jquery-ui.min.js", 2345 swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", 2346 cssjQueryUI : "http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.22/themes/ui-lightness/jquery-ui.css", 2347 underscore : "http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js", 2348 Mustache : "http://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.5.0-dev/mustache.min.js", 2349 raphael : "http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js", 2350 json : "http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js", 2351 popcorn: "http://cdn.popcornjs.org/code/dist/popcorn-complete.min.js" 2352 }, 2353 useCdn : false 2354}; 2355 2356IriSP.widgetsDir = 'widgets'; 2357 2358IriSP.widgetsRequirements = { 2359 PopcornPlayer: { 2360 noCss: true, 2361 requires: [ "popcorn" ] 2362 }, 2363 HtmlPlayer: { 2364 noCss: true 2365 }, 2366 JwpPlayer: { 2367 noCss: true, 2368 requires: [ "jwplayer" ] 2369 }, 2370 DailymotionPlayer: { 2371 noCss: true, 2372 requires: [ "swfObject" ] 2373 }, 2374 AdaptivePlayer: { 2375 noCss: true 2376 }, 2377 AutoPlayer: { 2378 noCss: true 2379 }, 2380 AnnotationsList: { 2381 requires: [ "jwplayer" ] 2382 }, 2383 Sparkline: { 2384 noCss: true, 2385 requires: [ "raphael" ] 2386 }, 2387 Arrow: { 2388 noCss: true, 2389 requires: [ "raphael" ] 2390 }, 2391 Mediafragment: { 2392 noCss: true 2393 }, 2394 Trace : { 2395 noCss: true, 2396 requires: [ "tracemanager" ] 2397 }, 2398 Slideshare: { 2399 requires: [ "swfObject" ] 2400 }, 2401 Social: { 2402 requires: [ "zeroClipboardJs" ] 2403 }, 2404 Renkan: { 2405 requires: [ "backbone", "backboneRelational", "paper", "jqueryMousewheel", "renkanPublish" ] 2406 }, 2407 KnowledgeConcierge: { 2408 requires: [ "processing" ] 2409 }, 2410 MultiSegments: { 2411 noCss: true 2412 }, 2413 SlideVideoPlayer: { 2414 requires: [ "jQuery", "jQueryUI", "splitter" ] 2415 }, 2416 Shortcuts: { 2417 requires: [ "mousetrap", "mousetrapGlobal" ] 2418 }, 2419 EnrichedPlan: { 2420 requires: [ "markjs" ] 2421 } 2422}; 2423 2424IriSP.guiDefaults = { 2425 width : "100%", 2426 container : 'LdtPlayer', 2427 spacer_div_height : 0, 2428 widgets: [] 2429}; 2430 2431/* End of defaults.js */ 2432/* widgets-container/metadataplayer.js - initialization and configuration of the widgets 2433*/ 2434 2435/* The Metadataplayer Object, single point of entry, replaces IriSP.init_player */ 2436 2437(function(ns) { 2438 2439var formerJQuery, formerUnderscore, former$; 2440 2441var Metadataplayer = ns.Metadataplayer = function(config) { 2442 ns.log("IriSP.Metadataplayer constructor"); 2443 for (var key in ns.guiDefaults) { 2444 if (ns.guiDefaults.hasOwnProperty(key) && !config.hasOwnProperty(key)) { 2445 config[key] = ns.guiDefaults[key] 2446 } 2447 } 2448 var _container = document.getElementById(config.container); 2449 _container.innerHTML = '<h3 class="Ldt-Loader">Loading... Chargement...</h3>'; 2450 this.sourceManager = new ns.Model.Directory(); 2451 this.config = config; 2452 this.__events = {}; 2453 this.loadLibs(); 2454}; 2455 2456Metadataplayer.prototype.toString = function() { 2457 return 'Metadataplayer in #' + this.config.container; 2458}; 2459 2460Metadataplayer.prototype.on = function(_event, _callback) { 2461 if (typeof this.__events[_event] === "undefined") { 2462 this.__events[_event] = []; 2463 } 2464 this.__events[_event].push(_callback); 2465}; 2466 2467Metadataplayer.prototype.trigger = function(_event, _data) { 2468 var _element = this; 2469 ns._(this.__events[_event]).each(function(_callback) { 2470 _callback.call(_element, _data); 2471 }); 2472}; 2473 2474Metadataplayer.prototype.loadLibs = function() { 2475 ns.log("IriSP.Metadataplayer.prototype.loadLibs"); 2476 var $L = $LAB 2477 .queueScript(ns.getLib("Mustache")); 2478 formerJQuery = !!window.jQuery; 2479 former$ = !!window.$; 2480 formerUnderscore = !!window._; 2481 2482 if (typeof ns.jQuery === "undefined") { 2483 $L.queueScript(ns.getLib("jQuery")); 2484 } 2485 2486 if (typeof ns._ === "undefined") { 2487 $L.queueScript(ns.getLib("underscore")); 2488 } 2489 2490 if (typeof window.JSON == "undefined") { 2491 $L.queueScript(ns.getLib("json")); 2492 } 2493 $L.queueWait().queueScript(ns.getLib("jQueryUI")).queueWait(); 2494 2495 /* widget specific requirements */ 2496 for(var _i = 0; _i < this.config.widgets.length; _i++) { 2497 var _t = this.config.widgets[_i].type; 2498 if (typeof ns.widgetsRequirements[_t] !== "undefined" && typeof ns.widgetsRequirements[_t].requires !== "undefined" ) { 2499 for (var _j = 0; _j < ns.widgetsRequirements[_t].requires.length; _j++) { 2500 $L.queueScript(ns.getLib(ns.widgetsRequirements[_t].requires[_j])); 2501 } 2502 } 2503 } 2504 2505 var _this = this; 2506 $L.queueWait(function() { 2507 _this.onLibsLoaded(); 2508 }); 2509 2510 $L.runQueue(); 2511}; 2512 2513Metadataplayer.prototype.onLibsLoaded = function() { 2514 ns.log("IriSP.Metadataplayer.prototype.onLibsLoaded"); 2515 2516 if (typeof ns.jQuery === "undefined" && typeof window.jQuery !== "undefined") { 2517 ns.jQuery = window.jQuery; 2518 if (former$ || formerJQuery) { 2519 window.jQuery.noConflict(formerJQuery); 2520 } 2521 } 2522 if (typeof ns._ === "undefined" && typeof window._ !== "undefined") { 2523 ns._ = window._; 2524 if (formerUnderscore) { 2525 _.noConflict(); 2526 } 2527 } 2528 2529 ns.loadCss(ns.getLib("cssjQueryUI")); 2530 ns.loadCss(this.config.css); 2531 2532 this.$ = ns.jQuery('#' + this.config.container); 2533 this.$.css({ 2534 "width": this.config.width, 2535 "clear": "both" 2536 }); 2537 if (typeof this.config.height !== "undefined") { 2538 this.$.css("height", this.config.height); 2539 } 2540 2541 this.widgets = []; 2542 var _this = this; 2543 ns._(this.config.widgets).each(function(widgetconf, key) { 2544 _this.widgets.push(null); 2545 _this.loadWidget(widgetconf, function(widget) { 2546 _this.widgets[key] = widget; 2547 if (widget.isLoaded()) { 2548 _this.trigger("widget-loaded"); 2549 } 2550 }); 2551 }); 2552 this.$.find('.Ldt-Loader').detach(); 2553 2554 this.widgetsLoaded = false;
2555 2556 this.on("widget-loaded", function() { 2557 if (_this.widgetsLoaded) { 2558 return; 2559 } 2560 var isloaded = !ns._(_this.widgets).any(function(w) { 2561 return !(w && w.isLoaded()); 2562 }); 2563 if (isloaded) { 2564 _this.widgetsLoaded = true; 2565 _this.trigger("widgets-loaded"); 2566 } 2567 }); 2568}; 2569 2570Metadataplayer.prototype.loadLocalAnnotations = function(localsourceidentifier) { 2571 if (this.localSource === undefined) 2572 this.localSource = this.sourceManager.newLocalSource({serializer: IriSP.serializers['ldt_localstorage']}); 2573 // Load current local annotations 2574 if (localsourceidentifier) { 2575 // Allow to override localsourceidentifier when necessary (usually at init time) 2576 this.localSource.identifier = localsourceidentifier; 2577 } 2578 this.localSource.deSerialize(window.localStorage[this.localSource.identifier] || "[]"); 2579 return this.localSource; 2580}; 2581 2582Metadataplayer.prototype.saveLocalAnnotations = function() { 2583 // Save annotations back to localstorage 2584 window.localStorage[this.localSource.identifier] = this.localSource.serialize(); 2585 // Merge modifications into widget source 2586 // this.source.merge(this.localSource); 2587}; 2588 2589Metadataplayer.prototype.addLocalAnnotation = function(a) { 2590 this.loadLocalAnnotations(); 2591 this.localSource.getAnnotations().push(a); 2592 this.saveLocalAnnotations(); 2593}; 2594 2595Metadataplayer.prototype.deleteLocalAnnotation = function(ident) { 2596 this.localSource.getAnnotations().removeId(ident, true); 2597 this.saveLocalAnnotations(); 2598}; 2599 2600Metadataplayer.prototype.getLocalAnnotation = function (ident) { 2601 this.loadLocalAnnotations(); 2602 // We cannot use .getElement since it fetches 2603 // elements from the global Directory 2604 return IriSP._.first(IriSP._.filter(this.localSource.getAnnotations(), function (a) { return a.id == ident; })); 2605}; 2606 2607Metadataplayer.prototype.loadMetadata = function(_metadataInfo) { 2608 if (_metadataInfo.elementType === "source") { 2609 return _metadataInfo; 2610 } 2611 if (typeof _metadataInfo.serializer === "undefined" && typeof _metadataInfo.format !== "undefined") { 2612 _metadataInfo.serializer = ns.serializers[_metadataInfo.format]; 2613 } 2614 if (typeof _metadataInfo.url !== "undefined" && typeof _metadataInfo.serializer !== "undefined") { 2615 return this.sourceManager.remoteSource(_metadataInfo); 2616 } else { 2617 return this.sourceManager.newLocalSource(_metadataInfo); 2618 } 2619}; 2620 2621Metadataplayer.prototype.loadWidget = function(_widgetConfig, _callback) { 2622 /* Creating containers if needed */ 2623 if (typeof _widgetConfig.container === "undefined") { 2624 var _divs = this.layoutDivs(_widgetConfig.type); 2625 _widgetConfig.container = _divs[0]; 2626 } 2627 2628 var _this = this; 2629 2630 if (typeof ns.Widgets[_widgetConfig.type] !== "undefined") { 2631 ns._.defer(function() { 2632 _callback(new ns.Widgets[_widgetConfig.type](_this, _widgetConfig)); 2633 }); 2634 } else { 2635 /* Loading Widget CSS */ 2636 if (typeof ns.widgetsRequirements[_widgetConfig.type] === "undefined" || typeof ns.widgetsRequirements[_widgetConfig.type].noCss === "undefined" || !ns.widgetsRequirements[_widgetConfig.type].noCss) { 2637 ns.loadCss(ns.widgetsDir + '/' + _widgetConfig.type + '.css'); 2638 } 2639 /* Loading Widget JS */ 2640 $LAB.script(ns.widgetsDir + '/' + _widgetConfig.type + '.js').wait(function() { 2641 _callback(new ns.Widgets[_widgetConfig.type](_this, _widgetConfig)); 2642 }); 2643 } 2644}; 2645 2646/** create a subdiv with an unique id, and a spacer div as well. 2647 @param widgetName the name of the widget. 2648 @return an array of the form [createdivId, spacerdivId]. 2649*/ 2650Metadataplayer.prototype.layoutDivs = function(_name, _height) { 2651 if (typeof(_name) === "undefined") { 2652 _name = ""; 2653 } 2654 var newDiv = ns._.uniqueId(this.config.container + "_widget_" + _name + "_"), 2655 spacerDiv = ns._.uniqueId("LdtPlayer_spacer_"), 2656 divHtml = ns.jQuery('<div>') 2657 .attr("id",newDiv) 2658 .css({ 2659 width: this.config.width + "px", 2660 position: "relative", 2661 clear: "both" 2662 }), 2663 spacerHtml = ns.jQuery('<div>') 2664 .attr("id",spacerDiv) 2665 .css({ 2666 width: this.config.width + "px", 2667 height: this.config.spacer_div_height + "px", 2668 position: "relative", 2669 clear: "both" 2670 }); 2671 if (typeof _height !== "undefined") { 2672 divHtml.css("height", _height); 2673 } 2674 2675 this.$.append(divHtml); 2676 this.$.append(spacerHtml); 2677 2678 return [newDiv, spacerDiv]; 2679}; 2680 2681})(IriSP); 2682 2683/* End of widgets-container/metadataplayer.js */ 2684/* widgetsDefinition of an ancestor for the Widget classes */ 2685 2686if (typeof IriSP.Widgets === "undefined") { 2687 IriSP.Widgets = {}; 2688} 2689 2690/** 2691 * @class IriSP.Widget is an "abstract" class. It's mostly used to define some properties common to every widget. 2692 * 2693 * Note that widget constructors are never called directly by the user. Instead, the widgets are instantiated by functions 2694 * defined in init.js 2695 * 2696 * @constructor 2697 * @param player - a reference to the player widget 2698 * @param config - configuration options for the widget 2699 */ 2700 2701 2702IriSP.Widgets.Widget = function (player, config) { 2703 2704 if (typeof player === "undefined") { 2705 /* Probably an abstract call of the class when 2706 * individual widgets set their prototype */ 2707 return; 2708 } 2709 2710 this.__subwidgets = []; 2711 2712 /* Setting all the configuration options */ 2713 var _type = config.type || "(unknown)", 2714 _config = IriSP._.defaults({}, config, (player && player.config ? player.config.default_options : {}), this.defaults), 2715 _this = this; 2716 2717 IriSP._(_config).forEach(function (_value, _key) { 2718 _this[_key] = _value; 2719 }); 2720 2721 this.$ = IriSP.jQuery('#' + this.container); 2722 2723 if (typeof this.width === "undefined") { 2724 this.width = this.$.width(); 2725 } else { 2726 this.$.css("width", this.width); 2727 } 2728 2729 if (typeof this.height !== "undefined") { 2730 this.$.css("height", this.height); 2731 } 2732 2733 /* Setting this.player at the end in case it's been overriden 2734 * by a configuration option of the same name :-( 2735 */ 2736 this.player = player || new IriSP.FakeClass(["on","trigger","off","loadWidget","loadMetadata"]); 2737 2738 /* Adding classes and html attributes */ 2739 this.$.addClass("Ldt-TraceMe Ldt-Widget").attr("widget-type", _type); 2740 2741 this.l10n = ( 2742 typeof this.messages[IriSP.language] !== "undefined" 2743 ? this.messages[IriSP.language] 2744 : ( 2745 IriSP.language.length > 2 && typeof this.messages[IriSP.language.substr(0, 2)] !== "undefined" 2746 ? this.messages[IriSP.language.substr(0, 2)] 2747 : this.messages["en"] 2748 ) 2749 ); 2750 2751 /* Loading Metadata if required */ 2752 2753 function onsourceloaded() { 2754 if (_this.localannotations) { 2755 _this.localsource = player.loadLocalAnnotations(_this.localannotations); 2756 _this.source.merge(_this.localsource); 2757 } 2758 if (_this.media_id) { 2759 _this.media = this.getElement(_this.media_id); 2760 } else { 2761 var _mediaopts = { 2762 is_mashup: _this.is_mashup || false 2763 }; 2764 _this.media = _this.source.getCurrentMedia(_mediaopts); 2765 } 2766 if (_this.pre_draw_callback) { 2767 IriSP.jQuery.when(_this.pre_draw_callback()).done(_this.draw()); 2768 } else { 2769 _this.draw(); 2770 } 2771 _this.player.trigger("widget-loaded"); 2772 } 2773 2774 if (this.metadata) { 2775 /* Getting metadata */ 2776 this.source = player.loadMetadata(this.metadata); 2777 /* Call draw when loaded */ 2778 this.source.onLoad(onsourceloaded); 2779 } else { 2780 if (this.source) { 2781 onsourceloaded(); 2782 } 2783 } 2784 2785 2786}; 2787 2788IriSP.Widgets.Widget.prototype.defaults = {}; 2789 2790IriSP.Widgets.Widget.prototype.template = ''; 2791 2792IriSP.Widgets.Widget.prototype.messages = {"en":{}}; 2793 2794IriSP.Widgets.Widget.prototype.toString = function () { 2795 return "Widget " + this.type; 2796}; 2797 2798IriSP.Widgets.Widget.prototype.templateToHtml = function (_template) { 2799 return Mustache.to_html(_template, this); 2800}; 2801 2802IriSP.Widgets.Widget.prototype.renderTemplate = function () { 2803 this.$.append(this.templateToHtml(this.template)); 2804}; 2805 2806IriSP.Widgets.Widget.prototype.functionWrapper = function (_name) { 2807 var _this = this, 2808 _function = this[_name]; 2809 if (typeof _function !== "undefined") { 2810 return function () { 2811 return _function.apply(_this, Array.prototype.slice.call(arguments, 0)); 2812 }; 2813 } else { 2814 console.log("Error, Unknown function IriSP.Widgets." + this.type + "." + _name); 2815 } 2816}; 2817 2818IriSP.Widgets.Widget.prototype.getFunctionOrName = function (_functionOrName) { 2819 switch (typeof _functionOrName) { 2820 case "function": 2821 return _functionOrName; 2822 case "string": 2823 return this.functionWrapper(_functionOrName); 2824 default: 2825 return undefined; 2826 } 2827}; 2828 2829IriSP.Widgets.Widget.prototype.onMdpEvent = function (_eventName, _functionOrName) { 2830 this.player.on(_eventName, this.getFunctionOrName(_functionOrName)); 2831}; 2832 2833IriSP.Widgets.Widget.prototype.onMediaEvent = function (_eventName, _functionOrName) { 2834 this.media.on(_eventName, this.getFunctionOrName(_functionOrName)); 2835}; 2836 2837IriSP.Widgets.Widget.prototype.getWidgetAnnotations = function () { 2838 var result = null; 2839 if (typeof this.annotation_type === "undefined") { 2840 result = this.media.getAnnotations(); 2841 } else if (this.annotation_type.elementType === "annotationType") { 2842 result = this.annotation_type.getAnnotations(); 2843 } else { 2844 result = this.media.getAnnotationsByTypeTitle(this.annotation_type); 2845 } 2846 if (typeof this.annotation_filter !== "undefined") { 2847 return this.annotation_filter(result); 2848 } else { 2849 return result; 2850 } 2851}; 2852 2853IriSP.Widgets.Widget.prototype.getWidgetAnnotationsAtTime = function () { 2854 var _time = this.media.getCurrentTime(); 2855 return this.getWidgetAnnotations().filter(function (_annotation) { 2856 return _annotation.begin <= _time && _annotation.end > _time; 2857 }); 2858}; 2859 2860IriSP.Widgets.Widget.prototype.isLoaded = function () { 2861 var isloaded = !IriSP._(this.__subwidgets).any(function (w) { 2862 return !(w && w.isLoaded()); 2863 }); 2864 return isloaded; 2865}; 2866 2867IriSP.Widgets.Widget.prototype.insertSubwidget = function (_selector, _widgetoptions, _propname) { 2868 var _id = _selector.attr("id"), 2869 _this = this, 2870 _type = _widgetoptions.type, 2871 $L = $LAB, 2872 key = this.__subwidgets.length; 2873 this.__subwidgets.push(null); 2874 if (typeof _id == "undefined") { 2875 _id = IriSP._.uniqueId(this.container + '_sub_widget_' + _widgetoptions.type); 2876 _selector.attr("id", _id); 2877 } 2878 _widgetoptions.container = _id;
2879 if (typeof IriSP.widgetsRequirements[_type] !== "undefined" && typeof IriSP.widgetsRequirements[_type].requires !== "undefined") { 2880 for (var _j = 0; _j < IriSP.widgetsRequirements[_type].requires.length; _j++) { 2881 $L.script(IriSP.getLib(IriSP.widgetsRequirements[_type].requires[_j])); 2882 } 2883 } 2884 $L.wait(function () { 2885 _this.player.loadWidget(_widgetoptions, function (_widget) { 2886 if (_propname) { 2887 _this[_propname] = _widget; 2888 } 2889 _this.__subwidgets[key] = _widget; 2890 }); 2891 }); 2892}; 2893 2894/* 2895 * Position the player to the next/previous annotations based on current player position 2896 * 2897 * Parameter: offset: -1 for previous annotation, +1 for next annotation 2898 */ 2899IriSP.Widgets.Widget.prototype.navigate = function (offset) { 2900 // offset is normally either -1 (previous slide) or +1 (next slide) 2901 var _this = this; 2902 var currentTime = _this.media.getCurrentTime(); 2903 var annotations = _this.getWidgetAnnotations().sortBy(function (_annotation) { 2904 return _annotation.begin; 2905 }); 2906 for (var i = 0; i < annotations.length; i++) { 2907 if (annotations[i].begin <= currentTime && currentTime < annotations[i].end) { 2908 // Found a current annotation - clamp i+offset value to [0, length - 1] 2909 i = Math.min(annotations.length - 1, Math.max(0, i + offset)); 2910 _this.media.setCurrentTime(annotations[i].begin); 2911 break; 2912 } 2913 }; 2914}; 2915 2916/* 2917 * Propose an export of the widget's annotations 2918 * 2919 * Parameter: a list of annotations. If not specified, the widget's annotations will be exported. 2920 */ 2921IriSP.Widgets.Widget.prototype.exportAnnotations = function (annotations) { 2922 var widget = this; 2923 if (annotations === undefined) { 2924 annotations = this.getWidgetAnnotations(); 2925 } 2926 var $ = IriSP.jQuery; 2927 2928 // FIXME: this should belong to a proper serialize/deserialize component? 2929 var content = Mustache.to_html("[video:{{url}}]\n", {url: widget.media.url}) + annotations.map(function (a) { return Mustache.to_html("[{{ a.begin }}]{{ a.title }} {{ a.description }}[{{ a.end }}]", { a: a }); }).join("\n"); 2930 2931 var el = $("<pre>") 2932 .addClass("exportContainer") 2933 .text(content) 2934 .dialog({ 2935 title: "Annotation export", 2936 open: function (event, ui) { 2937 // Select text 2938 var range; 2939 if (document.selection) { 2940 range = document.body.createTextRange(); 2941 range.moveToElementText(this[0]); 2942 range.select(); 2943 } else if (window.getSelection) { 2944 range = document.createRange(); 2945 range.selectNode(this[0]); 2946 window.getSelection().addRange(range); 2947 } 2948 }, 2949 autoOpen: true, 2950 width: '80%', 2951 minHeight: '400', 2952 height: 400, 2953 buttons: [ { text: "Close", click: function () { $(this).dialog("close"); } }, 2954 { text: "Download", click: function () { 2955 a = document.createElement('a'); 2956 a.setAttribute('href', 'data:text/plain;base64,' + btoa(content)); 2957 a.setAttribute('download', 'Annotations - ' + widget.media.title.replace(/[^ \w]/g, '') + '.txt'); 2958 a.click(); 2959 } } ] 2960 }); 2961}; 2962 2963/** 2964 * This method responsible of drawing a widget on screen. 2965 */ 2966IriSP.Widgets.Widget.prototype.draw = function () { 2967 /* implemented by "sub-classes" */ 2968};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.