diff -r 46e21d060650 -r fe008e95a716 sbin/res/jsdoc/LdtPlayer-release.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/res/jsdoc/LdtPlayer-release.js Fri Dec 23 11:38:47 2011 +0100 @@ -0,0 +1,3541 @@ +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +/*! LAB.js (LABjs :: Loading And Blocking JavaScript) + v2.0.3 (c) Kyle Simpson + MIT License +*/ + +(function(global){ + var _$LAB = global.$LAB, + + // constants for the valid keys of the options object + _UseLocalXHR = "UseLocalXHR", + _AlwaysPreserveOrder = "AlwaysPreserveOrder", + _AllowDuplicates = "AllowDuplicates", + _CacheBust = "CacheBust", + /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/ + _BasePath = "BasePath", + + // stateless variables used across all $LAB instances + root_page = /^[^?#]*\//.exec(location.href)[0], + root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0], + append_to = document.head || document.getElementsByTagName("head"), + + // inferences... ick, but still necessary + opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style), + +/*!START_DEBUG*/ + // console.log() and console.error() wrappers + log_msg = function(){}, + log_error = log_msg, +/*!END_DEBUG*/ + + // feature sniffs (yay!) + test_script_elem = document.createElement("script"), + explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29 + real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append? + script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order + + // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers) + xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko + ; + +/*!START_DEBUG*/ + // define console wrapper functions if applicable + if (global.console && global.console.log) { + if (!global.console.error) global.console.error = global.console.log; + log_msg = function(msg) { global.console.log(msg); }; + log_error = function(msg,err) { global.console.error(msg,err); }; + } +/*!END_DEBUG*/ + + // test for function + function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; } + + // test for array + function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; } + + // make script URL absolute/canonical + function canonical_uri(src,base_path) { + var absolute_regex = /^\w+\:\/\//; + + // is `src` is protocol-relative (begins with // or ///), prepend protocol + if (/^\/\/\/?/.test(src)) { + src = location.protocol + src; + } + // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /) + else if (!absolute_regex.test(src) && src.charAt(0) != "/") { + // prepend `base_path`, if any + src = (base_path || "") + src; + } + // make sure to return `src` as absolute + return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src); + } + + // merge `source` into `target` + function merge_objs(source,target) { + for (var k in source) { if (source.hasOwnProperty(k)) { + target[k] = source[k]; // TODO: does this need to be recursive for our purposes? + }} + return target; + } + + // does the chain group have any ready-to-execute scripts? + function check_chain_group_scripts_ready(chain_group) { + var any_scripts_ready = false; + for (var i=0; i 0) { + for (var i=0; i=0;) { + val = queue.shift(); + $L = $L[val.type].apply(null,val.args); + } + return $L; + }, + + // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB + noConflict:function(){ + global.$LAB = _$LAB; + return instanceAPI; + }, + + // create another clean instance of $LAB + sandbox:function(){ + return create_sandbox(); + } + }; + + return instanceAPI; + } + + // create the main instance of $LAB + global.$LAB = create_sandbox(); + + + /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?). + + The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does + proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked + document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready. + For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or + fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs. + */ + (function(addEvent,domLoaded,handler){ + if (document.readyState == null && document[addEvent]){ + document.readyState = "loading"; + document[addEvent](domLoaded,handler = function(){ + document.removeEventListener(domLoaded,handler,false); + document.readyState = "complete"; + },false); + } + })("addEventListener","DOMContentLoaded"); + +})(this);/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function() { + var Renderer = function() {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function(template, context, partials, in_recursion) { + // reset buffer & set context + if(!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if(!this.includes("", template)) { + if(in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + template = this.render_pragmas(template); + var html = this.render_section(template, context, partials); + if(in_recursion) { + return this.render_tags(html, context, partials, in_recursion); + } + + this.render_tags(html, context, partials, in_recursion); + }, + + /* + Sends parsed lines + */ + send: function(line) { + if(line !== "") { + this.buffer.push(line); + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function(template) { + // no pragmas + if(!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + + this.ctag, "g"); + return template.replace(regex, function(match, pragma, options) { + if(!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if(options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function(name, context, partials) { + name = this.trim(name); + if(!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if(typeof(context[name]) != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function(template, context, partials) { + if(!this.includes("#", template) && !this.includes("^", template)) { + return template; + } + + var that = this; + // CSW - Added "+?" so it finds the tighest bound, not the widest + var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag + + "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag + + "\\s*", "mg"); + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function(match, type, name, content) { + var value = that.find(name, context); + if(type == "^") { // inverted section + if(!value || that.is_array(value) && value.length === 0) { + // false or empty list, render it + return that.render(content, context, partials, true); + } else { + return ""; + } + } else if(type == "#") { // normal section + if(that.is_array(value)) { // Enumerable, Let's loop! + return that.map(value, function(row) { + return that.render(content, that.create_context(row), + partials, true); + }).join(""); + } else if(that.is_object(value)) { // Object, Use it as subcontext! + return that.render(content, that.create_context(value), + partials, true); + } else if(typeof value === "function") { + // higher order section + return value.call(context, content, function(text) { + return that.render(text, context, partials, true); + }); + } else if(value) { // boolean section + return that.render(content, context, partials, true); + } else { + return ""; + } + } + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function(template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function() { + return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + + that.ctag + "+", "g"); + }; + + var regex = new_regex(); + var tag_replace_callback = function(match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + return that.find(name, context); + default: // escape the value + return that.escape(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if(!in_recursion) { + this.send(lines[i]); + } + } + + if(in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function(delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function(text) { + // thank you Simon Willison + if(!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function(name, context) { + name = this.trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + if(is_kinda_truthy(context[name])) { + value = context[name]; + } else if(is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + + if(typeof value === "function") { + return value.apply(context); + } + if(value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + // Utility methods + + /* includes tag */ + includes: function(needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + /* + Does away with nasty characters + */ + escape: function(s) { + s = String(s === null ? "" : s); + return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) { + switch(s) { + case "&": return "&"; + case "\\": return "\\\\"; + case '"': return '"'; + case "'": return '''; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); + }, + + // by @langalex, support for arrays of strings + create_context: function(_context) { + if(this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if(this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function(a) { + return a && typeof a == "object"; + }, + + is_array: function(a) { + return Object.prototype.toString.call(a) === '[object Array]'; + }, + + /* + Gets rid of leading and trailing whitespace + */ + trim: function(s) { + return s.replace(/^\s*|\s*$/g, ""); + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function(array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + } + }; + + return({ + name: "mustache.js", + version: "0.3.1-dev", + + /* + Turns a template and view into HTML + */ + to_html: function(template, view, partials, send_fun) { + var renderer = new Renderer(); + if(send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view, partials); + if(!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +// Underscore.js 1.2.3 +// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c, +h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.concat,H=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&& +define.amd?define("underscore",function(){return b}):s._=b;b.VERSION="1.2.3";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g, +c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c, +b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});return e};var D=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a, +d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex= +function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after= +function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a=== +Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)== +"[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){J(c, +b[c]=a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g, +"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b, +a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this); +/* main file */ + +if ( window.IriSP === undefined && window.__IriSP === undefined ) { + var IriSP = {}; + var __IriSP = IriSP; /* for backward compatibility */ +} + +IriSP.loadLibs = function( libs, config, metadata_url, callback ) { + // Localize jQuery variable + IriSP.jQuery = null; + var $L = $LAB.script(libs.jQuery).script(libs.swfObject) + .script(libs.jQueryUI) + + if (config.player.type === "jwplayer") { + // load our popcorn.js lookalike + $L = $L.script(libs.jwplayer); + } else { + // load the real popcorn + $L = $L.script(libs.popcorn).script(libs["popcorn.code"]); + if (config.player.type === "youtube") { + $L = $L.script(libs["popcorn.youtube"]); + } + if (config.player.type === "vimeo") + $L = $L.script(libs["popcorn.vimeo"]); + + /* do nothing for html5 */ + } + + /* widget specific requirements */ + for (var idx in config.gui.widgets) { + if (config.gui.widgets[idx].type === "PolemicWidget") { + $L.script(libs.raphael); + } + } + + // same for modules + /* + for (var idx in config.modules) { + if (config.modules[idx].type === "PolemicWidget") + $L.script(libs.raphaelJs); + } + */ + + $L.wait(function() { + IriSP.jQuery = window.jQuery.noConflict( true ); + IriSP._ = window._.noConflict(); + IriSP.underscore = IriSP._; + + var css_link_jquery = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: libs.cssjQueryUI, + 'class': "dynamic_css" + } ); + var css_link_custom = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: config.gui.css, + 'class': "dynamic_css" + } ); + + css_link_jquery.appendTo('head'); + css_link_custom.appendTo('head'); + + IriSP.setupDataLoader(); + IriSP.__dataloader.get(metadata_url, + function(data) { + /* save the data so that we could re-use it to + configure the video + */ + IriSP.__jsonMetadata = data; + callback.call(window) }); + }); +}; +IriSP.annotation_template = "{{! template for an annotation displayed in a segmentWidget }}
"; +IriSP.annotationWidget_template = "{{! template for the annotation widget }}
share on facebook share on twitter share on google+
"; +IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}
 
Chargement...
"; +IriSP.arrowWidget_template = "
"; +IriSP.overlay_marker_template = "{{! the template for the small bars which is z-indexed over our segment widget }}
"; +IriSP.player_template = "{{! template for the radio player }}
/
"; +IriSP.search_template = "{{! template for the search container }}
"; +IriSP.share_template = "{{! social network sharing template }} "; +IriSP.sliderWidget_template = "{{! template for the slider widget - it's composed of two divs we one overlayed on top of the other }}
"; +IriSP.tooltip_template = "{{! template used by the jquery ui tooltip }}
{{title}}
{{begin}} : {{end}}
{{description}}
"; +IriSP.tooltipWidget_template = "{{! template for the tooltip widget }}
"; +IriSP.tweetWidget_template = "{{! template for the tweet widget }}";/* wrapper that simulates popcorn.js because + popcorn is a bit unstable at the time */ + +IriSP.PopcornReplacement = { + msgPump : {} /* used by jquery to receive and send messages */ +}; + +IriSP.PopcornReplacement.media = { + "paused": true, + "muted": false +}; + +IriSP.PopcornReplacement.listen = function(msg, callback) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).bind(msg, function(event, rest) { callback(rest); }); + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + IriSP.PopcornReplacement.msgPump[msg] = []; + + IriSP.PopcornReplacement.msgPump[msg].push(callback); +}; + +IriSP.PopcornReplacement.trigger = function(msg, params) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).trigger(msg, params); + + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + return; + + var d = IriSP.PopcornReplacement.msgPump[msg]; + for(var entry in d) { + d[entry].call(window, params); + } + +}; + +IriSP.PopcornReplacement.guid = function(prefix) { + var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); + + return prefix + str; +}; + +IriSP.PopcornReplacement.__initApi = function() { + IriSP.PopcornReplacement.trigger("loadedmetadata"); // we've done more than loading metadata of course, + // but popcorn doesn't need to know more. + IriSP.PopcornReplacement.media.muted = jwplayer(IriSP.PopcornReplacement._container).getMute(); +}; + +IriSP.PopcornReplacement.jwplayer = function(container, options) { + IriSP.PopcornReplacement._container = container.slice(1); //eschew the '#' + options.events = { + onReady: IriSP.PopcornReplacement.__initApi, + onTime: IriSP.PopcornReplacement.__timeHandler, + onPlay: IriSP.PopcornReplacement.__playHandler, + onPause: IriSP.PopcornReplacement.__pauseHandler, + onSeek: IriSP.PopcornReplacement.__seekHandler + } + + jwplayer(IriSP.PopcornReplacement._container).setup(options); + IriSP.PopcornReplacement.media.duration = options.duration; + return IriSP.PopcornReplacement; +}; + +IriSP.PopcornReplacement.currentTime = function(time) { + if (typeof(time) === "undefined") { + return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + } else { + var currentTime = +time; + jwplayer( IriSP.PopcornReplacement._container ).seek( currentTime ); + IriSP.PopcornReplacement.trigger("seeked"); + return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + } +}; + +IriSP.PopcornReplacement.play = function() { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +// IriSP.PopcornReplacement.trigger("playing"); + jwplayer( IriSP.PopcornReplacement._container ).play(); +}; + +IriSP.PopcornReplacement.pause = function() { + if ( !IriSP.PopcornReplacement.media.paused ) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger( "pause" ); + jwplayer( IriSP.PopcornReplacement._container ).pause(); + } +}; + +IriSP.PopcornReplacement.muted = function(val) { + if (typeof(val) !== "undefined") { + + if (jwplayer(IriSP.PopcornReplacement._container).getMute() !== val) { + if (val) { + jwplayer(IriSP.PopcornReplacement._container).setMute(true); + IriSP.PopcornReplacement.media.muted = true; + } else { + jwplayer( IriSP.PopcornReplacement._container ).setMute(false); + IriSP.PopcornReplacement.media.muted = false; + } + + IriSP.PopcornReplacement.trigger( "volumechange" ); + } + + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } else { + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } +}; + +IriSP.PopcornReplacement.mute = IriSP.PopcornReplacement.muted; + +IriSP.PopcornReplacement.__codes = []; +IriSP.PopcornReplacement.code = function(options) { + IriSP.PopcornReplacement.__codes.push(options); + return IriSP.PopcornReplacement; +}; + +IriSP.PopcornReplacement.__runCode = function() { + var currentTime = jwplayer(IriSP.PopcornReplacement._container).getPosition(); + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + if (currentTime == c.start) { + c.onStart(); + } + + if (currentTime == c.end) { + c.onEnd(); + } + + } +}; + +/* called everytime the player updates itself + (onTime event) + */ + +IriSP.PopcornReplacement.__timeHandler = function(event) { + var pos = event.position; + + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (pos >= c.start && pos < c.end && + pos - 0.1 <= c.start) { + c.onStart(); + } + + if (pos > c.start && pos > c.end && + pos - 0.1 <= c.end) { + console.log("eonedn"); + c.onEnd(); + } + + } + + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + +IriSP.PopcornReplacement.__seekHandler = function(event) { + var i = 0; + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (event.position >= c.start && event.position < c.end) { + c.onEnd(); + } + } + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (typeof(event.offset) === "undefined") + event.offset = 0; + + if (event.offset >= c.start && event.offset < c.end) { + c.onStart(); + } + + } + + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + + +IriSP.PopcornReplacement.__playHandler = function(event) { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +}; + +IriSP.PopcornReplacement.__pauseHandler = function(event) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger("pause"); +}; + +IriSP.PopcornReplacement.roundTime = function() { + var currentTime = IriSP.PopcornReplacement.currentTime(); + return Math.round(currentTime); +}; +/* utils.js - various utils that don't belong anywhere else */ + +/* trace function, for debugging */ + +IriSP.traceNum = 0; +IriSP.trace = function( msg, value ) { +/* + if( IriSP.config.gui.debug === true ) { + IriSP.traceNum += 1; + IriSP.jQuery( "
"+IriSP.traceNum+" - "+msg+" : "+value+"
" ).appendTo( "#Ldt-output" ); + } +*/ +}; + +/* used in callbacks - because in callbacks we lose "this", + we need to have a special function which wraps "this" in + a closure. This way, the +*/ +IriSP.wrap = function (obj, fn) { + return function() { + var args = Array.prototype.slice.call(arguments, 0); + return fn.apply(obj, args); + } +} + +/* convert a time to a percentage in the media */ +IriSP.timeToPourcent = function(time, timetotal){ + var time = Math.abs(time); + var timetotal = Math.abs(timetotal); + + return Math.floor((time/timetotal) * 100); +}; + +IriSP.padWithZeros = function(num) { + if (Math.abs(num) < 10) { + return "0" + num.toString(); + } else { + return num.toString(); + } +}; +/* convert a number of seconds to a tuple of the form + [hours, minutes, seconds] +*/ +IriSP.secondsToTime = function(secs) { + var hours = Math.abs(parseInt( secs / 3600 ) % 24); + var minutes = Math.abs(parseInt( secs / 60 ) % 60); + var seconds = parseFloat(Math.abs(secs % 60).toFixed(0)); + + var toString_fn = function() { + var ret = ""; + if (hours > 0) + ret = IriSP.padWithZeros(this.hours) + ":"; + ret += IriSP.padWithZeros(this.minutes) + ":" + IriSP.padWithZeros(this.seconds); + + return ret; + } + return {"hours" : hours, "minutes" : minutes, "seconds" : seconds, toString: toString_fn}; +}; + +IriSP.secondsToString + +/* format a tweet - replaces @name by a link to the profile, #hashtag, etc. */ +IriSP.formatTweet = function(tweet) { + /* + an array of arrays which hold a regexp and its replacement. + */ + var regExps = [ + /* copied from http://codegolf.stackexchange.com/questions/464/shortest-url-regex-match-in-javascript/480#480 */ + [/((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/gi, "$1"], + [/@(\w+)/gi, "@$1"], // matches a @handle + [/#(\w+)/gi, "#$1"],// matches a hashtag + [/(\+\+)/gi, "$1"], + [/(--)/gi, "$1"], + [/(==)/gi, "$1"], + [/(\?\?)/gi, "$1"] + ]; + + var i = 0; + for(i = 0; i < regExps.length; i++) { + tweet = tweet.replace(regExps[i][0], regExps[i][1]); + } + + return tweet; +}; + +IriSP.countProperties = function(obj) { + var count = 0; + + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) + ++count; + } + + return count; +}; + +// conversion de couleur Decimal vers HexaDecimal || 000 si fff +IriSP.DEC_HEXA_COLOR = function (dec) { + var hexa='0123456789ABCDEF'; + var hex=''; + var tmp; + while (dec>15){ + tmp = dec-(Math.floor(dec/16))*16; + hex = hexa.charAt(tmp)+hex; + dec = Math.floor(dec/16); + } + hex = hexa.charAt(dec)+hex; + return(hex); +}; + +/* shortcut to have global variables in templates */ +IriSP.templToHTML = function(template, values) { + var params = IriSP.jQuery.extend(IriSP.default_templates_vars, values); + return Mustache.to_html(template, params); +}; + +/* we need to be stricter than encodeURIComponent, + because of twitter +*/ +IriSP.encodeURI = function(str) { + return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28'). + replace(/\)/g, '%29').replace(/\*/g, '%2A'); +} + +IriSP.__guidCounter = 0; +IriSP.guid = function(prefix) { + IriSP.__guidCounter += 1; + return prefix + IriSP.__guidCounter; +}; +/* for ie compatibility +if (Object.prototype.__defineGetter__&&!Object.defineProperty) { + Object.defineProperty=function(obj,prop,desc) { + if ("get" in desc) obj.__defineGetter__(prop,desc.get); + if ("set" in desc) obj.__defineSetter__(prop,desc.set); + } +} +*/ +/* data.js - this file deals with how the players gets and sends data */ + +IriSP.DataLoader = function() { + this._cache = {}; + + /* + A structure to hold callbacks for specific urls. We need it because + ajax calls are asynchronous, so it means that sometimes we ask + multiple times for a ressource because the first call hasn't been + received yet. + */ + this._callbacks = {}; +}; + +IriSP.DataLoader.prototype.get = function(url, callback) { + + var base_url = url.split("&")[0] + if (this._cache.hasOwnProperty(base_url)) { + callback(this._cache[base_url]); + } else { + if (!this._callbacks.hasOwnProperty(base_url)) { + this._callbacks[base_url] = []; + this._callbacks[base_url].push(callback); + /* we need a closure because this gets lost when it's called back */ + + // uncomment you don't want to use caching. + // IriSP.jQuery.get(url, callback); + + var func = function(data) { + this._cache[base_url] = data; + var i = 0; + + for (i = 0; i < this._callbacks[base_url].length; i++) { + this._callbacks[base_url][i](this._cache[base_url]); + } + }; + + /* automagically choose between json and jsonp */ + if (url.indexOf(document.location.hostname) === -1 && + url.indexOf("http://") !== -1 /* not a relative url */ ) { + // we contacting a foreign domain, use JSONP + + IriSP.jQuery.get(url, {}, IriSP.wrap(this, func), "jsonp"); + } else { + + // otherwise, hey, whatever rows your boat + IriSP.jQuery.get(url, IriSP.wrap(this, func)); + } + + } else { + /* simply push the callback - it'll get called when the ressource + has been received */ + + this._callbacks[base_url].push(callback); + + } + } +} + +/* the base abstract "class" */ +IriSP.Serializer = function(DataLoader, url) { + this._DataLoader = DataLoader; + this._url = url; + this._data = []; +}; + +IriSP.Serializer.prototype.serialize = function(data) { }; +IriSP.Serializer.prototype.deserialize = function(data) {}; + +IriSP.Serializer.prototype.currentMedia = function() { +}; + +IriSP.Serializer.prototype.sync = function(callback) { + callback.call(this, this._data); +}; + +IriSP.SerializerFactory = function(DataLoader) { + this._dataloader = DataLoader; +}; + +IriSP.SerializerFactory.prototype.getSerializer = function(metadataOptions) { + /* This function returns serializer set-up with the correct + configuration - takes a metadata struct describing the metadata source + */ + + if (metadataOptions === undefined) + /* return an empty serializer */ + return IriSP.Serializer("", ""); + + switch(metadataOptions.type) { + case "json": + return new IriSP.JSONSerializer(this._dataloader, metadataOptions.src); + break; + + case "dummy": /* only used for unit testing - not defined in production */ + return new IriSP.MockSerializer(this._dataloader, metadataOptions.src); + break; + + case "empty": + return new IriSP.Serializer("", "empty"); + break; + + default: + return undefined; + } +}; +/* site.js - all our site-dependent config : player chrome, cdn locations, etc...*/ + +IriSP.lib = { + jQuery : "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js", + jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js", + jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js", + swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", + cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css", + popcorn : "/mdp/src/js/libs/popcorn.js", + jwplayer : "/mdp/src/js/libs/jwplayer.js", + popcornReplacement: "/mdp/src/js/libs/pop.js", + raphael: "/mdp/src/js/libs/raphael.js", + "popcorn.mediafragment" : "/mdp/src/js/libs/popcorn.mediafragment.js", + "popcorn.code" : "/mdp/src/js/libs/popcorn.code.js", + "popcorn.jwplayer": "/mdp/src/js/libs/popcorn.jwplayer.js", + "popcorn.youtube": "/mdp/src/js/libs/popcorn.youtube.js" +}; + +//Player Configuration +IriSP.config = undefined; + +IriSP.widgetsDefaults = { + "LayoutManager" : {spacer_div_height : "0px" }, + "PlayerWidget" : {}, + "AnnotationsWidget": { + "share_text" : "I'm watching ", + "fb_link" : "http://www.facebook.com/share.php?u=", + "tw_link" : "http://twitter.com/home?status=", + "gplus_link" : "" + }, + "TweetsWidget" : { + default_profile_picture : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png", + tweet_display_period: 10000 // how long do we show a tweet ? + }, + "SliderWidget" : { + minimize_period: 850 // how long does the slider stays maximized after the user leaves the zone ? + }, + "Main" : { + autoplay: true + } + +}; + +IriSP.paths = { +// "imgs": "/tweetlive/res/metadataplayer/src/css/imgs" + "imgs": "/mdp/src/css/imgs" +}; +IriSP.default_templates_vars = { + "img_dir" : IriSP.paths.imgs +}; + +/* ui.js - ui related functions */ + +/* FIXME: use an sharing library */ +IriSP.LdtShareTool = IriSP.share_template; /* the contents come from share.html */ + +IriSP.createPlayerChrome = function(){ + var width = IriSP.config.gui.width; + var height = IriSP.config.gui.height; + var heightS = IriSP.config.gui.height-20; + + // AUDIO */ + // PB dans le html : ; + IriSP.trace( "__IriSP.createMyHtml",IriSP.config.gui.container ); + + + /* FIXME : factor this in another file */ + if( IriSP.config.gui.mode=="radio" ){ + + IriSP.jQuery( "#"+IriSP.config.gui.container ).before(IriSP.search_template); + var radioPlayer = Mustache.to_html(IriSP.radio_template, {"share_template" : IriSP.share_template}); + IriSP.jQuery(radioPlayer).appendTo("#"+IriSP.config.gui.container); + + // special tricks for IE 7 + if (IriSP.jQuery.browser.msie==true && IriSP.jQuery.browser.version=="7.0"){ + //LdtSearchContainer + //__IriSP.jQuery("#LdtPlayer").attr("margin-top","50px"); + IriSP.jQuery("#Ldt-Root").css("padding-top","25px"); + IriSP.trace("__IriSP.createHtml","IE7 SPECIAL "); + } + } else if(IriSP.config.gui.mode=="video") { + + var videoPlayer = Mustache.to_html(IriSP.video_template, {"share_template" : IriSP.share_template, "heightS" : heightS}); + IriSP.jQuery(videoPlayer).appendTo("#"+IriSP.config.gui.container); + } + + IriSP.jQuery("#Ldt-Annotations").width(width-(75*2)); + IriSP.jQuery("#Ldt-Show-Arrow-container").width(width-(75*2)); + IriSP.jQuery("#Ldt-ShowAnnotation-audio").width(width-10); + IriSP.jQuery("#Ldt-ShowAnnotation-video").width(width-10); + IriSP.jQuery("#Ldt-SaKeyword").width(width-10); + IriSP.jQuery("#Ldt-controler").width(width-10); + IriSP.jQuery("#Ldt-Control").attr("z-index","100"); + IriSP.jQuery("#Ldt-controler").hide(); + + IriSP.jQuery(IriSP.annotation_loading_template).appendTo("#Ldt-ShowAnnotation-audio"); + + if(IriSP.config.gui.mode=='radio'){ + IriSP.jQuery("#Ldt-load-container").attr("width",IriSP.config.gui.width); + } + // Show or not the output + if(IriSP.config.gui.debug===true){ + IriSP.jQuery("#Ldt-output").show(); + } else { + IriSP.jQuery("#Ldt-output").hide(); + } + +}; + + +/* create the buttons and the slider */ +IriSP.createInterface = function( width, height, duration ) { + + IriSP.jQuery( "#Ldt-controler" ).show(); + //__IriSP.jQuery("#Ldt-Root").css('display','visible'); + IriSP.trace( "__IriSP.createInterface" , width+","+height+","+duration+"," ); + + IriSP.jQuery( "#Ldt-ShowAnnotation").click( function () { + //__IriSP.jQuery(this).slideUp(); + } ); + + var LdtpPlayerY = IriSP.jQuery("#Ldt-PlaceHolder").attr("top"); + var LdtpPlayerX = IriSP.jQuery("#Ldt-PlaceHolder").attr("left"); + + IriSP.jQuery( "#slider-range-min" ).slider( { //range: "min", + value: 0, + min: 1, + max: duration/1000,//1:54:52.66 = 3600+3240+ + step: 0.1, + slide: function(event, ui) { + + //__IriSP.jQuery("#amount").val(ui.value+" s"); + //player.sendEvent('SEEK', ui.value) + IriSP.MyApiPlayer.seek(ui.value); + //changePageUrlOffset(ui.value); + //player.sendEvent('PAUSE') + } + } ); + + IriSP.trace("__IriSP.createInterface","ICI"); + IriSP.jQuery("#amount").val(IriSP.jQuery("#slider-range-min").slider("value")+" s"); + IriSP.jQuery(".Ldt-Control1 button:first").button({ + icons: { + primary: 'ui-icon-play' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-seek-next' + }, + text: false + }); + IriSP.jQuery(".Ldt-Control2 button:first").button({ + icons: { + primary: 'ui-icon-search'//, + //secondary: 'ui-icon-volume-off' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-volume-on' + }, + text: false + }); + + // /!\ PB A MODIFIER + //__IriSP.MyTags.draw(); + IriSP.trace("__IriSP.createInterface","ICI2"); + IriSP.jQuery( "#ldt-CtrlPlay" ).attr( "style", "background-color:#CD21C24;" ); + + IriSP.jQuery( "#Ldt-load-container" ).hide(); + + if( IriSP.config.gui.mode=="radio" & IriSP.jQuery.browser.msie != true ) { + IriSP.jQuery( "#Ldtplayer1" ).attr( "height", "0" ); + } + IriSP.trace( "__IriSP.createInterface" , "3" ); + + IriSP.trace( "__IriSP.createInterface", "END" ); + + }; +/* the widget classes and definitions */ + +IriSP.Widget = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; + + if (config.hasOwnProperty("container")) { + this._id = config.container; + this.selector = IriSP.jQuery("#" + this._id); + } + + if (config.hasOwnProperty("spacer")) { + this._spacerId = config.spacer; + this.spacer = IriSP.jQuery("#" + this._spacerId); + } + + + if (config.hasOwnProperty("width")) { + // this.width and not this._width because we consider it public. + this.width = config.width; + } + + if (config.hasOwnProperty("height")) { + this.height = config.height; + } + + if (config.hasOwnProperty("heightmax")) { + this.heightmax = config.heightmax; + } + + if (config.hasOwnProperty("widthmax")) { + this.widthmax = config.widthmax; + } + +}; + +IriSP.Widget.prototype.draw = function() { + /* implemented by "sub-classes" */ +}; + +IriSP.Widget.prototype.redraw = function() { + /* implemented by "sub-classes" */ +}; +/* modules are non-graphical entities, similar to widgets */ + +IriSP.Module = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; +}; +/* layout.js - very basic layout management */ + +/* + a layout manager manages a div and the layout of objects + inside it. +*/ + +IriSP.LayoutManager = function(options) { + this._Popcorn = null; + this._widgets = []; + + this._div = "LdtPlayer"; + this._width = 640; + + if (options === undefined) { + options = {}; + }; + + if (options.hasOwnProperty('container')) { + this._div = options.container; + } + + if (options.hasOwnProperty('width')) { + this._width = options.width; + } + + if (options.hasOwnProperty('height')) { + this._height = options.height; + } + + /* this is a shortcut */ + this.selector = IriSP.jQuery("#" + this._div); + + this.selector.css("width", this._width); + + if (this._height !== undefined) + this.selector.css("height", this._height); +}; + +/* we need this special setter because of a chicken and egg problem : + we want the manager to use popcorn but the popcorn div will be managed + by the manager. So we need a way to set the instance the manager uses +*/ + +IriSP.LayoutManager.prototype.setPopcornInstance = function(popcorn) { + this._Popcorn = popcorn; +} + +/* stem is a string to append to the id of the widget */ +IriSP.LayoutManager.prototype.createDiv = function(stem) { + if (typeof(stem) === "undefined") + stem = ""; + + var newDiv = IriSP.guid(this._div + "_widget_" + stem + "_"); + var spacerDiv = IriSP.guid("LdtPlayer_spacer_"); + this._widgets.push(newDiv); + + var divTempl = "
"); + + if (options.hasOwnProperty("width")) + IriSP.jQuery("#" + containerDiv).css("width", options.width); + + if (options.hasOwnProperty("height")) + IriSP.jQuery("#" + containerDiv).css("height", options.height); + + pop = Popcorn("#" + tmpId); + break; + + case "jwplayer": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + + if (options.provider === "rtmp") { + /* exit if we can't access the metadata */ + if (typeof(IriSP.__jsonMetadata) === "undefined") { + break; + }; + + + // the json format is totally illogical + opts.streamer = IriSP.__jsonMetadata["medias"][0]["meta"]["item"]["value"]; + var source = IriSP.__jsonMetadata["medias"][0]["href"]; + + // the source if a full url but jwplayer wants an url relative to the + // streamer url, so we've got to remove the common part. + opts.file = source.slice(opts.streamer.length); + } else { + /* other providers type, video for instance - + pass everything as is */ + } + + pop = IriSP.PopcornReplacement.jwplayer("#" + containerDiv, opts); + break; + + case "youtube": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + opts.controls = 0; + opts.autostart = false; + templ = "width: {{width}}px; height: {{height}}px;"; + var str = Mustache.to_html(templ, {width: opts.width, height: opts.height}); + // Popcorn.youtube wants us to specify the size of the player in the style attribute of its container div. + IriSP.jQuery("#" + containerDiv).attr("style", str); + + pop = Popcorn.youtube("#" + containerDiv, opts.video, opts); + break; + + default: + pop = undefined; + }; + + return pop; +}; + +IriSP.configureWidgets = function (popcornInstance, layoutManager, guiOptions) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var params = {width: guiOptions.width, height: guiOptions.height}; + + var ret_widgets = []; + var index; + + for (index = 0; index < guiOptions.widgets.length; index++) { + var widgetConfig = guiOptions.widgets[index]; + var widget = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig); + ret_widgets.push(widget); + + }; + + return ret_widgets; +}; + +IriSP.configureModules = function (popcornInstance, modulesList) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var ret_modules = []; + var index; + + for (index = 0; index < modulesList.length; index++) { + var moduleConfig = modulesList[index]; + + var serializer = serialFactory.getSerializer(moduleConfig.metadata); + var module = new IriSP[moduleConfig.type](popcornInstance, moduleConfig, serializer); + ret_modules.push(module); + }; + + return ret_modules; +}; + +IriSP.instantiateWidget = function(popcornInstance, serialFactory, layoutManager, widgetConfig) { + /* create div returns us a container for the widget and a spacer */ + var ret = layoutManager.createDiv(widgetConfig.type); + var container = ret[0]; + var spacer = ret[1]; + + var arr = IriSP.jQuery.extend({}, widgetConfig); + arr.container = container; + arr.spacer = spacer; + + var serializer = serialFactory.getSerializer(widgetConfig.metadata); + + if (typeof serializer == "undefined") + debugger; + + // instantiate the object passed as a string + var widget = new IriSP[widgetConfig.type](popcornInstance, arr, serializer); + + if (widgetConfig.hasOwnProperty("requires")) { + // also create the widgets this one depends on. + // the dependency widget is available in the parent widget context as + // this.WidgetName (for instance, this.TipWidget); + + var i = 0; + for(i = 0; i < widgetConfig.requires.length; i++) { + var widgetName = widgetConfig.requires[i]["type"]; + widget[widgetName] = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig.requires[i]); + } + } + + serializer.sync(IriSP.wrap(widget, function() { this.draw(); })); + return widget; +}; +/* mediafragment module */ + +IriSP.MediaFragment = function(Popcorn, config, Serializer) { + IriSP.Module.call(this, Popcorn, config, Serializer); + + this.mutex = false; /* a mutex because we access the url from two different functions */ + + this._Popcorn.listen( "loadedmetadata", IriSP.wrap(this, IriSP.MediaFragment.advanceTime)); + this._Popcorn.listen( "pause", IriSP.wrap(this, IriSP.MediaFragment.updateTime)); + this._Popcorn.listen( "seeked", IriSP.wrap(this, IriSP.MediaFragment.updateTime)); + this._Popcorn.listen( "IriSP.PolemicTweet.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation)); + this._Popcorn.listen( "IriSP.SegmentsWidget.click", IriSP.wrap(this, IriSP.MediaFragment.updateAnnotation)); +}; + +IriSP.MediaFragment.advanceTime = function() { + var url = window.location.href; + + if ( url.split( "#" )[ 1 ] != null ) { + pageoffset = url.split( "#" )[1]; + + if ( pageoffset.substring(0, 2) === "t=") { + // timecode + if ( pageoffset.substring( 2 ) != null ) { + var offsettime = pageoffset.substring( 2 ); + this._Popcorn.currentTime( parseFloat( offsettime ) ); + } + } else if ( pageoffset.substring(0, 2) === "a=") { + // annotation + var annotationId = pageoffset.substring( 2 ); + + // there's no better way than that because + // of possible race conditions + this._serializer.sync(IriSP.wrap(this, function() { + IriSP.MediaFragment.lookupAnnotation.call(this, annotationId); + })); + } + } +}; + +IriSP.MediaFragment.updateTime = function() { + if (this.mutex === true) { + return; + } + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#t=" + this._Popcorn.currentTime().toFixed( 2 ) ); +}; + + +IriSP.MediaFragment.updateAnnotation = function(annotationId) { + var _this = this; + this.mutex = true; + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#a=" + annotationId); + + window.setTimeout(function() { _this.mutex = false }, 50); +}; + +// lookup and seek to the beginning of an annotation +IriSP.MediaFragment.lookupAnnotation = function(annotationId) { + var annotation = undefined; + var annotations = this._serializer._data.annotations; + + var i; + for (i = 0; i < annotations.length; i++) { + if (annotations[i].id === annotationId) { + annotation = annotations[i]; + break; + } + } + + if (typeof(annotation) !== "undefined") { + this._Popcorn.currentTime(annotation.begin / 1000); + } +}; +IriSP.AnnotationsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + +}; + + +IriSP.AnnotationsWidget.prototype = new IriSP.Widget(); + +IriSP.AnnotationsWidget.prototype.clear = function() { + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").text(""); +}; + +IriSP.AnnotationsWidget.prototype.displayAnnotation = function(annotation) { + + var title = annotation.content.title; + var description = annotation.content.description; + var keywords = "" // FIXME; + var begin = +annotation.begin / 1000; + var end = +annotation.end / 1000; + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + var title_templ = "{{title}} - ( {{begin}} - {{end}} )"; + var endstr = Mustache.to_html(title_templ, {title: title, begin: IriSP.secondsToTime(begin), end: IriSP.secondsToTime(end)}); + + this.selector.find(".Ldt-SaTitle").text(endstr); + this.selector.find(".Ldt-SaDescription").text(description); + + // update sharing buttons + var defaults = IriSP.widgetsDefaults.AnnotationsWidget; + var text = defaults.share_text; + var fb_link = defaults.fb_link; + var tw_link = defaults.tw_link; + var gplus_link = defaults.gplus_link; + var url = document.location.href + "#a=" + annotation.id; + this.selector.find(".Ldt-fbShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-TwShare").attr("href", tw_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-GplusShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); +}; + +IriSP.AnnotationsWidget.prototype.clearWidget = function() { + + + /* retract the pane between two annotations */ + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").html(""); + this.selector.find(".Ldt-ShowAnnotation").slideUp(); +}; + +IriSP.AnnotationsWidget.prototype.draw = function() { + var _this = this; + + var annotationMarkup = IriSP.templToHTML(IriSP.annotationWidget_template); + this.selector.append(annotationMarkup); + var view; + + if (typeof(this._serializer._data.views) !== "undefined" && this._serializer._data.views !== null) + view = this._serializer._data.views[0]; + + var view_type = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + view_type = view.annotation_types[0]; + } + + var annotations = this._serializer._data.annotations; + var i; + + for (i in annotations) { + var annotation = annotations[i]; + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + + if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + + var conf = {start: begin, end: end, + onStart: + function(annotation) { + return function() { + _this.displayAnnotation(annotation); + + } }(annotation), + onEnd: + function() { _this.clearWidget.call(_this); } + }; + this._Popcorn = this._Popcorn.code(conf); + } + +}; +IriSP.ArrowWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._oldAnnotation = null; + +}; + + +IriSP.ArrowWidget.prototype = new IriSP.Widget(); + +IriSP.ArrowWidget.prototype.clear = function() { + +}; + +IriSP.ArrowWidget.prototype.clearWidget = function() { +}; + +IriSP.ArrowWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.arrowWidget_template, {}); + this.selector.append(templ); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler)); +}; + +IriSP.ArrowWidget.prototype.timeUpdateHandler = function(percents) { + var currentTime = this._Popcorn.currentTime(); + var currentAnnotation = this._serializer.currentAnnotations(currentTime)[0]; // FIXME : use the others ? + + /* move the arrow only if the current annotation changes */ + if (currentAnnotation != this._oldAnnotation) { + var begin = (+ currentAnnotation.begin) / 1000; + var end = (+ currentAnnotation.end) / 1000; + + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var middle_time = (begin + end) / 2; + var percents = Math.floor((middle_time / duration) * 100); + + // we need to apply a fix because the arrow has a certain length + // it's half the length of the arrow (27 / 2). We need to convert + // it in percents though. + var totalWidth = this.selector.width(); + var correction = ((27 / 2) / totalWidth) * 100; + var corrected_percents = percents - correction; + + /* don't move out of the screen */ + if (corrected_percents <= 0) + corrected_percents = 0; + + this.selector.children(".Ldt-arrowWidget").animate({"left" : corrected_percents + "%"}); + + this._oldAnnotation = currentAnnotation; + } +} +IriSP.PlayerWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._searchBlockOpen = false; + this._searchLastValue = ""; +}; + +IriSP.PlayerWidget.prototype = new IriSP.Widget(); + +IriSP.PlayerWidget.prototype.draw = function() { + var self = this; + var width = this.width; + var height = this.height; + var heightS = this.height-20; + + var Player_templ = Mustache.to_html(IriSP.player_template, {"share_template" : IriSP.share_template}); + this.selector.append(Player_templ); + + this.selector.children(".Ldt-controler").show(); + + // handle clicks by the user on the video. + this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater)); + this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater)); + + this._Popcorn.listen("volumechange", IriSP.wrap(this, this.muteButtonUpdater)); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater)); + this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch)); + this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch)); + + + this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); }); + this.selector.find(".Ldt-CtrlNext").click(function() { }); + this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); }); + + this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } ); + + this.selector.find(".Ldt-CtrlPlay").attr( "style", "background-color:#CD21C24;" ); + + var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position(); + var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"}); + this.selector.append(searchBox); + + // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget) + this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, + function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); }); + + this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */ +}; + +/* Update the elasped time div */ +IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() { + + if (this._previousSecond === undefined) + this._previousSecond = this._Popcorn.roundTime(); + + else { + /* we're still in the same second, so it's not necessary to update time */ + if (this._Popcorn.roundTime() == this._previousSecond) + return; + + } + + // we get it at each call because it may change. + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var totalTime = IriSP.secondsToTime(duration); + var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime()); + + this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString()); + this.selector.find(".Ldt-TotalTime").html(totalTime.toString()); + this._previousSecond = this._Popcorn.roundTime(); +}; + +/* update the icon of the button - separate function from playHandler + because in some cases (for instance, when the user directly clicks on + the jwplayer window) we have to change the icon without playing/pausing +*/ +IriSP.PlayerWidget.prototype.playButtonUpdater = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlPlay").attr("title", "Play"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/play_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlPlay").attr("title", "Pause"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/pause_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.playHandler = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this._Popcorn.play(); + } else { + this._Popcorn.pause(); + } +}; + +IriSP.PlayerWidget.prototype.muteHandler = function() { + if (!this._Popcorn.muted()) { + this._Popcorn.mute(true); + } else { + this._Popcorn.mute(false); + } +}; + +IriSP.PlayerWidget.prototype.muteButtonUpdater = function() { + var status = this._Popcorn.media.muted; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlSound").attr("title", "Unmute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/sound_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlSound").attr("title", "Mute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/mute_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.searchButtonHandler = function() { + var self = this; + + /* show the search field if it is not shown */ + if ( this._searchBlockOpen == false ) { + this.selector.find(".LdtSearch").show(100); + + this.selector.find(".LdtSearchInput").css('background-color','#fff'); + this.selector.find(".LdtSearchInput").focus(); + this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue); + this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural. + + this._searchBlockOpen = true; + this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } ); + + // we need this variable because some widget can find a match in + // their data while at the same time other's don't. As we want the + // search field to become green when there's a match, we need a + // variable to remember that we had one. + this._positiveMatch = false; + + // tell the world the field is open + this._Popcorn.trigger("IriSP.search.open"); + + } else { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this.selector.find(".LdtSearchInput").attr('value',''); + this.selector.find(".LdtSearch").hide(100); + + // unbind the watcher event. + this.selector.find(".LdtSearchInput").unbind('keypress set'); + this._searchBlockOpen = false; + + this._positiveMatch = false; + + this._Popcorn.trigger("IriSP.search.closed"); + } +}; + +/* this handler is called whenever the content of the search + field changes */ +IriSP.PlayerWidget.prototype.searchHandler = function() { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this._positiveMatch = false; + + // do nothing if the search field is empty, instead of highlighting everything. + if (this._searchLastValue == "") { + this._Popcorn.trigger("IriSP.search.cleared"); + this.selector.find(".LdtSearchInput").css('background-color',''); + } else { + this._Popcorn.trigger("IriSP.search", this._searchLastValue); + } +}; + +/* + handler for the IriSP.search.found message, which is sent by some views when they + highlight a match. +*/ +IriSP.PlayerWidget.prototype.searchMatch = function() { + this._positiveMatch = true; + this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1'); +} + +/* the same, except that no value could be found */ +IriSP.PlayerWidget.prototype.searchNoMatch = function() { + if (this._positiveMatch !== true) + this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a"); +} + +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +// CHART TIMELINE / VERSION PROTOTYPE :: + +IriSP.PolemicWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this.userPol = new Array(); + this.userNoPol = new Array(); + this.userst = new Array(); + this.numberOfTweet = 0; + this.Users; + this.TweetPolemic; + this.yMax = this.height; + this.PaperSlider; + this.heightOfChart; + this.tweets = new Array(); + this.svgElements = {}; + + // Make and define the Raphael area + this.paper = Raphael(document.getElementById(this._id), config.width, config.height); + + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); })); + this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler)); + this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler)); + +}; + +IriSP.PolemicWidget.prototype = new IriSP.Widget(); + +IriSP.PolemicWidget.prototype.draw = function() { + + // variable + // yMax + + var self = this; + var yCoef = 2; // coef for height of 1 tweet + var frameSize = 5; // frame size + var margin = 1; // marge between frame + var lineSize = this.width; // timeline pixel width + var nbrframes = lineSize/frameSize; // frame numbers + var numberOfTweet = 0; // number of tweet overide later + var duration = +this._serializer.currentMedia().meta["dc:duration"]; // timescale width + var frameLength = lineSize / frameSize; // frame timescale + var timeline; + var colors = new Array("","#1D973D","#C5A62D","#CE0A15","#036AAE","#585858"); + + // array + //var tweets = new Array(); + var element = new Array(); + var cluster = new Array(); + var frames = new Array(frameLength); + var slices = new Array(); + + + // Classes ======================================================================= + var Frames = function(){ + + var Myclusters; + var x; + var y; + var width; + var height; + }; + Frames = function(json){ + // make my clusters + // ou Frame vide + }; + Frames.prototype.draw = function(){ + }; + Frames.prototype.zoom = function(){ + }; + Frames.prototype.inside = function(){ + }; + var Clusters = function(){ + var Object; + var yDist; + var x; + var y; + var width; + var height; + }; + Clusters = function(json){ + // make my object + }; + var Tweet = function(){ + }; + // Classes ======================================================================= + + // Refactoring (parametere) ************************************************************ + // color translastion + var qTweet_0 =0; + var qTweet_Q =0; + var qTweet_REF=0; + var qTweet_OK =0; + var qTweet_KO =0; + function colorTranslation(value){ + if(value == "Q"){ + qTweet_Q+=1; + return 2; + }else if(value =="REF"){ + qTweet_REF+=1; + return 4; + }else if(value =="OK"){ + qTweet_OK+=1; + return 1; + }else if(value =="KO"){ + qTweet_KO+=1; + return 3; + }else if(value ==""){ + qTweet_0+=1; + return 5; + } + } + + + this._serializer.sync(function(data) { loaded_callback.call(self, data) }); + + function loaded_callback (json) { + + // get current view (the first ???) + view = json.views[0]; + + // the tweets are by definition of the second annotation type FIXME ? + tweet_annot_type = null; + if(typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + tweet_annot_type = view.annotation_types[1]; + } + + for(var i = 0; i < json.annotations.length; i++) { + var item = json.annotations[i]; + var MyTime = Math.floor(item.begin/duration*lineSize); + var Myframe = Math.floor(MyTime/lineSize*frameLength); + + if (typeof(item.meta) !== "undefined" + && typeof(item.meta["id-ref"]) !== "undefined" + && item.meta["id-ref"] === tweet_annot_type) { + + var MyTJson = JSON.parse(item.meta['dc:source']['content']); + + if (item.content['polemics'] != undefined + && item.content['polemics'][0] != null) { + + // a tweet can have many polemics at the same time. + for(var j=0; j max) { + max = moy; + } + } + + var tweetDrawed = new Array(); + var TweetHeight = 5; + + // DRAW TWEETS ============================================ + for(var i = 0; i < nbrframes; i++) { + var addEheight = 5; + if (frames[i] != undefined){ + // by type + + for (var j = 6; j > -1; j--) { + if (frames[i].qualifVol[j] != undefined) { + // show tweet by type + for (var k = 0; k < frames[i].mytweetsID.length; k++) { + + if (frames[i].mytweetsID[k].qualification == j) { + var x = i * frameSize; + var y = this.heightmax - addEheight; + + if (this.yMax > y) { + this.yMax = y; + } + + var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */) + .attr({stroke:"#00","stroke-width":0.1, fill: colors[j]}); + + addEheight += TweetHeight; + + e.color = colors[j]; + e.time = frames[i].mytweetsID[k].timeframe; + e.title = frames[i].mytweetsID[k].title; + e.id = frames[i].mytweetsID[k].cinecast_id; + + this.svgElements[e.id] = e; + + /* + e.mouseover(function(element) { return function (event) { + // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. + self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.clientX - 106, event.clientY - 160); + element.displayed = true; + }}(e)).mouseout(function(element) { return function () { + self.TooltipWidget.hide.call(self.TooltipWidget); + }}(e)).mousedown(function () { + self._Popcorn.currentTime(this.time/1000); + self._Popcorn.trigger("IriSP.PolemicTweet.click", this.id); + }); + */ + + IriSP.jQuery(e.node).mouseenter(function(element) { return function (event) { + // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. + self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.pageX - 106, event.pageY - 160); + element.displayed = true; + }}(e)).mousedown(function(element) { return function () { + self._Popcorn.currentTime(element.time/1000); + self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); + } + }(e)); + + IriSP.jQuery(e.node).attr('id', 't' + k + ''); + IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title); + IriSP.jQuery(e.node).attr('begin', frames[i].mytweetsID[k].timeframe); + } + } + } + } + } + + } + // DRAW UI :: resize border and bgd + this.paperBackground = this.paper.rect(0, 0, this.width, this.heightmax).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1}); + + // outer borders + this.outerBorders = []; + this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + + // inner borders + this.innerBorders = []; + this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8})); + this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1})); + + + + this.paperSlider = this.paper.rect(0, 0, 0, this.heightmax).attr({fill:"#D4D5D5", stroke: "none", opacity: 1}); + + // the small white line displayed over the slider. + this.sliderTip = this.paper.rect(0, 0, 1, this.heightmax).attr({fill:"#fc00ff", stroke: "none", opacity: 1}); + // decalage + // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1}); + + + this.paperSlider.toBack(); + this.paperBackground.toBack(); + this.sliderTip.toFront(); + } + + this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); })); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); +} + +IriSP.PolemicWidget.prototype.sliderUpdater = function() { + + var time = +this._Popcorn.currentTime(); + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + this.paperSlider.attr("width", time * (this.width / (duration / 1000))); + + this.sliderTip.attr("x", time * (this.width / (duration / 1000))); +}; + +IriSP.PolemicWidget.prototype.searchHandler = function(searchString) { + if (searchString == "") + return; + + var matches = this._serializer.searchTweetsOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + for (var id in matches) { + if (this.svgElements.hasOwnProperty(id)) { + var e = this.svgElements[id]; + this.svgElements[id].attr({fill: "#fc00ff"}); + } + } + + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + if (!matches.hasOwnProperty(id)) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + } + + this.oldSearchMatches = matches; +}; + +IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; + +IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() { + // clean up the blocks that were in the previous search + // but who aren't in the current one. + for (var id in this.oldSearchMatches) { + var e = this.svgElements[id]; + e.attr({fill: e.color}); + } + +}; + +IriSP.SegmentsWidget = function(Popcorn, config, Serializer) { + + var self = this; + IriSP.Widget.call(this, Popcorn, config, Serializer); + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", function(searchString) { self.searchHandler.call(self, searchString); }); + this._Popcorn.listen("IriSP.search.closed", function() { self.searchFieldClosedHandler.call(self); }); + this._Popcorn.listen("IriSP.search.cleared", function() { self.searchFieldClearedHandler.call(self); }); +}; + +IriSP.SegmentsWidget.prototype = new IriSP.Widget(); + +/* Get the width of a segment, in pixels. */ +IriSP.SegmentsWidget.prototype.segmentToPixel = function(annotation) { + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + + var startPourcent = IriSP.timeToPourcent(begin, duration); + var startPixel = Math.floor(this.selector.parent().width() * (startPourcent / 100)); + + var endPourcent = Math.floor(IriSP.timeToPourcent(end, duration) - startPourcent); + var endPixel = Math.floor(this.selector.parent().width() * (endPourcent / 100)); + + return endPixel; +}; + +/* compute the total length of a group of segments */ +IriSP.SegmentsWidget.prototype.segmentsLength = function(segmentsList) { + var self = this; + var total = 0; + + for (var i = 0; i < segmentsList.length; i++) + total += self.segmentToPixel(segmentsList[i].annotation); + + return total; +}; + +IriSP.SegmentsWidget.prototype.draw = function() { + + var self = this; + var annotations = this._serializer._data.annotations; + + this.selector.addClass("Ldt-SegmentsWidget"); + this.selector.append(Mustache.to_html(IriSP.overlay_marker_template)); + + var view_type = this._serializer.getNonTweetIds()[0]; + + this.positionMarker = this.selector.children(":first"); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.positionUpdater)); + + + var i = 0; + + var segments_annotations = []; + + for (i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + segments_annotations.push(annotation); + } + + var totalWidth = this.selector.width() - segments_annotations.length; + var lastSegment = IriSP.underscore.max(segments_annotations, function(annotation) { return annotation.end; }); + + for (i = 0; i < segments_annotations.length; i++) { + + var annotation = segments_annotations[i]; + var begin = (+ annotation.begin); + var end = (+ annotation.end); + var duration = this._serializer.currentMedia().meta["dc:duration"]; + var id = annotation.id; + + var startPixel = Math.floor(this.selector.parent().width() * (begin / duration)); + + var endPixel = Math.floor(this.selector.parent().width() * (end / duration)); + + if (annotation.id !== lastSegment.id) + var pxWidth = endPixel - startPixel -1; + else + /* the last segment has no segment following it */ + var pxWidth = endPixel - startPixel; + + var divTitle = (annotation.content.title + " - " + annotation.content.description).substr(0,55); + + if (typeof(annotation.content.color) !== "undefined") + var color = annotation.content.color; + else + var color = annotation.color; + + var hexa_color = IriSP.DEC_HEXA_COLOR(color); + + if (hexa_color === "FFCC00") + hexa_color = "333"; + if (hexa_color.length == 4) + hexa_color = hexa_color + '00'; + + var annotationTemplate = Mustache.to_html(IriSP.annotation_template, + {"divTitle" : divTitle, "id" : id, "startPixel" : startPixel, + "pxWidth" : pxWidth, "hexa_color" : hexa_color, + "seekPlace" : Math.round(begin/1000)}); + + + this.selector.append(annotationTemplate); + + /* add a special class to the last segment and change its border */ + if (annotation.id === lastSegment.id) { + this.selector.find("#" + id).addClass("Ldt-lastSegment"); + this.selector.find(".Ldt-lastSegment").css("border-color", "#" + hexa_color); + } + + IriSP.jQuery("#" + id).fadeTo(0, 0.3); + + IriSP.jQuery("#" + id).mouseover( + /* we wrap the handler in another function because js's scoping + rules are function-based - otherwise, the internal vars like + divTitle are preserved but they are looked-up from the draw + method scope, so after that the loop is run, so they're not + preserved */ + (function(divTitle) { + return function(event) { + IriSP.jQuery(this).animate({opacity: 0.6}, 5); + var offset = IriSP.jQuery(this).offset(); + var correction = IriSP.jQuery(this).outerWidth() / 2; + + var offset_x = offset.left + correction - 106; + if (offset_x < 0) + offset_x = 0; + + self.TooltipWidget.show(divTitle, color, offset_x, event.pageY - 160); + } })(divTitle)).mouseout(function(){ + IriSP.jQuery(this).animate({opacity: 0.3}, 5); + self.TooltipWidget.hide(); + }); + + IriSP.jQuery("#" + id).click(function(_this, annotation) { + return function() { _this.clickHandler(annotation)}; + }(this, annotation)); + } +}; + +/* restores the view after a search */ +IriSP.SegmentsWidget.prototype.clear = function() { + this.selector.children(".Ldt-iri-chapter").animate({opacity:0.3}, 100); +}; + +IriSP.SegmentsWidget.prototype.clickHandler = function(annotation) { + this._Popcorn.trigger("IriSP.SegmentsWidget.click", annotation.id); + var begin = (+ annotation.begin) / 1000; + this._Popcorn.currentTime(Math.round(begin)); +}; + +IriSP.SegmentsWidget.prototype.searchHandler = function(searchString) { + + if (searchString == "") + return; + + var matches = this._serializer.searchOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + // un-highlight all the blocks + this.selector.children(".Ldt-iri-chapter").css("opacity", 0.1); + + // then highlight the ones with matches. + for (var id in matches) { + var factor = 0.5 + matches[id] * 0.2; + this.selector.find("#"+id).dequeue(); + this.selector.find("#"+id).animate({opacity:factor}, 200); + } + + + this.oldSearchMatches = matches; +}; + +IriSP.SegmentsWidget.prototype.searchFieldClearedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.searchFieldClosedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.positionUpdater = function() { + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var time = this._Popcorn.currentTime(); + //var position = ((time / duration) * 100).toFixed(2); + var position = ((time / duration) * 100).toFixed(2); + + this.positionMarker.css("left", position + "%"); +}; +IriSP.SliderWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); +}; + +IriSP.SliderWidget.prototype = new IriSP.Widget(); + +IriSP.SliderWidget.prototype.draw = function() { + var self = this; + + this.selector.append(Mustache.to_html(IriSP.sliderWidget_template, {})); + this.selector.addClass("Ldt-SliderMinimized"); + + this.sliderBackground = this.selector.find(".Ldt-sliderBackground"); + this.sliderForeground = this.selector.find(".Ldt-sliderForeground"); + this.positionMarker = this.selector.find(".Ldt-sliderPositionMarker"); + + + // a special variable to stop methods from tinkering + // with the positionMarker when the user is dragging it + this.draggingOngoing = false; + + // another special variable used by the timeout handler to + // open or close the slider. + this.sliderMaximized = false; + this.timeOutId = null; + + + this.positionMarker.draggable({axis: "x", + start: IriSP.wrap(this, this.positionMarkerDraggingStartedHandler), + stop: IriSP.wrap(this, this.positionMarkerDraggedHandler), + containment: "parent" + }); + this.positionMarker.css("position", "absolute"); + + this.sliderBackground.click(function(event) { self.backgroundClickHandler.call(self, event); }); + this.sliderForeground.click(function(event) { self.foregroundClickHandler.call(self, event); }); + + this.selector.hover(IriSP.wrap(this, this.mouseOverHandler), IriSP.wrap(this, this.mouseOutHandler)); + + // update the positions + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); + + // special messages : + this._Popcorn.listen("IriSP.PlayerWidget.MouseOver", IriSP.wrap(this, this.mouseOverHandler)); + this._Popcorn.listen("IriSP.PlayerWidget.MouseOut", IriSP.wrap(this, this.mouseOutHandler)); +}; + +/* update the slider and the position marker as time passes */ +IriSP.SliderWidget.prototype.sliderUpdater = function() { + if(this.draggingOngoing || this._disableUpdate) + return; + + var time = this._Popcorn.currentTime(); + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var percent = ((time / duration) * 100).toFixed(2); + + /* we do these complicated calculations to center exactly + the position Marker */ + var pixels_to_percents = 100 / this.selector.width(); /* how much is a pixel in percents */ + var positionMarker_width = this.positionMarker.width(); + var correction = (pixels_to_percents * positionMarker_width) / 2; + + var newPos = percent - correction; + if (newPos <= 0) + newPos = 0; + + this.sliderForeground.css("width", percent + "%"); + this.positionMarker.css("left", newPos + "%"); + +}; + +IriSP.SliderWidget.prototype.backgroundClickHandler = function(event) { + /* this piece of code is a little bit convoluted - here's how it works : + we want to handle clicks on the progress bar and convert those to seeks in the media. + However, jquery only gives us a global position, and we want a number of pixels relative + to our container div, so we get the parent position, and compute an offset to this position, + and finally compute the progress ratio in the media. + Finally we multiply this ratio with the duration to get the correct time + */ + + var parentOffset = this.sliderBackground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* same function as the previous one, except that it handles clicks + on the foreground element */ +IriSP.SliderWidget.prototype.foregroundClickHandler = function(event) { + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* handles mouse over the slider */ +IriSP.SliderWidget.prototype.mouseOverHandler = function(event) { + + if (this.timeOutId !== null) { + window.clearTimeout(this.timeOutId); + } + + this.sliderMaximized = true; + + this.sliderBackground.animate({"height": "9px"}, 100); + this.sliderForeground.animate({"height": "9px"}, 100); + this.positionMarker.animate({"height": "9px", "width": "9px"}, 100); + //this.positionMarker.css("margin-top", "-4px"); + +// this.selector.removeClass("Ldt-SliderMinimized"); +// this.selector.addClass("Ldt-SliderMaximized"); +}; + +/* handles when the mouse leaves the slider */ +IriSP.SliderWidget.prototype.mouseOutHandler = function(event) { + + this.timeOutId = window.setTimeout(IriSP.wrap(this, this.minimizeOnTimeout), + IriSP.widgetsDefaults.SliderWidget.minimize_period); +}; + +IriSP.SliderWidget.prototype.minimizeOnTimeout = function(event) { + this.sliderBackground.animate({"height": "5px"}, 100); + this.sliderForeground.animate({"height": "5px"}, 100); + this.positionMarker.animate({"height": "5px", "width": "5px"}, 100); + this.positionMarker.css("margin-top", "0px"); + this.sliderMinimized = true; + +// this.selector.removeClass("Ldt-SliderMaximized"); +// this.selector.addClass("Ldt-SliderMinimized"); + +}; + +// called when the user starts dragging the position indicator +IriSP.SliderWidget.prototype.positionMarkerDraggingStartedHandler = function(event, ui) { + this.draggingOngoing = true; +}; + +IriSP.SliderWidget.prototype.positionMarkerDraggedHandler = function(event, ui) { + this._disableUpdate = true; // disable slider position updates while dragging is ongoing. + window.setTimeout(IriSP.wrap(this, function() { this._disableUpdate = false; }), 500); + + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); + + this.draggingOngoing = false; +}; + +/* this widget displays a small tooltip */ +IriSP.TooltipWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + this._shown = false; + this._displayedText = ""; + this._hideTimeout = -1; +}; + + +IriSP.TooltipWidget.prototype = new IriSP.Widget(); + +IriSP.TooltipWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.tooltipWidget_template); + + this.selector.append(templ); + this.hide(); + +}; + +IriSP.TooltipWidget.prototype.clear = function() { + this.selector.find(".tiptext").text(""); +}; + +IriSP.TooltipWidget.prototype.show = function(text, color, x, y) { + + if (this._displayedText == text) + return; + + this.selector.find(".tipcolor").css("background-color", color); + this._displayedText = text; + this.selector.find(".tiptext").text(text); + //this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").show(); + this._shown = true; +}; + +IriSP.TooltipWidget.prototype.hide = function() { + this.selector.find(".tip").hide(); + this._shown = false; +};/* a widget that displays tweet - used in conjunction with the polemicWidget */ + +IriSP.TweetsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._displayingTweet = false; + this._timeoutId = undefined; +}; + + +IriSP.TweetsWidget.prototype = new IriSP.Widget(); + + +IriSP.TweetsWidget.prototype.drawTweet = function(annotation) { + + var title = IriSP.formatTweet(annotation.content.title); + var img = annotation.content.img.src; + if (typeof(img) === "undefined" || img === "" || img === "None") { + img = IriSP.widgetsDefaults.TweetsWidget.default_profile_picture; + } + + var imageMarkup = IriSP.templToHTML("user image", + {src : img}); + + if (typeof(annotation.meta["dc:source"].content) !== "undefined") { + var tweetContents = JSON.parse(annotation.meta["dc:source"].content); + var creator = tweetContents.user.screen_name; + var real_name = tweetContents.user.name; + + imageMarkup = IriSP.templToHTML("user image", + {src : img, creator: creator}); + + var formatted_date = new Date(tweetContents.created_at).toLocaleDateString(); + title = IriSP.templToHTML("@{{creator}} - " + + "
{{real_name}}
" + + "
{{{ contents }}}
" + + "
{{ date }}
", + {creator: creator, real_name: real_name, contents : title, date : formatted_date}); + + this.selector.find(".Ldt-TweetReply").attr("href", "http://twitter.com/home?status=@" + creator + ":%20"); + + + var rtText = Mustache.to_html("http://twitter.com/home?status=RT @{{creator}}: {{text}}", + {creator: creator, text: IriSP.encodeURI(annotation.content.title)}); + this.selector.find(".Ldt-Retweet").attr("href", rtText); + } + + this.selector.find(".Ldt-tweetContents").html(title); + this.selector.find(".Ldt-tweetAvatar").html(imageMarkup); + this.selector.show("blind", 250); +}; + +IriSP.TweetsWidget.prototype.displayTweet = function(annotation) { + if (this._displayingTweet === false) { + this._displayingTweet = true; + } else { + window.clearTimeout(this._timeoutId); + } + + this.drawTweet(annotation); + + var time = this._Popcorn.currentTime(); + this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), IriSP.widgetsDefaults.TweetsWidget.tweet_display_period); +}; + + +IriSP.TweetsWidget.prototype.clearPanel = function() { + this._displayingTweet = false; + this._timeoutId = undefined; + this.closePanel(); + +}; + +IriSP.TweetsWidget.prototype.closePanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } + + this.selector.hide("blind", 400); + +}; + +/* cancel the timeout if the user clicks on the keep panel open button */ +IriSP.TweetsWidget.prototype.keepPanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } +}; + +IriSP.TweetsWidget.prototype.draw = function() { + var _this = this; + + var tweetMarkup = IriSP.templToHTML(IriSP.tweetWidget_template, {"share_template" : IriSP.share_template}); + this.selector.append(tweetMarkup); + this.selector.hide(); + this.selector.find(".Ldt-tweetWidgetMinimize").click(IriSP.wrap(this, this.closePanel)); + this.selector.find(".Ldt-tweetWidgetKeepOpen").click(IriSP.wrap(this, this.keepPanel)); + + this._Popcorn.listen("IriSP.PolemicTweet.click", IriSP.wrap(this, this.PolemicTweetClickHandler)); +}; + +IriSP.TweetsWidget.prototype.PolemicTweetClickHandler = function(tweet_id) { + var index, annotation; + for (index in this._serializer._data.annotations) { + annotation = this._serializer._data.annotations[index]; + + if (annotation.id === tweet_id) + break; + } + + if (annotation.id !== tweet_id) + /* we haven't found it */ + return; + + this.displayTweet(annotation); + return; +}; + +IriSP.JSONSerializer = function(DataLoader, url) { + IriSP.Serializer.call(this, DataLoader, url); +}; + +IriSP.JSONSerializer.prototype = new IriSP.Serializer(); + +IriSP.JSONSerializer.prototype.serialize = function(data) { + return JSON.stringify(data); +}; + +IriSP.JSONSerializer.prototype.deserialize = function(data) { + return JSON.parse(data); +}; + +IriSP.JSONSerializer.prototype.sync = function(callback) { + /* we don't have to do much because jQuery handles json for us */ + + var self = this; + + var fn = function(data) { + self._data = data; + // sort the data too + self._data["annotations"].sort(function(a, b) + { var a_begin = +a.begin; + var b_begin = +b.begin; + return a_begin - b_begin; + }); + + callback(data); + }; + + this._DataLoader.get(this._url, fn); +}; + +IriSP.JSONSerializer.prototype.currentMedia = function() { + return this._data.medias[0]; /* FIXME: don't hardcode it */ +}; + +/* this function searches for an annotation which matches title, description and keyword + "" matches any field. + Note: it ignores tweets. +*/ +IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return true; // don't pass + } else { + return false; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* only look for tweets */ +IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return false; // pass + } else { + return true; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* + the previous function call this one, which is more general: + */ +IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) { + + var rTitle; + var rDescription; + var rKeyword; + /* match anything if given the empty string */ + if (title == "") + title = ".*"; + if (description == "") + description = ".*"; + if (keyword == "") + keyword = ".*"; + + rTitle = new RegExp(title, "i"); + rDescription = new RegExp(description, "i"); + rKeyword = new RegExp(keyword, "i"); + + var ret_array = []; + + var i; + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (filter(annotation)) { + continue; + } + + if (rTitle.test(annotation.content.title) && + rDescription.test(annotation.content.description)) { + /* FIXME : implement keyword support */ + ret_array.push(annotation); + } + } + + return ret_array; +}; + +/* breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/* breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchTweets(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchTweets("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/* takes the currentTime and returns all the annotations that are displayable at the moment + NB: only takes account the first type of annotations - ignores tweets + currentTime is in seconds. + */ + +IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime) { + var view; + var currentTimeMs = 1000 * currentTime; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var view_type = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length >= 1) { + view_type = view.annotation_types[0]; + } + + var ret_array = []; + + var i; + + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + if (annotation.meta["id-ref"] === view_type && annotation.begin <= currentTimeMs && annotation.end >= currentTimeMs) + ret_array.push(annotation); + } + + return ret_array; +}; + + +/* this function returns a list of ids of tweet lines */ +IriSP.JSONSerializer.prototype.getTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + var tweetsId = []; + + /* first get the list containing the tweets */ + var tweets = IriSP.underscore.filter(this._data.lists, function(entry) { return entry.id.indexOf("tweet") !== -1 }); + + // FIXME: collect tweets from multiple sources ? + tweetsId = IriSP.underscore.pluck(tweets[0].items, "id-ref"); + + return tweetsId; +}; + +/* this function returns a list of lines which are not tweet lines */ +IriSP.JSONSerializer.prototype.getNonTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + /* get all the ids */ + var ids = IriSP.underscore.map(this._data.lists, function(entry) { + return IriSP.underscore.pluck(entry.items, "id-ref"); }); + + var illegal_values = this.getTweetIds(); + return IriSP.underscore.difference(ids, illegal_values); + +};