Tracemanager changes
authorveltr
Fri, 11 May 2012 16:07:52 +0200
changeset 899 445631dffdf8
parent 897 94fea76c883e
child 901 12b2cd7e9159
Tracemanager changes
src/js/libs/tracemanager.js
test/integration/allocine_dossier_independant/js/LdtPlayer-release.js
test/integration/allocine_dossier_independant/js/libs/tracemanager.js
test/integration/allocine_dossier_independant/test-allocine.htm
--- a/src/js/libs/tracemanager.js	Fri May 11 16:04:53 2012 +0200
+++ b/src/js/libs/tracemanager.js	Fri May 11 16:07:52 2012 +0200
@@ -12,8 +12,8 @@
 
      var BufferedService_prototype = {
          /*
-          *  Buffered service for traces
-          */
+* Buffered service for traces
+*/
          // url: "",
          // buffer: [],
          // isReady: false,
@@ -43,7 +43,7 @@
                      // 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');
+                     data = data.replace(/[;"#]/g, function(s){ return s == ';' ? '"' : ( s == '"' ? ';' : '%23'); });
                      // FIXME: check data length (< 2K is safe)
                      var request=$('<img />').error( function() { this.failureCount += 1; })
                          .load( function() { this.failureCount = 0; })
@@ -72,12 +72,12 @@
          },
 
          /* 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) {
+* synchronisation with server, the trace has to be explicitly saved
+* if needed */
+         set_sync_mode: function(mode, default_subject) {
              this.sync_mode = mode;
              if (! this.isReady && mode !== "none")
-                 this.init();
+                 this.init(default_subject);
              if (mode == 'delayed') {
                  this.start_timer();
              } else {
@@ -118,16 +118,18 @@
          },
 
          /*
-          * Initialize the sync service
-          */
-         init: function() {
+* Initialize the sync service
+*/
+         init: function(default_subject) {
              var self = this;
              if (this.isReady)
                  /* Already initialized */
                  return;
+             if (typeof default_subject === 'undefined')
+                 default_subject = 'anonymous';
              if (this.mode == 'GET')
              {
-                 var request=$('<img/>').attr('src', this.url + 'login?userinfo={"name":"ktbs4js"}');
+                 var request=$('<img/>').attr('src', this.url + 'login?userinfo={"default_subject": "' + default_subject + '"}');
                  // Do not wait for the return, assume it is
                  // initialized. This assumption will not work anymore
                  // if login returns some necessary information
@@ -137,7 +139,7 @@
              {
                  $.ajax({ url: this.url + 'login',
                           type: 'POST',
-                          data: 'userinfo={"name":"ktbs4js"}',
+                          data: 'userinfo={"default_subject":"' + default_subject + '"}',
                           success: function(data, textStatus, jqXHR) {
                               self.isReady = true;
                               if (self.buffer.length) {
@@ -168,20 +170,20 @@
 
      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 */
+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 */
+* 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).
-          */
+* representation (shorthands).
+*/
          shorthands: null,
          syncservice: null,
 
@@ -191,23 +193,23 @@
          },
 
          /* Sync mode: delayed, sync (immediate sync), none (no
-          * synchronisation with server, the trace has to be explicitly saved
-          * if needed */
+* 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);
+                 this.syncservice.set_sync_mode(mode, this.default_subject);
              }
          },
 
          /*
-          * Return a list of the obsels of this trace matching the parameters
-          */
+* 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.
-                  */
+* Not optimized yet.
+*/
                  res = [];
                  var l = this.obsels.length;
                  for (var i = 0; i < l; i++) {
@@ -235,8 +237,8 @@
          },
 
          /*
-          * Return the obsel of this trace identified by the URI, or undefined
-          */
+* 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 */
@@ -248,6 +250,9 @@
          },
 
          set_default_subject: function(subject) {
+             // FIXME: if we call this method after the sync_service
+             // init method, then the default_subject will not be
+             // consistent anymore. Maybe we should then call init() again?
              this.default_subject = subject;
          },
 
@@ -291,8 +296,8 @@
 
      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 */
+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)
@@ -316,8 +321,8 @@
 
      var Obsel_prototype = {
          /* The following attributes are here for documentation
-          * purposes. They MUST be defined in the constructor
-          * function. */
+* purposes. They MUST be defined in the constructor
+* function. */
          trace: undefined,
          type: undefined,
          begin: undefined,
@@ -347,7 +352,7 @@
          list_attribute_types: function() {
              var result = [];
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                      result.push(prop);
              }
              /* FIXME: we return URIs here instead of AttributeType elements */
@@ -368,8 +373,8 @@
              /* FIXME: not implemented yet */
          },
          /*
-          * Return the value of the given attribute type for this obsel
-          */
+* Return the value of the given attribute type for this obsel
+*/
          get_attribute_value: function(at) {
              if (typeof at === "string")
                  /* It is a URI */
@@ -409,8 +414,8 @@
          },
 
          /*
-          * Return a JSON representation of the obsel
-          */
+* Return a JSON representation of the obsel
+*/
          toJSON: function() {
              var r = {
                  "@id": this.id,
@@ -420,29 +425,35 @@
                  "subject": this.subject
              };
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                      r[prop] = this.attributes[prop];
              }
              return r;
          },
 
          /*
-          * Return a compact JSON representation of the obsel.
-          * Use predefined + custom shorthands for types/properties
-          */
+* 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
              };
+             // Transmit subject only if different from default_subject
+             if (this.subject !== this.trace.default_subject)
+                 r["@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;
 
+             // Store id only if != ""
+             if (this.id !== "")
+                 r["@i"] = this.id;
+
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                  {
                      var v = this.attributes[prop];
                      r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
@@ -474,19 +485,19 @@
      var TraceManager_prototype = {
          traces: [],
          /*
-          * Return the trace with id name
-          * If it was not registered, return undefined.
-          */
+* 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.
-          */
+* 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);
@@ -495,8 +506,8 @@
              syncmode = params.syncmode ? params.syncmode : "none";
              default_subject = params.default_subject ? params.default_subject : "default";
              var t = new Trace(url, requestmode);
+             t.set_default_subject(default_subject);
              t.set_sync_mode(syncmode);
-             t.set_default_subject(default_subject);
              this.traces[name] = t;
              return t;
          }
@@ -507,6 +518,6 @@
      };
      TraceManager.prototype = TraceManager_prototype;
 
-     var tracemanager  = new TraceManager();
+     var tracemanager = new TraceManager();
      return tracemanager;
  };
--- a/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js	Fri May 11 16:04:53 2012 +0200
+++ b/test/integration/allocine_dossier_independant/js/LdtPlayer-release.js	Fri May 11 16:07:52 2012 +0200
@@ -1115,7 +1115,7 @@
 IriSP.search_template = "{{! template for the search container }}<div class='LdtSearchContainer'	style='margin-left: {{margin_left}}; position: absolute; margin-top: -60px;'>	<div class='LdtSearch'		style='display: none; background-color: #EEE; width: 165px; border-color: #CFCFCF; position: absolute; text-align: center;'>		<input class='LdtSearchInput'			style='margin-top: 1px; margin-bottom: 2px;' />	</div></div><div class='cleaner'></div>";
 IriSP.share_template = "{{! social network sharing template }}<a onclick='__IriSP.MyApiPlayer.share(\'delicious\');' title='{{l10n.share_on}} delicious'><span class='share shareDelicious'>&nbsp;</span></a>		<a onclick='__IriSP.MyApiPlayer.share(\'facebook\');' title='{{l10n.share_on}} facebook'> <span class='share shareFacebook'>&nbsp;</span></a><a onclick='__IriSP.MyApiPlayer.share(\'twitter\');' title='{{l10n.share_on}} twitter'>  <span class='share shareTwitter'>&nbsp;</span></a><a onclick='__IriSP.MyApiPlayer.share(\'myspace\');' title='{{l10n.share_on}} Myspace'>  <span class='share shareMySpace'>&nbsp;</span></a>";
 IriSP.sliceWidget_template = "{{! template for the slice widget }}<div class='Ldt-sliceWidget'>  {{! the whole bar }}  <div class='Ldt-sliceBackground'></div>    <div class='Ldt-sliceLeftHandle'></div>  {{! the zone which represents our slice }}  <div class='Ldt-sliceZone'></div>     <div class='Ldt-sliceRightHandle'></div></div>";
-IriSP.slideShareWidget_template = "{{! template for the slideShare widget of the other }}<div class='Ldt-SlideShare'><!--p> class='sync_links'><a class='sync_on'>Synchronise</a> - <a class='sync_off'>Ne synchronise pas</a></p--><div class='SlideShareContainer'></div></div>";
+IriSP.slideShareWidget_template = "{{! template for the slideShare widget of the other }}<div class='Ldt-SlideShare'><!--p> class='sync_links'><a class='sync_on'>Synchronise</a> - <a class='sync_off'>Ne synchronise pas</a></p--><div class='SlideShareContainer'></div>  <div class='SlideShareButtons'><ul><li><div class='ss_sync_on'></div><div class='ss_sync_off'></div></li><li><div class='ss_link'></div></li><li class='left_icon'><div class='ss_tooltip'></div></li></ul></div></div>";
 IriSP.sliderWidget_template = "{{! template for the slider widget - it's composed of two divs we one overlayed on top    of the other }}<div class='Ldt-sliderBackground'></div><div class='Ldt-sliderForeground'></div><div class='Ldt-sliderPositionMarker Ldt-TraceMe'></div>";
 IriSP.tooltip_template = "{{! template used by the jquery ui tooltip }}<div class='Ldt-tooltip'>  <div class='title'>{{title}}</div>  <div class='time'>{{begin}} : {{end}} </div>  <div class='description'>{{description}}</div></div>";
 IriSP.tooltipWidget_template = "{{! template for the tooltip widget }}<div class='tip'>	<div class='tipcolor' style='height:10px;width:10px'></div>	<div class='tiptext'></div>";
@@ -4892,6 +4892,15 @@
 /** A widget to display slide show from embed slide share */
 IriSP.SlideShareWidget = function(Popcorn, config, Serializer) {
   IriSP.Widget.call(this, Popcorn, config, Serializer);
+  // Default flash embed size
+  this.embed_width = 425;
+  this.embed_height = 355;
+  if(this._config.embed_width){
+	  this.embed_width = this._config.embed_width;
+  }
+  if(this._config.embed_height){
+	  this.embed_height = this._config.embed_height;
+  }
 };
 
 IriSP.SlideShareWidget.prototype = new IriSP.Widget();
@@ -4905,12 +4914,7 @@
 	  return;
   }
   var templ = Mustache.to_html(IriSP.slideShareWidget_template);
