# HG changeset patch # User veltr # Date 1333477812 -7200 # Node ID 8da49ff273e06c29f99d55d2543c140079d31b79 # Parent ac66e2240e1edea53ba92e658b94c3ed34e5b766 Modifs cinecast diff -r ac66e2240e1e -r 8da49ff273e0 src/js/libs/tracemanager.js --- a/src/js/libs/tracemanager.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/libs/tracemanager.js Tue Apr 03 20:30:12 2012 +0200 @@ -2,9 +2,13 @@ * Modelled Trace API */ IriSP.TraceManager = function($) { - /* - * FIXME: Write proper representation functions (str, json, ...) - */ + // If there are more than MAX_FAILURE_COUNT synchronisation + // failures, then disable synchronisation + MAX_FAILURE_COUNT = 20; + + // If there are more than MAX_BUFFER_SIZE obsels in the buffer, + // then "compress" them as a single "ktbsFullBuffer" + MAX_BUFFER_SIZE = 500; var BufferedService_prototype = { /* @@ -14,15 +18,18 @@ // buffer: [], // isReady: false, // timer: null, + // failureCount: 0, /* Flush buffer */ flush: function() { - // FIXME: should add a counter to avoid starving the sync - // process in case of too many generated obsels. // FIXME: add mutex on this.buffer if (! this.isReady) { - console.log("Sync service not ready"); + if (window.console) window.console.log("Sync service not ready"); + } else if (this.failureCount > MAX_FAILURE_COUNT) + { + // Disable synchronisation + this.set_sync_mode('none'); } else if (this.buffer.length) { var temp = this.buffer; this.buffer = []; @@ -34,11 +41,13 @@ // prefixing it with c var data = 'c' + JSON.stringify(temp.map(function (o) { return o.toCompactJSON(); })); // Swap " (very frequent, which will be - // serialized into %22) and / (rather rare), this + // serialized into %22) and ; (rather rare), this // saves some bytes - data = data.replace(/[\/"]/g, function(s){ return s == '/' ? '"' : '/'; }).replace('#','%23'); + data = data.replace(/[;"]/g, function(s){ return s == ';' ? '"' : ';'; }).replace(/#/g, '%23'); // FIXME: check data length (< 2K is safe) - var request=$('').attr('src', this.url + 'trace/?data=' + data); + var request=$('').error( function() { this.failureCount += 1; }) + .load( function() { this.failureCount = 0; }) + .attr('src', this.url + 'trace/?data=' + data); } else { @@ -50,28 +59,52 @@ // Type of the returned data. dataType: "html", error: function(jqXHR, textStatus, errorThrown) { - // FIXME: not called for JSONP/crossdomain - console.log("Error when sending buffer:", textStatus); + if (window.console) window.console.log("Error when sending buffer:", textStatus); + this.failureCount += 1; }, success: function(data, textStatus, jqXHR) { - // FIXME: parse the returned JSON, and get - // the updated properties (id, uri...) to apply them to temp items + // Reset failureCount to 0 as soon as there is 1 valid answer + this.failureCount = 0; } }); } } }, + /* Sync mode: delayed, sync (immediate sync), none (no + * synchronisation with server, the trace has to be explicitly saved + * if needed */ + set_sync_mode: function(mode) { + this.sync_mode = mode; + if (! this.isReady && mode !== "none") + this.init(); + if (mode == 'delayed') { + this.start_timer(); + } else { + this.stop_timer(); + } + }, + /* Enqueue an obsel */ enqueue: function(obsel) { + if (this.buffer.length > MAX_BUFFER_SIZE) + { + obsel = new Obsel('ktbsFullBuffer', this.buffer[0].begin, + this.buffer[this.buffer.length - 1].end, this.buffer[0].subject); + obsel.trace = this.buffer[0].trace; + this.buffer = []; + } this.buffer.push(obsel); + if (this.sync_mode === 'sync') { + // Immediate sync of the obsel. + this.flush(); + } }, start_timer: function() { var self = this; if (this.timer === null) { this.timer = window.setInterval(function() { - console.log("Flushing timeout"); self.flush(); }, this.timeOut); } @@ -120,6 +153,9 @@ this.buffer = []; this.isReady = false; this.timer = null; + this.failureCount = 0; + // sync_mode is either "none", "sync" or "buffered" + this.sync_mode = "none"; /* mode can be either POST or GET */ if (mode == 'POST' || mode == 'GET') this.mode = mode; @@ -137,7 +173,6 @@ obsels: [], /* Trace URI */ uri: "", - sync_mode: "none", default_subject: "", /* baseuri is used as the base URI to resolve relative * attribute-type names in obsels. Strictly speaking, this @@ -159,16 +194,8 @@ * synchronisation with server, the trace has to be explicitly saved * if needed */ set_sync_mode: function(mode) { - this.sync_mode = mode; - if (this.syncservice != null) { - if (mode !== 'none') { - this.syncservice.init(); - } - if (mode == 'delayed') { - this.syncservice.start_timer(); - } else { - this.syncservice.stop_timer(); - } + if (this.syncservice !== null) { + this.syncservice.set_sync_mode(mode); } }, @@ -237,38 +264,10 @@ } o.trace = this; this.obsels.push(o); - if (this.syncservice !== null && this.sync_mode != 'none') { + if (this.syncservice !== null) this.syncservice.enqueue(o); - if (this.sync_mode === 'sync') { - // Immediate sync of the obsel. - this.syncservice.flush(); - } - } }, - obselProbe : function(element, bindingEvent, ObselFunction) { - console.log("!!!!!!!!- ICI -!!!!!!!!!"); - console.log(element); - console.log(bindingEvent); - console.log(ObselFunction); - - //var myOPI = self.setInterval("ObselProbeInterval("+element+","+bindingEvent+","+ObselFunction+")",1000); - var myOPI = self.setInterval("ObselProbeInterval("+element+")",1000); - //var ObselProbeInterval = function(element, bindingEvent, ObselFunction){ - var ObselProbeInterval = function(element) { - console.log("!!!!!!!!- ObselProbeInterval -!!!!!!!!!"); - console.log($(element).length); - /* - if($(element).length!=0){ - $(element).bind(bindingEvent, ObselFunction ); - this.clearInterval(); - }else{ console.log("!!!!!!!!- EXISTE PAS -!!!!!!!!!") - } - */ - // - }; - - }, /* Helper methods */ /* Create a new obsel with the given attributes */ @@ -320,7 +319,6 @@ * purposes. They MUST be defined in the constructor * function. */ trace: undefined, - obselProbe: undefined, type: undefined, begin: undefined, end: undefined, @@ -334,7 +332,6 @@ }, get_obsel_type: function() { - /* FIXME: maybe we should return a ObselType object. In the meantime, return the URI */ return this.type; }, get_begin: function() { @@ -350,7 +347,8 @@ list_attribute_types: function() { var result = []; for (var prop in this.attributes) { - result.push(prop); + if (this.hasOwnProperty(prop)) + result.push(prop); } /* FIXME: we return URIs here instead of AttributeType elements */ return result; @@ -422,7 +420,8 @@ "subject": this.subject }; for (var prop in this.attributes) { - r[prop] = this.attributes[prop]; + if (this.hasOwnProperty(prop)) + r[prop] = this.attributes[prop]; } return r; }, @@ -434,15 +433,20 @@ toCompactJSON: function() { var r = { "@i": this.id, - "@t": (this.trace.shorthands.hasOwnProperty(this.type) - ? this.trace.shorthands[this.type] : this.type), + "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type), "@b": this.begin, - "@e": this.end, "@s": this.subject }; + // Store duration (to save some bytes) and only if it is non-null + if (this.begin !== this.end) + r["@d"] = this.end - this.begin; + for (var prop in this.attributes) { - var v = this.attributes[prop]; - r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v; + if (this.hasOwnProperty(prop)) + { + var v = this.attributes[prop]; + r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v; + } } return r; }, @@ -485,12 +489,14 @@ */ init_trace: function(name, params) { - console.log("init_trace", params); + if (window.console) window.console.log("init_trace", params); url = params.url ? params.url : ""; requestmode = params.requestmode ? params.requestmode : "POST"; syncmode = params.syncmode ? params.syncmode : "none"; + default_subject = params.default_subject ? params.default_subject : "default"; var t = new Trace(url, requestmode); t.set_sync_mode(syncmode); + t.set_default_subject(default_subject); this.traces[name] = t; return t; } @@ -501,5 +507,6 @@ }; TraceManager.prototype = TraceManager_prototype; - return new TraceManager(); + var tracemanager = new TraceManager(); + return tracemanager; }; diff -r ac66e2240e1e -r 8da49ff273e0 src/js/players/player.allocine.js --- a/src/js/players/player.allocine.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/players/player.allocine.js Tue Apr 03 20:30:12 2012 +0200 @@ -13,49 +13,22 @@ this.playerFns = { play : function() { - if (_this.player) { - // console.log("ask play _this.player = " + _this.player); - return _this.player.sendToActionScript("play"); - } else { - return false; - } + return _this.apiCall("play"); }, pause : function() { - if (_this.player) { - // console.log("ask pause _this.player = " + _this.player); - return _this.player.sendToActionScript("pause"); - } else { - return false; - } + return _this.apiCall("pause"); }, getPosition : function() { - if (_this.player) { - return _this.player.sendToActionScript("getSeek","return"); - } else { - return 0; - } + return _this.apiCall("getSeek","return") || 0; }, seek : function(pos) { - if (_this.player) { - return _this.player.sendToActionScript("seek",pos); - } else { - return false; - } + return _this.apiCall("seek",pos); }, getMute : function() { - if (_this.player) { - return _this.player.sendToActionScript("getMute","return"); - } else { - return false; - } + return _this.apiCall("getMute","return"); }, setMute : function(p) { - if (_this.player) { - //return p ? _this.player.sendToActionScript("setMute") : _this.player.sendToActionScript("setMute"); - _this.player.sendToActionScript("setMute"); - } else { - return false; - } + return _this.apiCall("setMute", p); } } @@ -75,12 +48,13 @@ var params = { "allowScriptAccess" : "always", "wmode": "opaque", - "flashvars" : fv + "flashvars" : fv, + "allowfullscreen" : true }; var atts = { id : this.container }; - swfobject.embedSWF(options.acPlayerUrl, this.container, options.width, options.height, "8", null, null, params, atts); + swfobject.embedSWF(options.acPlayerUrl, this.container, options.width, options.height, "10", null, null, params, atts); }; @@ -89,7 +63,6 @@ IriSP.PopcornReplacement.allocine.prototype.ready = function() { this.player = document.getElementById(this.container); this.player.addEventListener("onStateChange", "onAllocineStateChange"); - this.player.addEventListener("onVideoProgress", "onAllocineVideoProgress"); this.player.cueVideoByUrl(this._options.video); this.callbacks.onReady(); }; @@ -101,6 +74,23 @@ } +IriSP.PopcornReplacement.allocine.prototype.apiCall = function(_method, _arg) { + if (this.player) { + try { + if (typeof _arg == "undefined") { + return this.player.sendToActionScript(_method); + } else { + return this.player.sendToActionScript(_method, _arg); + } + } catch(e) { + console.error('Exception while requesting AcPlayer for "' + _method + (typeof _arg == "undefined" ? '' : '" with argument "' + _arg ) + '"\n', e); + return false; + } + } else { + return false; + } +} + IriSP.PopcornReplacement.allocine.prototype.stateHandler = function(state) { console.log("stateHandler"); switch(state) { diff -r ac66e2240e1e -r 8da49ff273e0 src/js/pop.js --- a/src/js/pop.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/pop.js Tue Apr 03 20:30:12 2012 +0200 @@ -116,11 +116,11 @@ }; IriSP.PopcornReplacement.player.prototype.pause = function() { - if ( !this.media.paused ) { +// if ( !this.media.paused ) { this.media.paused = true; this.trigger( "pause" ); this.playerFns.pause(); - } +// } }; IriSP.PopcornReplacement.player.prototype.muted = function(val) { diff -r ac66e2240e1e -r 8da49ff273e0 src/js/site.js.templ --- a/src/js/site.js.templ Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/site.js.templ Tue Apr 03 20:30:12 2012 +0200 @@ -114,7 +114,7 @@ implementers. Note that the player has to replace the variables between {{ and }} by its own values. */ - ajax_url: platform_url + "/ldtplatform/api/ldt/segments/{media}/{begin}/{end}", + ajax_url: platform_url + "/ldtplatform/api/ldt/segments/{{media}}/{{begin}}/{{end}}", ajax_granularity: 10000, /* how much ms should we look before and after the current timecode */ diff -r ac66e2240e1e -r 8da49ff273e0 src/js/widgets/annotationsListWidget.js --- a/src/js/widgets/annotationsListWidget.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/widgets/annotationsListWidget.js Tue Apr 03 20:30:12 2012 +0200 @@ -7,6 +7,7 @@ this.checkOption('project_url'); this.checkOption('default_thumbnail'); this.checkOption("cinecast_version", false); + this.checkOption("ajax_url"); this.searchRe = null; this._ajax_cache = []; var _this = this; @@ -73,7 +74,7 @@ }; IriSP.AnnotationsListWidget.prototype.transformAnnotation = function(a) { - var _this = this + var _this = this; return { "id" : a.id, "title": this.cinecast_version ? IriSP.get_aliased(a.meta, ['creator_name', 'creator']) : a.content.title, @@ -82,6 +83,7 @@ "end" : IriSP.msToTime(a.end), "thumbnail" : (typeof a.meta == "object" && typeof a.meta.thumbnail == "string") ? a.meta.thumbnail : this.default_thumbnail, "url" : (typeof a.meta == "object" && typeof a.meta.url == "string") ? a.meta.url : null, + "created_at" :(typeof a.meta == "object" && typeof a.meta.created == "string") ? Date.parse(a.meta.created.replace(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}\:\d{2}\:\d{2}).*$/,"$2/$3/$1 $4 UTC+0000")) : null, "tags": typeof a.tags == "object" ? IriSP.underscore(a.tags) .chain() @@ -140,7 +142,6 @@ this._Popcorn.trigger("IriSP.search.noMatchFound"); } } - list = IriSP.underscore(list) .chain() .sortBy(function(_o) { @@ -148,10 +149,9 @@ }) .first(10) .sortBy(function(_o) { - return _o.iterator; + return (_this.cinecast_version ? - _o.created_at : _o.iterator); }) .value(); - var idList = IriSP.underscore.pluck(list, "id").sort(); @@ -176,13 +176,11 @@ } - /* the platform gives us a special url - of the type : http://path/{media}/{begin}/{end} + /* the platform gives us a special url - of the type : http://path/{{media}}/{{begin}}/{{end}} we double the braces using regexps and we feed it to mustache to build the correct url we have to do that because the platform only knows at run time what view it's displaying. */ - var platf_url = IriSP.widgetsDefaults.AnnotationsListWidget.ajax_url - .replace(/\{/g, '{{').replace(/\}/g, '}}'); var media_id = this._serializer.currentMedia()["id"]; var duration = this._serializer.getDuration(); @@ -194,7 +192,7 @@ if (end_timecode > duration) end_timecode = duration; - var templ = Mustache.to_html(platf_url, {media: media_id, begin: begin_timecode, + var templ = Mustache.to_html(this.ajax_url, {media: media_id, begin: begin_timecode, end: end_timecode}); /* we create on the fly a serializer to get the ajax */ diff -r ac66e2240e1e -r 8da49ff273e0 src/js/widgets/createAnnotationWidget.js --- a/src/js/widgets/createAnnotationWidget.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/widgets/createAnnotationWidget.js Tue Apr 03 20:30:12 2012 +0200 @@ -13,7 +13,8 @@ "empty_annotation": "Your annotation is empty. Please write something before submitting.", "annotation_saved": "Thank you, your annotation has been saved.", "share_annotation": "Would you like to share it on social networks ?", - "share_on": "Share on" + "share_on": "Share on", + "moar_tags": "More tags" }, "fr": { "submit": "Envoyer", @@ -26,7 +27,8 @@ "empty_annotation": "Votre annotation est vide. Merci de rédiger un texte avant de l'envoyer.", "annotation_saved": "Merci, votre annotation a été enregistrée.", "share_annotation": "Souhaitez-vous la partager sur les réseaux sociaux ?", - "share_on": "Partager sur" + "share_on": "Partager sur", + "moar_tagz": "Plus de mots-clés" } } ); @@ -42,6 +44,8 @@ this.checkOption("api_endpoint_template"); this.checkOption("show_from_field", true); this.checkOption("api_method"); + this.checkOption("random_keywords"); + this.checkOption("disable_share", false); if (!IriSP.null_or_undefined(IriSP.user)) { if (!IriSP.null_or_undefined(IriSP.user.avatar)) { @@ -69,6 +73,20 @@ }; IriSP.createAnnotationWidget.prototype.draw = function() { + var _this = this; + if (typeof this._config.remote_keywords != "undefined" && typeof this._config.remote_keywords) { + IriSP.jQuery.getJSON(this._config.remote_keywords, function(_json) { + _this.keywords = IriSP.underscore(_json.tags).map(function(_tag) { + return _tag.meta.description; + }); + _this.drawCallback(); + }); + } else { + this.drawCallback(); + } +} + +IriSP.createAnnotationWidget.prototype.drawCallback = function() { var _this = this; var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_template, @@ -81,17 +99,25 @@ else { this.showStartScreen(); } - + + if (this.random_keywords) { + this.selector.find(".Ldt-createAnnotation-keywords li").hide(); + this.showMoarTagz(); + this.selector.find('.Ldt-createAnnotation-moar-keywordz').click(function() { + _this.showMoarTagz(); + }) + } // Add onclick event to both polemic and keywords buttons - this.selector.find(".Ldt-createAnnotation-btnblock button").click(function() { + this.selector.find(".Ldt-createAnnotation-keyword-button, .Ldt-createAnnotation-polemic-button").click(function() { _this.addKeyword(IriSP.jQuery(this).text()); + return false; }); // js_mod is a custom event because there's no simple way to test for a js // change in a textfield. this.selector.find(".Ldt-createAnnotation-Description") - .bind("propertychange keyup input paste js_mod", IriSP.wrap(this, this.handleTextChanges)); + .bind("propertychange keyup input paste click js_mod", IriSP.wrap(this, this.handleTextChanges)); /* the cinecast version of the player is supposed to pause when the user clicks on the button */ @@ -152,6 +178,21 @@ } }; +IriSP.createAnnotationWidget.prototype.showMoarTagz = function() { + for (var j=0; j < this.random_keywords; j++) { + var _jq = this.selector.find(".Ldt-createAnnotation-keywords li:hidden"); + if (_jq.length > 1) { + IriSP.jQuery(_jq[Math.floor(_jq.length*Math.random())]).show(); + } else { + _jq.show(); + break; + } + } + if (this.selector.find(".Ldt-createAnnotation-keywords li:hidden").length == 0) { + this.selector.find('.Ldt-createAnnotation-moar-keywordz').hide(); + } +} + /* Handles adding keywords and polemics */ IriSP.createAnnotationWidget.prototype.addKeyword = function(_keyword) { var _field = this.selector.find(".Ldt-createAnnotation-Description"), @@ -161,7 +202,7 @@ ? _contents.replace(_rx,"").replace(" "," ").trim() : _contents.trim() + " " + _keyword ); - _field.val(_contents); + _field.val(_contents.trim()); _field.trigger("js_mod"); } @@ -223,7 +264,7 @@ /** watch for changes in the textfield and change the buttons accordingly */ IriSP.createAnnotationWidget.prototype.handleTextChanges = function(event) { var contents = this.selector.find(".Ldt-createAnnotation-Description").val(); - if (this.cinecast_version && !this._Popcorn.media.paused) { + if (this.cinecast_version) { this._Popcorn.pause(); } this.selector.find(".Ldt-createAnnotation-btnblock button").each(function() { @@ -398,7 +439,17 @@ meta.created = Date().toString(); // All #hashtags are added to tags - annotation.tags = contents.match(/#[^#\s]+\b/gim) || []; + var _tags = contents.toLowerCase().match(/#[^#\s]+\b/gim) || []; + this.selector.find('.Ldt-createAnnotation-keyword-button').each(function() { + var _tx = IriSP.jQuery(this).text(), + _rx = IriSP.regexpFromText(_tx); + if (_rx.test(contents)) { + _tags.push(_tx.toLowerCase()) + } + }); + + annotation.tags = IriSP.underscore.uniq(_tags); + var jsonString = JSON.stringify(apiJson); var project_id = this._serializer._data.meta.id; @@ -436,8 +487,10 @@ annotation.meta = meta; annotation.meta["id-ref"] = json.annotations[0]["type"]; + } else { + annotation.type = "cinecast:UserAnnotation"; } - + annotation.is_new = true; // everything is shared so there's no need to propagate the change _this._serializer._data.annotations.push(annotation); diff -r ac66e2240e1e -r 8da49ff273e0 src/js/widgets/traceWidget.js --- a/src/js/widgets/traceWidget.js Fri Mar 30 18:00:26 2012 +0200 +++ b/src/js/widgets/traceWidget.js Tue Apr 03 20:30:12 2012 +0200 @@ -127,6 +127,7 @@ } this.lastEvent = _traceName; this.tracer.trace(_traceName, _arg); - console.log("trace('" + _traceName + "', " + JSON.stringify(_arg) + ");"); - + if (this._config.js_console) { + console.log("tracer.trace('" + _traceName + "', " + JSON.stringify(_arg) + ");"); + } } diff -r ac66e2240e1e -r 8da49ff273e0 src/templates/createAnnotationWidget.html --- a/src/templates/createAnnotationWidget.html Fri Mar 30 18:00:26 2012 +0200 +++ b/src/templates/createAnnotationWidget.html Tue Apr 03 20:30:12 2012 +0200 @@ -32,6 +32,9 @@ {{/keywords}} + {{#random_keywords}} + + {{/random_keywords}} {{/keywords.length}} {{#polemic_mode}} {{#polemics.length}} @@ -58,12 +61,14 @@
{{l10n.annotation_saved}}
+ {{^disable_share}} {{l10n.share_annotation}}
+ {{/disable_share}}
diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/allocine_test/AcPlayer_v3.0_new.swf Binary file test/integration/allocine_dossier_independant/allocine_test/AcPlayer_v3.0_new.swf has changed diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/allocine_test/data_cinecast_new.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/allocine_dossier_independant/allocine_test/data_cinecast_new.xml Tue Apr 03 20:30:12 2012 +0200 @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Publicité : votre vidéo commence dans | secondes]]> + + + + \ No newline at end of file diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/css/LdtPlayer.css --- a/test/integration/allocine_dossier_independant/css/LdtPlayer.css Fri Mar 30 18:00:26 2012 +0200 +++ b/test/integration/allocine_dossier_independant/css/LdtPlayer.css Tue Apr 03 20:30:12 2012 +0200 @@ -261,29 +261,67 @@ margin: 4px 2px; } -.Ldt-CtrlSound-SoundState { +.Ldt-CtrlSound-Full { background-position: -120px 0; } -.Ldt-CtrlSound-SoundState:hover { +.Ldt-CtrlSound-Full:hover { background-position: -120px -25px; } -.Ldt-CtrlSound-SoundState:active { +.Ldt-CtrlSound-Full:active { background-position: -120px -50px; } -.Ldt-CtrlSound-MuteState { +.Ldt-CtrlSound-Mute { background-position: -150px 0; } -.Ldt-CtrlSound-MuteState:hover { +.Ldt-CtrlSound-Mute:hover { background-position: -150px -25px; } -.Ldt-CtrlSound-MuteState:active { +.Ldt-CtrlSound-Mute:active { background-position: -150px -50px; } + +.Ldt-CtrlSound-Half { + background-position: -180px 0; +} + +.Ldt-CtrlSound-Half:hover { + background-position: -180px -25px; +} + +.Ldt-CtrlSound-Half:active { + background-position: -180px -50px; +} + +.Ldt-Ctrl-Volume-Control { + display: none; + position: absolute; + background:url('img-cinecast/controlbarbgd.png') repeat-x transparent ; + height: 34px; + width: 100px; top: 30px; right: 0; z-index: 100; + padding: 0 2px; +} + +.Ldt-Ctrl-Volume-Bar { + height: 5px; margin: 13px 3px 0; background: #cccccc; border: 1px solid #999999; border-radius: 2px; +} + +.Ldt-Ctrl-Volume-Cursor { + position: absolute; top: 6px; width: 6px; height: 19px; background: #a8a8a8; border: 1px solid #999999; border-radius: 2px; + cursor: pointer; +} + +.Ldt-Ctrl-Volume-Cursor:hover { + background: #cccccc; +} + +.Ldt-Ctrl-Volume-Cursor.ui-draggable-dragging { + background: #999999; +} .Ldt-cleaner { clear:both; @@ -451,6 +489,7 @@ .Ldt-createAnnotationWidget { width: 610px; padding-bottom: 10px; clear: both; + color: #fff; background: url(img-cinecast/createannbgd.png) no-repeat bottom right; } @@ -512,23 +551,26 @@ /* */ .Ldt-createAnnotation-btnblock { - float: left; width: 480px; margin: 5px 0; } .Ldt-createAnnotation-btnblock label { - float: left; margin-top: 8px; width: 120px; font-size: 12px; height: 20px; color: #ffffff; + float: left; margin-top: 20px; width: 480px; font-size: 14px; color: #ffffff; } /* CINECAST SPECIFIC TAG BUTTONS */ +.Ldt-createAnnotation-keywords ul { + width: 100%; clear: both; +} + .Ldt-createAnnotation-keywords li { - border: none; margin: 5px 10px 0 0; height: 23px; padding: 0 0 0 15px; + border: none; margin: 0 10px 5px 0; height: 23px; padding: 0 0 0 15px; background: url(img-cinecast/tag.png) left top no-repeat; cursor: pointer; } .Ldt-createAnnotation-keyword-button { - font-size: 13px; color: #ffffff; width: 95px; + font-size: 13px; color: #ffffff; width: 170px; text-shadow: 1px 1px 1px #000000; height: 23px; padding: 0 5px 0 0; border: none; margin: 0; background: url(img-cinecast/tag.png) right top no-repeat; cursor: pointer; @@ -543,11 +585,11 @@ } .Ldt-createAnnotation-keywords li.Ldt-createAnnotation-active-button { - background-position: left -46px; margin: 5px 0 0 0; + background-position: left -46px; margin: 0 0 5px 0; } .Ldt-createAnnotation-keywords li.Ldt-createAnnotation-active-button .Ldt-createAnnotation-keyword-button { - background-position: right -46px; padding: 0 15px 0 0; width: 105px; + background-position: right -46px; padding: 0 15px 0 0; width: 180px; } /* */ @@ -692,12 +734,21 @@ } .Ldt-AnnotationsList-Tag-Div { - font-size: 13px; color: #ffffff; + font-size: 13px; color: #ffffff; text-shadow: 1px 1px 1px #000000; height: 19px; padding: 4px 5px 0 0; border: none; margin: 0; background: url(img-cinecast/tag.png) right top no-repeat; cursor: pointer; } +.Ldt-createAnnotation-moar-keywordz { + float: right; font-size: 13px; color: #ffffff; text-shadow: 1px 1px 1px #000000; + width: 140px; height: 23px; background: url(img-cinecast/moar.png); border: none; margin: 0 15px; +} + +.Ldt-createAnnotation-moar-keywordz:hover { + background-position: bottom; +} + /* Tagcloud */ .Ldt-TagCloud { diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/css/img-cinecast/createannbgd.png Binary file test/integration/allocine_dossier_independant/css/img-cinecast/createannbgd.png has changed diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/css/img-cinecast/moar.png Binary file test/integration/allocine_dossier_independant/css/img-cinecast/moar.png has changed diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/css/img-cinecast/tag.png Binary file test/integration/allocine_dossier_independant/css/img-cinecast/tag.png has changed diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/js/LdtPlayer-release.js --- a/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js Fri Mar 30 18:00:26 2012 +0200 +++ b/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js Tue Apr 03 20:30:12 2012 +0200 @@ -1091,10 +1091,11 @@ IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}
 
Chargement...
"; IriSP.annotationsListWidget_template = "{{! template for the annotation list widget }}
"; IriSP.arrowWidget_template = "
"; -IriSP.createAnnotationWidget_template = "{{! template for the annotation creation widget }}
{{^cinecast_version}}
{{/cinecast_version}}
{{#show_from_field}} {{/show_from_field}}
{{^user_avatar}} {{/user_avatar}} {{#user_avatar}} {{/user_avatar}}
{{#keywords.length}}
    {{#keywords}}
  • {{/keywords}}
{{/keywords.length}} {{#polemic_mode}} {{#polemics.length}}
    {{#polemics}}
  • {{/polemics}}
{{/polemics.length}} {{/polemic_mode}}
"; +IriSP.createAnnotationWidget_template = "{{! template for the annotation creation widget }}
{{^cinecast_version}}
{{/cinecast_version}}
{{#show_from_field}} {{/show_from_field}}
{{^user_avatar}} {{/user_avatar}} {{#user_avatar}} {{/user_avatar}}
{{#keywords.length}}
    {{#keywords}}
  • {{/keywords}}
{{#random_keywords}} {{/random_keywords}} {{/keywords.length}} {{#polemic_mode}} {{#polemics.length}}
    {{#polemics}}
  • {{/polemics}}
{{/polemics.length}} {{/polemic_mode}}
"; IriSP.createAnnotation_errorMessage_template = "

{{l10n.empty_annotation}}

"; +IriSP.loading_template = "
{{l10n.loading_wait}}
"; 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 }}
{{^disable_annotate_btn}}
{{/disable_annotate_btn}} {{^disable_search_btn}}
{{/disable_search_btn}}
00:00
/
00:00
"; +IriSP.player_template = "{{! template for the radio player }}
{{^disable_annotate_btn}}
{{/disable_annotate_btn}} {{^disable_search_btn}}
{{/disable_search_btn}}
00:00
/
00:00
"; IriSP.search_template = "{{! template for the search container }}
"; IriSP.share_template = "{{! social network sharing template }}       "; IriSP.sliceWidget_template = "{{! template for the slice widget }}
{{! the whole bar }}
{{! the zone which represents our slice }}
"; @@ -1216,7 +1217,7 @@ /* shortcut to have global variables in templates */ IriSP.templToHTML = function(template, values) { - var params = IriSP.jQuery.extend( + var params = IriSP.underscore.extend( { "defaults" : IriSP.default_templates_vars, "l10n" : IriSP.i18n.getMessages() }, @@ -1423,11 +1424,11 @@ }; IriSP.PopcornReplacement.player.prototype.pause = function() { - if ( !this.media.paused ) { +// if ( !this.media.paused ) { this.media.paused = true; this.trigger( "pause" ); this.playerFns.pause(); - } +// } }; IriSP.PopcornReplacement.player.prototype.muted = function(val) { @@ -1451,6 +1452,22 @@ } }; +IriSP.PopcornReplacement.player.prototype.volume = function(val) { + if (typeof this.playerFns.getVolume == "undefined" || typeof this.playerFns.setVolume == "undefined") { + return false; + } + var _vol = this.playerFns.getVolume(); + if (typeof(val) !== "undefined" && parseFloat(val) !== NaN) { + val = Math.max(0, Math.min(1, val)); + if (parseFloat(val) != parseFloat(_vol)) { + this.playerFns.setVolume(val); + this.trigger("volumechange"); + _vol = this.playerFns.getVolume(); + } + } + return _vol; +}; + IriSP.PopcornReplacement.player.prototype.mute = IriSP.PopcornReplacement.player.prototype.muted; IriSP.PopcornReplacement.player.prototype.code = function(options) { @@ -1918,7 +1935,10 @@ /* this is a shortcut */ this.selector = IriSP.jQuery("#" + this._div); - this.selector.css("width", this._width); + this.selector.css({ + "width": this._width, + "clear": "both" + }); if (this._height !== undefined) this.selector.css("height", this._height); @@ -1948,7 +1968,7 @@ var spacerDiv = IriSP.guid("LdtPlayer_spacer_"); this._widgets.push([widgetName, newDiv]); - var divTempl = "
1) { + IriSP.jQuery(_jq[Math.floor(_jq.length*Math.random())]).show(); + } else { + _jq.show(); + break; + } + } + if (this.selector.find(".Ldt-createAnnotation-keywords li:hidden").length == 0) { + this.selector.find('.Ldt-createAnnotation-moar-keywordz').hide(); + } +} + /* Handles adding keywords and polemics */ IriSP.createAnnotationWidget.prototype.addKeyword = function(_keyword) { var _field = this.selector.find(".Ldt-createAnnotation-Description"), @@ -3389,7 +3463,7 @@ ? _contents.replace(_rx,"").replace(" "," ").trim() : _contents.trim() + " " + _keyword ); - _field.val(_contents); + _field.val(_contents.trim()); _field.trigger("js_mod"); } @@ -3451,7 +3525,7 @@ /** watch for changes in the textfield and change the buttons accordingly */ IriSP.createAnnotationWidget.prototype.handleTextChanges = function(event) { var contents = this.selector.find(".Ldt-createAnnotation-Description").val(); - if (this.cinecast_version && !this._Popcorn.media.paused) { + if (this.cinecast_version) { this._Popcorn.pause(); } this.selector.find(".Ldt-createAnnotation-btnblock button").each(function() { @@ -3626,7 +3700,17 @@ meta.created = Date().toString(); // All #hashtags are added to tags - annotation.tags = contents.match(/#[^#\s]+\b/gim) || []; + var _tags = contents.toLowerCase().match(/#[^#\s]+\b/gim) || []; + this.selector.find('.Ldt-createAnnotation-keyword-button').each(function() { + var _tx = IriSP.jQuery(this).text(), + _rx = IriSP.regexpFromText(_tx); + if (_rx.test(contents)) { + _tags.push(_tx.toLowerCase()) + } + }); + + annotation.tags = IriSP.underscore.uniq(_tags); + var jsonString = JSON.stringify(apiJson); var project_id = this._serializer._data.meta.id; @@ -3643,9 +3727,9 @@ //dataType: 'json', success: IriSP.wrap(this, function(json, textStatus, XMLHttpRequest) { /* add the annotation to the annotation and tell the world */ - if (this.cinecast_version) { - var annotation = json.annotations[0]; - } else { + var annotation = json.annotations[0]; + + if (!this.cinecast_version) { /* if the media doesn't have a contributions line, we need to add one */ if (typeof(this._serializer.getContributions()) === "undefined") { /* set up a basic view */ @@ -3664,8 +3748,10 @@ annotation.meta = meta; annotation.meta["id-ref"] = json.annotations[0]["type"]; + } else { + annotation.type = "cinecast:UserAnnotation"; } - + annotation.is_new = true; // everything is shared so there's no need to propagate the change _this._serializer._data.annotations.push(annotation); @@ -3708,7 +3794,9 @@ "annotate": "Annotate", "search": "Search", "elapsed_time": "Elapsed time", - "total_time": "Total time" + "total_time": "Total time", + "volume": "Volume", + "volume_control": "Volume control" }, "fr": { "play_pause": "Lecture/Pause", @@ -3720,7 +3808,9 @@ "annotate": "Annoter", "search": "Rechercher", "elapsed_time": "Durée écoulée", - "total_time": "Durée totale" + "total_time": "Durée totale", + "volume": "Niveau sonore", + "volume_control": "Réglage du niveau sonore" } } ); @@ -3750,7 +3840,7 @@ 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("volumechange", IriSP.wrap(this, this.volumeUpdater)); this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater)); // update the time display for the first time. @@ -3766,7 +3856,20 @@ { self._Popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked"); }); this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); }); - this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } ); + var _volctrl = this.selector.find(".Ldt-Ctrl-Volume-Control"); + this.selector.find('.Ldt-CtrlSound') + .click(function() { self.muteHandler.call(self); } ) + .mouseover(function() { + _volctrl.show(); + }) + .mouseout(function() { + _volctrl.hide(); + }); + _volctrl.mouseover(function() { + _volctrl.show(); + }).mouseout(function() { + _volctrl.hide(); + }); /* var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position(); @@ -3777,8 +3880,19 @@ // 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.selector.find(".Ldt-Ctrl-Volume-Cursor").draggable({ + axis: "x", + drag: function(event, ui) { + var _vol = Math.max(0, Math.min( 1, ui.position.left / (ui.helper.parent().width() - ui.helper.outerWidth()))); + ui.helper.attr("title",IriSP.i18n.getMessage('volume')+': ' + Math.floor(100*_vol) + '%'); + self._Popcorn.volume(_vol); + }, + containment: "parent" + }); - this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */ + setTimeout(function() { + self.volumeUpdater(); + }, 1000); /* some player - jwplayer notable - save the state of the mute button between sessions */ }; /* Update the elasped time div */ @@ -3835,25 +3949,28 @@ }; IriSP.PlayerWidget.prototype.muteHandler = function() { - if (!this._Popcorn.muted()) { - this._Popcorn.mute(true); - } else { - this._Popcorn.mute(false); + this._Popcorn.mute(!this._Popcorn.muted()); +}; + +IriSP.PlayerWidget.prototype.volumeUpdater = function() { + var _muted = this._Popcorn.muted(), + _vol = this._Popcorn.volume(); + if (_vol === false) { + _vol = .5; } -}; - -IriSP.PlayerWidget.prototype.muteButtonUpdater = function() { - var status = this._Popcorn.media.muted; - - if ( status == true ){ - this.selector.find(".Ldt-CtrlSound").attr("title", IriSP.i18n.getMessage('unmute')); - this.selector.find(".Ldt-CtrlSound").removeClass("Ldt-CtrlSound-MuteState").addClass("Ldt-CtrlSound-SoundState"); - } else { - this.selector.find(".Ldt-CtrlSound").attr("title", IriSP.i18n.getMessage('mute')); - this.selector.find(".Ldt-CtrlSound").removeClass("Ldt-CtrlSound-SoundState").addClass("Ldt-CtrlSound-MuteState"); - } - - return; + var _soundCtl = this.selector.find(".Ldt-CtrlSound"); + _soundCtl.removeClass("Ldt-CtrlSound-Mute Ldt-CtrlSound-Half Ldt-CtrlSound-Full"); + if (_muted) { + _soundCtl.attr("title", IriSP.i18n.getMessage('unmute')) + .addClass("Ldt-CtrlSound-Mute"); + } else { + _soundCtl.attr("title", IriSP.i18n.getMessage('mute')) + .addClass(_vol < .5 ? "Ldt-CtrlSound-Half" : "Ldt-CtrlSound-Full" ) + } + var _cursor = this.selector.find(".Ldt-Ctrl-Volume-Cursor"); + _cursor.css({ + "left": ( _muted ? 0 : Math.floor(_vol * (_cursor.parent().width() - _cursor.outerWidth())) ) + "px" + }) }; IriSP.PlayerWidget.prototype.showSearchBlock = function() { @@ -4956,7 +5073,6 @@ this.selector.css("background", this._config.background); } this.checkOption('cinecast_version'); - console.log('Cinecast', this.cinecast_version); }; @@ -4988,7 +5104,7 @@ // If we've found the correct view, feed the directly the data from the view // to jquery sparkline. Otherwise, compute it ourselves. if (!IriSP.null_or_undefined(stat_view)) { - console.log("sparklinewidget : using stats embedded in the json"); + //console.log("sparklinewidget : using stats embedded in the json"); var _results = stat_view.meta.stat.split(","); } else { var _annotations = this._serializer._data.annotations, @@ -5588,8 +5704,9 @@ } this.lastEvent = _traceName; this.tracer.trace(_traceName, _arg); - console.log("trace('" + _traceName + "', " + JSON.stringify(_arg) + ");"); - + if (this._config.js_console) { + console.log("tracer.trace('" + _traceName + "', " + JSON.stringify(_arg) + ");"); + } } /* a widget that displays tweet - used in conjunction with the polemicWidget */ diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/js/libs/tracemanager.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/integration/allocine_dossier_independant/js/libs/tracemanager.js Tue Apr 03 20:30:12 2012 +0200 @@ -0,0 +1,512 @@ +/* + * Modelled Trace API + */ +IriSP.TraceManager = function($) { + // If there are more than MAX_FAILURE_COUNT synchronisation + // failures, then disable synchronisation + MAX_FAILURE_COUNT = 20; + + // If there are more than MAX_BUFFER_SIZE obsels in the buffer, + // then "compress" them as a single "ktbsFullBuffer" + MAX_BUFFER_SIZE = 500; + + var BufferedService_prototype = { + /* + * Buffered service for traces + */ + // url: "", + // buffer: [], + // isReady: false, + // timer: null, + // failureCount: 0, + + /* Flush buffer */ + flush: function() { + // FIXME: add mutex on this.buffer + if (! this.isReady) + { + if (window.console) window.console.log("Sync service not ready"); + } else if (this.failureCount > MAX_FAILURE_COUNT) + { + // Disable synchronisation + this.set_sync_mode('none'); + } else if (this.buffer.length) { + var temp = this.buffer; + this.buffer = []; + + if (this.mode == 'GET') + { + // GET mode: do some data mangline. We mark the + // "compressed" nature of the generated JSON by + // prefixing it with c + var data = 'c' + JSON.stringify(temp.map(function (o) { return o.toCompactJSON(); })); + // Swap " (very frequent, which will be + // serialized into %22) and ; (rather rare), this + // saves some bytes + data = data.replace(/[;"]/g, function(s){ return s == ';' ? '"' : ';'; }).replace(/#/g, '%23'); + // FIXME: check data length (< 2K is safe) + var request=$('').error( function() { this.failureCount += 1; }) + .load( function() { this.failureCount = 0; }) + .attr('src', this.url + 'trace/?data=' + data); + } + else + { + $.ajax({ url: this.url + 'trace/', + type: 'POST', + contentType: 'application/json', + data: JSON.stringify(temp.map(function (o) { return o.toJSON(); })), + processData: false, + // Type of the returned data. + dataType: "html", + error: function(jqXHR, textStatus, errorThrown) { + if (window.console) window.console.log("Error when sending buffer:", textStatus); + this.failureCount += 1; + }, + success: function(data, textStatus, jqXHR) { + // Reset failureCount to 0 as soon as there is 1 valid answer + this.failureCount = 0; + } + }); + } + } + }, + + /* Sync mode: delayed, sync (immediate sync), none (no + * synchronisation with server, the trace has to be explicitly saved + * if needed */ + set_sync_mode: function(mode) { + this.sync_mode = mode; + if (! this.isReady && mode !== "none") + this.init(); + if (mode == 'delayed') { + this.start_timer(); + } else { + this.stop_timer(); + } + }, + + /* Enqueue an obsel */ + enqueue: function(obsel) { + if (this.buffer.length > MAX_BUFFER_SIZE) + { + obsel = new Obsel('ktbsFullBuffer', this.buffer[0].begin, + this.buffer[this.buffer.length - 1].end, this.buffer[0].subject); + obsel.trace = this.buffer[0].trace; + this.buffer = []; + } + this.buffer.push(obsel); + if (this.sync_mode === 'sync') { + // Immediate sync of the obsel. + this.flush(); + } + }, + + start_timer: function() { + var self = this; + if (this.timer === null) { + this.timer = window.setInterval(function() { + self.flush(); + }, this.timeOut); + } + }, + + stop_timer: function() { + if (this.timer !== null) { + window.clearInterval(this.timer); + this.timer = null; + } + }, + + /* + * Initialize the sync service + */ + init: function() { + var self = this; + if (this.isReady) + /* Already initialized */ + return; + if (this.mode == 'GET') + { + var request=$('').attr('src', this.url + 'login?userinfo={"name":"ktbs4js"}'); + // Do not wait for the return, assume it is + // initialized. This assumption will not work anymore + // if login returns some necessary information + this.isReady = true; + } + else + { + $.ajax({ url: this.url + 'login', + type: 'POST', + data: 'userinfo={"name":"ktbs4js"}', + success: function(data, textStatus, jqXHR) { + self.isReady = true; + if (self.buffer.length) { + self.flush(); + } + } + }); + } + } + }; + var BufferedService = function(url, mode) { + this.url = url; + this.buffer = []; + this.isReady = false; + this.timer = null; + this.failureCount = 0; + // sync_mode is either "none", "sync" or "buffered" + this.sync_mode = "none"; + /* mode can be either POST or GET */ + if (mode == 'POST' || mode == 'GET') + this.mode = mode; + else + this.mode = 'POST'; + /* Flush buffer every timeOut ms if the sync_mode is delayed */ + this.timeOut = 2000; + }; + BufferedService.prototype = BufferedService_prototype; + + var Trace_prototype = { + /* FIXME: We could/should use a sorted list such as + http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html + to speed up queries based on time */ + obsels: [], + /* Trace URI */ + uri: "", + default_subject: "", + /* baseuri is used as the base URI to resolve relative + * attribute-type names in obsels. Strictly speaking, this + * should rather be expressed as a reference to model, or + * more generically, as a qname/URI dict */ + baseuri: "", + /* Mapping of obsel type or property name to a compact + * representation (shorthands). + */ + shorthands: null, + syncservice: null, + + /* Define the trace URI */ + set_uri: function(uri) { + this.uri = uri; + }, + + /* Sync mode: delayed, sync (immediate sync), none (no + * synchronisation with server, the trace has to be explicitly saved + * if needed */ + set_sync_mode: function(mode) { + if (this.syncservice !== null) { + this.syncservice.set_sync_mode(mode); + } + }, + + /* + * Return a list of the obsels of this trace matching the parameters + */ + list_obsels: function(_begin, _end, _reverse) { + var res; + if (typeof _begin !== 'undefined' || typeof _end !== 'undefined') { + /* + * Not optimized yet. + */ + res = []; + var l = this.obsels.length; + for (var i = 0; i < l; i++) { + var o = this.obsels[i]; + if ((typeof _begin !== 'undefined' && o.begin > _begin) && (typeof _end !== 'undefined' && o.end < _end)) { + res.push(o); + } + } + } + + if (typeof _reverse !== 'undefined') { + if (res !== undefined) { + /* Should reverse the whole list. Make a copy. */ + res = this.obsels.slice(0); + } + res.sort(function(a, b) { return b.begin - a.begin; }); + return res; + } + + if (res === undefined) { + res = this.obsels; + } + return res; + + }, + + /* + * Return the obsel of this trace identified by the URI, or undefined + */ + get_obsel: function(id) { + for (var i = 0; i < this.obsels.length; i++) { + /* FIXME: should check against variations of id/uri, take this.baseuri into account */ + if (this.obsels[i].uri === id) { + return this.obsels[i]; + } + } + return undefined; + }, + + set_default_subject: function(subject) { + this.default_subject = subject; + }, + + get_default_subject: function() { + return this.default_subject; + }, + + /* (type:ObselType, begin:int, end:int?, subject:str?, attributes:[AttributeType=>any]?) */ + /* Create a new obsel and add it to the trace */ + create_obsel: function(type, begin, end, subject, _attributes) { + var o = new Obsel(type, begin, end, subject); + if (typeof _attributes !== 'undefined') { + o.attributes = _attributes; + } + o.trace = this; + this.obsels.push(o); + if (this.syncservice !== null) + this.syncservice.enqueue(o); + }, + + /* Helper methods */ + + /* Create a new obsel with the given attributes */ + trace: function(type, _attributes, _begin, _end, _subject) { + var t = (new Date()).getTime(); + if (typeof begin === 'undefined') { + _begin = t; + } + if (typeof end === 'undefined') { + _end = _begin; + } + if (typeof subject === 'undefined') { + _subject = this.default_subject; + } + if (typeof _attributes === 'undefined') { + _attributes = {}; + } + return this.create_obsel(type, _begin, _end, _subject, _attributes); + } + }; + + var Trace = function(uri, requestmode) { + /* FIXME: We could/should use a sorted list such as + http://closure-library.googlecode.com/svn/docs/class_goog_structs_AvlTree.html + to speed up queries based on time */ + this.obsels = []; + /* Trace URI */ + if (uri === undefined) + uri = ""; + this.uri = uri; + this.sync_mode = "none"; + this.default_subject = ""; + this.shorthands = {}; + /* baseuri is used a the base URI to resolve relative attribute names in obsels */ + this.baseuri = ""; + + this.syncservice = new BufferedService(uri, requestmode); + $(window).unload( function () { + if (this.syncservice && this.sync_mode !== 'none') { + this.syncservice.flush(); + this.syncservice.stop_timer(); + } + }); + }; + Trace.prototype = Trace_prototype; + + var Obsel_prototype = { + /* The following attributes are here for documentation + * purposes. They MUST be defined in the constructor + * function. */ + trace: undefined, + type: undefined, + begin: undefined, + end: undefined, + subject: undefined, + /* Dictionary indexed by ObselType URIs */ + attributes: {}, + + /* Method definitions */ + get_trace: function() { + return this.trace; + }, + + get_obsel_type: function() { + return this.type; + }, + get_begin: function() { + return this.begin; + }, + get_end: function() { + return this.end; + }, + get_subject: function() { + return this.subject; + }, + + list_attribute_types: function() { + var result = []; + for (var prop in this.attributes) { + if (this.hasOwnProperty(prop)) + result.push(prop); + } + /* FIXME: we return URIs here instead of AttributeType elements */ + return result; + }, + + list_relation_types: function() { + /* FIXME: not implemented yet */ + }, + + list_related_obsels: function (rt) { + /* FIXME: not implemented yet */ + }, + list_inverse_relation_types: function () { + /* FIXME: not implemented yet */ + }, + list_relating_obsels: function (rt) { + /* FIXME: not implemented yet */ + }, + /* + * Return the value of the given attribute type for this obsel + */ + get_attribute_value: function(at) { + if (typeof at === "string") + /* It is a URI */ + return this.attributes[at]; + else + /* FIXME: check that at is instance of AttributeType */ + return this.attributes[at.uri]; + }, + + + /* obsel modification (trace amendment) */ + + set_attribute_value: function(at, value) { + if (typeof at === "string") + /* It is a URI */ + this.attributes[at] = value; + /* FIXME: check that at is instance of AttributeType */ + else + this.attributes[at.uri] = value; + }, + + del_attribute_value: function(at) { + if (typeof at === "string") + /* It is a URI */ + delete this.attributes[at]; + /* FIXME: check that at is instance of AttributeType */ + else + delete this.attributes[at.uri]; + }, + + add_related_obsel: function(rt, value) { + /* FIXME: not implemented yet */ + }, + + del_related_obsel: function(rt, value) { + /* FIXME: not implemented yet */ + }, + + /* + * Return a JSON representation of the obsel + */ + toJSON: function() { + var r = { + "@id": this.id, + "@type": this.type, + "begin": this.begin, + "end": this.end, + "subject": this.subject + }; + for (var prop in this.attributes) { + if (this.hasOwnProperty(prop)) + r[prop] = this.attributes[prop]; + } + return r; + }, + + /* + * Return a compact JSON representation of the obsel. + * Use predefined + custom shorthands for types/properties + */ + toCompactJSON: function() { + var r = { + "@i": this.id, + "@t": (this.trace.shorthands.hasOwnProperty(this.type) ? this.trace.shorthands[this.type] : this.type), + "@b": this.begin, + "@s": this.subject + }; + // Store duration (to save some bytes) and only if it is non-null + if (this.begin !== this.end) + r["@d"] = this.end - this.begin; + + for (var prop in this.attributes) { + if (this.hasOwnProperty(prop)) + { + var v = this.attributes[prop]; + r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v; + } + } + return r; + }, + + toJSONstring: function() { + return JSON.stringify(this.toJSON()); + } + }; + + var Obsel = function(type, begin, end, subject, attributes) { + this.trace = undefined; + this.uri = ""; + this.id = ""; + this.type = type; + this.begin = begin; + this.end = end; + this.subject = subject; + /* Is the obsel synched with the server ? */ + this.sync_status = false; + /* Dictionary indexed by ObselType URIs */ + this.attributes = {}; + }; + Obsel.prototype = Obsel_prototype; + + var TraceManager_prototype = { + traces: [], + /* + * Return the trace with id name + * If it was not registered, return undefined. + */ + get_trace: function(name) { + return this.traces[name]; + }, + + /* + * Explicitly create and initialize a new trace with the given name. + * The optional uri parameter allows to initialize the trace URI. + * + * If another existed with the same name before, then it is replaced by a new one. + */ + init_trace: function(name, params) + { + if (window.console) window.console.log("init_trace", params); + url = params.url ? params.url : ""; + requestmode = params.requestmode ? params.requestmode : "POST"; + syncmode = params.syncmode ? params.syncmode : "none"; + default_subject = params.default_subject ? params.default_subject : "default"; + var t = new Trace(url, requestmode); + t.set_sync_mode(syncmode); + t.set_default_subject(default_subject); + this.traces[name] = t; + return t; + } + }; + + var TraceManager = function() { + this.traces = {}; + }; + TraceManager.prototype = TraceManager_prototype; + + var tracemanager = new TraceManager(); + return tracemanager; + }; diff -r ac66e2240e1e -r 8da49ff273e0 test/integration/allocine_dossier_independant/polemic-allocine.htm --- a/test/integration/allocine_dossier_independant/polemic-allocine.htm Fri Mar 30 18:00:26 2012 +0200 +++ b/test/integration/allocine_dossier_independant/polemic-allocine.htm Tue Apr 03 20:30:12 2012 +0200 @@ -21,7 +21,7 @@ name : 'awesome_user_name', avatar : 'allocine_test/avatar.png' }; - IriSP.libdir = "/metadataplayer/src/js/libs/"; + IriSP.libdir = "js/libs/"; IriSP.defaults.user = function() { return IriSP.user; }; @@ -50,12 +50,6 @@ lineColor: "#ffffff", fillColor: "#999999" }, { - type : "SliderWidget" - }, { - type : "PlayerWidget", - disable_annotate_btn : true, - disable_search_btn : true - }, { type : "SegmentsWidget", requires : [{ type : "TooltipWidget", @@ -65,23 +59,26 @@ }, { type : "createAnnotationWidget", polemic_mode : false, - keywords : ['#vodkaster', '#allocine', '#universcine', '#FauxRaccord', '#SceneCulte', '#navet'], + remote_keywords : 'http://festival.cinecast.fr/configuration.jsonp?jsonp=?', + random_keywords : 3, + disable_share: true, api_endpoint_template : "coucou/{{id}}.json", api_method : 'POST' }, { type: "TraceWidget", - url: "http://192.168.56.101:5000/", + // js_console : true, + url: "http://traces.advene.org:5000/", requestmode: 'GET', syncmode: "sync" - }] + } ] }, player : { type : 'allocine', // player type height : 300, width : 610, - acPlayerUrl : "allocine_test/AcPlayer_v3.0.swf", - autoPlay : "false", - urlAcData : "allocine_test/data_cinecast.xml" + acPlayerUrl : "allocine_test/AcPlayer_v3.0_new.swf", + autoPlay : "true", + urlAcData : "allocine_test/data_cinecast_new.xml" }, modules : [{ type : "MediaFragment",