-  this.selector.html(templ);
-  
-  // Synchro management
-  this._disableUpdate = false;
-  this.selector.find('.sync_on').click(function(event) { self.syncHandler.call(self, event); });
-  this.selector.find('.sync_off').click(function(event) { self.unSyncHandler.call(self, event); });
+  this.selector.append(templ);
   
   // global variables used to keep the position and width of the zone.  
   this.zoneLeft = 0;
@@ -4921,6 +4925,16 @@
   this.lastSSId = "";
   this.containerDiv = this.selector.find('.SlideShareContainer');
   
+  // Synchro management
+  this._disableUpdate = false;
+  this.buttonsDiv = this.selector.find('.SlideShareButtons');
+  this.buttonsDiv.width(this.embed_width - 2); // -2 because of css borders 328 -> 235px
+  this.buttonsDiv.find('.left_icon').css("margin-left",(this.embed_width-96)+"px");
+  this.buttonsDiv.find('.ss_sync_on').click(function(event) { self.unSyncHandler.call(self, event); });
+  this.buttonsDiv.find('.ss_sync_off').click(function(event) { self.syncHandler.call(self, event); });
+  this.buttonsDiv.find('.ss_sync_off').hide();
+  this.buttonsDiv.hide();
+  
   // Update the slide from timeupdate event
   this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.slideShareUpdater));
   
@@ -4931,7 +4945,8 @@
   var annotations = this._serializer._data.annotations;
   var view_type = this._serializer.getSlideShareType();
   if(typeof(view_type) === "undefined") {
-	  if(console){ if(console.log){ console.log("No annotation-type for slideshare widget, this widget is canceled."); } }
+	  if(console){ if(console.log){ console.log("No annotation-type for slideshare widget, this widget is canceled and the container is visible hidden."); } }
+	  this.selector.hide();
 	  return;
   }
   var i = 0;
@@ -4959,72 +4974,100 @@
   // We search if a segments_slides is in the current timecode
   var time = this._Popcorn.currentTime() * 1000;
   var nb_slides = this.segments_slides.length;
-  var found = false;
+  var forceEmpty = false;
   for (i = 0; i < nb_slides; i++) {
     var segment_slide = this.segments_slides[i];
     if(segment_slide.begin<time && time<segment_slide.end){
-    	found = true;
     	if(segment_slide.content.description!=this.lastSSFullUrl){
 			// The url is like http://stuf.com#X and X is the slide number. So we split and save it.
     		this.lastSSFullUrl = segment_slide.content.description;
-    		var description_ar = this.lastSSFullUrl.split("#id=");
-    		var slideNb = 1;
-    		if(description_ar[1]){
-    			slideNb = description_ar[1];
-    		}
-    		if(description_ar[0]!=this.lastSSUrl){
-    			this.lastSSUrl = description_ar[0];
-	    		// We have the slideshare oembed url.
-	    		var url = "http://www.slideshare.net/api/oembed/1?format=jsonp&url=" + this.lastSSUrl;
-	    		
-	    		IriSP.jQuery.ajax({
-					url: url,
-					dataType: "jsonp",
-					success: function(data) {
-						self.lastSSId = data["slideshow_id"];
-						embed_code = data["html"];
-						// If slideNb exist, we hack the embed code to add ?startSlide=X
-						if(slideNb){
-							embed_code = embed_code.replace(new RegExp("ssplayer2.swf\\?","g"), "ssplayer2.swf?startSlide=" + slideNb + "&");
-						}
-						self.containerDiv.html(embed_code);
-					},
-					error: function(jqXHR, textStatus, errorThrown){
-						self.containerDiv.html("Error while downloading the slideshow. jqXHR = " + jqXHR + ", textStatus = " + textStatus + ", errorThrown = " + errorThrown);
-					}
-	    		});
+    		if(this.lastSSFullUrl==""){
+    			// We force unload
+    			forceEmpty = true;
     		}
     		else{
-    			// If the presentation was already loaded, we only use the ss js api to load the wanted slide number
-    			if(this.lastSSId!=""){
-    				// We get the embed flash element
-    				var embed = document.getElementsByName("__sse" + this.lastSSId)[0];
-    				if(embed){
-    					embed.jumpTo(parseInt(slideNb));
-    				}
-    			}
+    			this.buttonsDiv.show();
+	    		var description_ar = this.lastSSFullUrl.split("#id=");
+	    		var slideNb = 1;
+	    		if(description_ar[1]){
+	    			slideNb = description_ar[1];
+	    		}
+	    		if(description_ar[0]!=this.lastSSUrl && description_ar[0].substring(0,7)=="http://"){
+	    			this.lastSSUrl = description_ar[0];
+		    		// We have the slideshare oembed url (version 1 because we want the flash embed).
+		    		var url = "http://www.slideshare.net/api/oembed/1?format=jsonp&url=" + this.lastSSUrl;
+		    		
+		    		IriSP.jQuery.ajax({
+						url: url,
+						dataType: "jsonp",
+						success: function(data) {
+							self.lastSSId = data["slideshow_id"];
+							embed_code = data["html"];
+							// If slideNb exist, we hack the embed code to add ?startSlide=X
+							if(slideNb){
+								embed_code = embed_code.replace(new RegExp("ssplayer2.swf\\?","g"), "ssplayer2.swf?startSlide=" + slideNb + "&");
+							}
+							// The embed always send the default width and height, so we can easily change them.
+							embed_code = embed_code.replace(new RegExp("425","g"), self.embed_width);
+							embed_code = embed_code.replace(new RegExp("355","g"), self.embed_height);
+							// We hide the title upon the slides.
+							embed_code = embed_code.replace(new RegExp("block"), "none");
+							self.containerDiv.html(embed_code);
+						},
+						error: function(jqXHR, textStatus, errorThrown){
+							self.containerDiv.html("Error while downloading the slideshow. jqXHR = " + jqXHR + ", textStatus = " + textStatus + ", errorThrown = " + errorThrown);
+						}
+		    		});
+	    		}
+	    		else if(description_ar[0]!=this.lastSSUrl){
+	    			this.lastSSUrl = description_ar[0];
+	    			this.lastSSId = "";
+		    		// In this case, we only have an id that is meant to build the flash embed
+					embed_code = '<div style="width:425px"><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=' + this.lastSSUrl + '&startSlide=' + slideNb + '" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" width="'+this.embed_width+'" height="'+this.embed_height+'"></embed></div>';
+					this.containerDiv.html(embed_code);
+	    		}
+	    		else{
+	    			// If the presentation was already loaded, we only use the ss js api to load the wanted slide number
+	    			var embed = null;
+	    			if(this.lastSSId!=""){
+	    				// If the presentation was loaded from a public url, we get the div from its id.
+						embed = document.getElementsByName("__sse" + this.lastSSId)[0];
+	    			}
+	    			else if(this.lastSSUrl.substring(0,7)!="http://"){
+	    				// If the presentation was loaded from a private id, we get the div from dom tree.
+	    				embed = this.containerDiv.children()[0].children[0];
+	    			}
+					if(embed){
+						embed.jumpTo(parseInt(slideNb));
+					}
+	    		}
+	    		return;
     		}
-    		return;
     	}
     }
   }
-  if(found==false){
+  if(forceEmpty==true){
 	this.lastSSFullUrl = "";
 	this.lastSSUrl = "";
 	this.lastSSId = "";
   	this.containerDiv.html("");
+  	this.buttonsDiv.hide();
   }
 
 };
 
 // Functions to stop or trigger sync between timeupdate event and slides        
-IriSP.SlideShareWidget.prototype.unSyncHandler = function(params) {
+IriSP.SlideShareWidget.prototype.unSyncHandler = function() {
 	//console.log("slideShare NO SYNC !");
 	this._disableUpdate = true;
-};
-IriSP.SlideShareWidget.prototype.syncHandler = function(params) {
+	this.buttonsDiv.find('.ss_sync_on').hide();
+	this.buttonsDiv.find('.ss_sync_off').show();
+};
+IriSP.SlideShareWidget.prototype.syncHandler = function() {
 	//console.log("slideShare SYNC PLEASE !");
 	this._disableUpdate = false;
+	this.buttonsDiv.find('.ss_sync_on').show();
+	this.buttonsDiv.find('.ss_sync_off').hide();
 };
 
 
@@ -5746,7 +5789,6 @@
     }));
     
     this.tracer = IriSP.TraceManager(IriSP.jQuery).init_trace("test", this._config);
-    this.tracer.set_default_subject("default_subject");
     this.tracer.trace("StartTracing", { "hello": "world" });
     
 }
--- a/test/integration/allocine_dossier_independant/js/libs/tracemanager.js	Fri May 11 16:04:53 2012 +0200
+++ b/test/integration/allocine_dossier_independant/js/libs/tracemanager.js	Fri May 11 16:07:52 2012 +0200
@@ -12,8 +12,8 @@
 
      var BufferedService_prototype = {
          /*
-          *  Buffered service for traces
-          */
+* Buffered service for traces
+*/
          // url: "",
          // buffer: [],
          // isReady: false,
@@ -43,7 +43,7 @@
                      // 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');
+                     data = data.replace(/[;"#]/g, function(s){ return s == ';' ? '"' : ( s == '"' ? ';' : '%23'); });
                      // FIXME: check data length (< 2K is safe)
                      var request=$('<img />').error( function() { this.failureCount += 1; })
                          .load( function() { this.failureCount = 0; })
@@ -72,12 +72,12 @@
          },
 
          /* 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) {
+* synchronisation with server, the trace has to be explicitly saved
+* if needed */
+         set_sync_mode: function(mode, default_subject) {
              this.sync_mode = mode;
              if (! this.isReady && mode !== "none")
-                 this.init();
+                 this.init(default_subject);
              if (mode == 'delayed') {
                  this.start_timer();
              } else {
@@ -118,16 +118,18 @@
          },
 
          /*
-          * Initialize the sync service
-          */
-         init: function() {
+* Initialize the sync service
+*/
+         init: function(default_subject) {
              var self = this;
              if (this.isReady)
                  /* Already initialized */
                  return;
+             if (typeof default_subject === 'undefined')
+                 default_subject = 'anonymous';
              if (this.mode == 'GET')
              {
-                 var request=$('<img/>').attr('src', this.url + 'login?userinfo={"name":"ktbs4js"}');
+                 var request=$('<img/>').attr('src', this.url + 'login?userinfo={"default_subject": "' + default_subject + '"}');
                  // Do not wait for the return, assume it is
                  // initialized. This assumption will not work anymore
                  // if login returns some necessary information
@@ -137,7 +139,7 @@
              {
                  $.ajax({ url: this.url + 'login',
                           type: 'POST',
-                          data: 'userinfo={"name":"ktbs4js"}',
+                          data: 'userinfo={"default_subject":"' + default_subject + '"}',
                           success: function(data, textStatus, jqXHR) {
                               self.isReady = true;
                               if (self.buffer.length) {
@@ -168,20 +170,20 @@
 
      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 */
+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 */
+* 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).
-          */
+* representation (shorthands).
+*/
          shorthands: null,
          syncservice: null,
 
@@ -191,23 +193,23 @@
          },
 
          /* Sync mode: delayed, sync (immediate sync), none (no
-          * synchronisation with server, the trace has to be explicitly saved
-          * if needed */
+* 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);
+                 this.syncservice.set_sync_mode(mode, this.default_subject);
              }
          },
 
          /*
-          * Return a list of the obsels of this trace matching the parameters
-          */
+* 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.
-                  */
+* Not optimized yet.
+*/
                  res = [];
                  var l = this.obsels.length;
                  for (var i = 0; i < l; i++) {
@@ -235,8 +237,8 @@
          },
 
          /*
-          * Return the obsel of this trace identified by the URI, or undefined
-          */
+* 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 */
@@ -248,6 +250,9 @@
          },
 
          set_default_subject: function(subject) {
+             // FIXME: if we call this method after the sync_service
+             // init method, then the default_subject will not be
+             // consistent anymore. Maybe we should then call init() again?
              this.default_subject = subject;
          },
 
@@ -291,8 +296,8 @@
 
      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 */
+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)
@@ -316,8 +321,8 @@
 
      var Obsel_prototype = {
          /* The following attributes are here for documentation
-          * purposes. They MUST be defined in the constructor
-          * function. */
+* purposes. They MUST be defined in the constructor
+* function. */
          trace: undefined,
          type: undefined,
          begin: undefined,
@@ -347,7 +352,7 @@
          list_attribute_types: function() {
              var result = [];
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                      result.push(prop);
              }
              /* FIXME: we return URIs here instead of AttributeType elements */
@@ -368,8 +373,8 @@
              /* FIXME: not implemented yet */
          },
          /*
-          * Return the value of the given attribute type for this obsel
-          */
+* Return the value of the given attribute type for this obsel
+*/
          get_attribute_value: function(at) {
              if (typeof at === "string")
                  /* It is a URI */
@@ -409,8 +414,8 @@
          },
 
          /*
-          * Return a JSON representation of the obsel
-          */
+* Return a JSON representation of the obsel
+*/
          toJSON: function() {
              var r = {
                  "@id": this.id,
@@ -420,29 +425,35 @@
                  "subject": this.subject
              };
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                      r[prop] = this.attributes[prop];
              }
              return r;
          },
 
          /*
-          * Return a compact JSON representation of the obsel.
-          * Use predefined + custom shorthands for types/properties
-          */
+* 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
              };
+             // Transmit subject only if different from default_subject
+             if (this.subject !== this.trace.default_subject)
+                 r["@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;
 
+             // Store id only if != ""
+             if (this.id !== "")
+                 r["@i"] = this.id;
+
              for (var prop in this.attributes) {
-                 if (this.hasOwnProperty(prop))
+                 if (this.attributes.hasOwnProperty(prop))
                  {
                      var v = this.attributes[prop];
                      r[prop] = this.trace.shorthands.hasOwnProperty(v) ? this.trace.shorthands[v] : v;
@@ -474,19 +485,19 @@
      var TraceManager_prototype = {
          traces: [],
          /*
-          * Return the trace with id name
-          * If it was not registered, return undefined.
-          */
+* 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.
-          */
+* 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);
@@ -495,8 +506,8 @@
              syncmode = params.syncmode ? params.syncmode : "none";
              default_subject = params.default_subject ? params.default_subject : "default";
              var t = new Trace(url, requestmode);
+             t.set_default_subject(default_subject);
              t.set_sync_mode(syncmode);
-             t.set_default_subject(default_subject);
              this.traces[name] = t;
              return t;
          }
@@ -507,6 +518,6 @@
      };
      TraceManager.prototype = TraceManager_prototype;
 
-     var tracemanager  = new TraceManager();
+     var tracemanager = new TraceManager();
      return tracemanager;
  };
--- a/test/integration/allocine_dossier_independant/test-allocine.htm	Fri May 11 16:04:53 2012 +0200
+++ b/test/integration/allocine_dossier_independant/test-allocine.htm	Fri May 11 16:07:52 2012 +0200
@@ -67,13 +67,13 @@
                         disable_share: true,
                         api_endpoint_template : "json_examples/return_after_post.json", //"endpoint/{{id}}.json",
                         api_method : 'POST'
-                    } /*, {
+                    }, {
                         type: "TraceWidget",
                      //   js_console : true,
                         url: "http://traces.advene.org:5000/",
                         requestmode: 'GET',
                         syncmode: "sync"
-                    } */ ]
+                    } ]
                 },
                 player : {
                     type : 'allocine', // player type