Started big refactoring new-model
authorveltr
Tue, 17 Apr 2012 20:19:46 +0200
branchnew-model
changeset 868 a525cc2214e7
parent 866 3bf7aa8216e5
child 870 2c025db10a10
Started big refactoring
src/css/LdtPlayer.css
src/js/defaults.js
src/js/init.js
src/js/layout.js
src/js/main.js
src/js/model.js
src/js/serializers/CinecastSerializer.js
src/js/serializers/PlatformSerializer.js
src/js/widgets.js
src/js/widgets/helloWorldWidget.js
src/templates/loading.html
test/integration/polemic.htm
--- a/src/css/LdtPlayer.css	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/css/LdtPlayer.css	Tue Apr 17 20:19:46 2012 +0200
@@ -22,7 +22,8 @@
   width:1.5em;
 }
 
-#Ldt-loader {
+.Ldt-loader {
+    min-height: 128px;
     background:url(imgs/loader.gif) center no-repeat;
     text-indent: -9999px;
     position: absolute;
--- a/src/js/defaults.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/defaults.js	Tue Apr 17 20:19:46 2012 +0200
@@ -29,10 +29,13 @@
     useCdn : false
 }
 
+IriSP.guiDefaults = {
+    width : 640,            
+    container : 'LdtPlayer',
+    spacer_div_height : 0
+}
+
 IriSP.widgetsDefaults = {
-    "LayoutManager" : {
-        spacer_div_height : 0
-    },
     "PlayerWidget" : {
         
     },
--- a/src/js/init.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/init.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,21 +1,147 @@
 /* init.js - initialization and configuration of Popcorn and the widgets
 exemple json configuration:
-
 */
 
-/** do some magic to configure popcorn according to the options object passed.
- Works for html5, jwplayer and youtube videos
- */
-IriSP.configurePopcorn = function(layoutManager, options) {
-    var pop;
-    var ret = layoutManager.createDiv();
-    var containerDiv = ret[0];
-    var spacerDiv = ret[1];
+/* The Metadataplayer Object, single point of entry, replaces IriSP.init_player */
+
+IriSP.Metadataplayer = function(config, video_metadata) {
+    IriSP._.defaults(config.gui, IriSP.guiDefaults);
+    var _container = document.getElementById(config.gui.container);
+    _container.innerHTML = IriSP.templToHTML(IriSP.loading_template, config.gui);
+    this.video_metadata = video_metadata;
+    this.sourceManager = new IriSP.Model.Directory();
+    this.config = config;
+    this.loadLibs();
+}
+
+IriSP.Metadataplayer.prototype.toString = function() {
+    return 'A Metadataplayer in DIV #' + this.config.gui.container;
+}
+
+IriSP.Metadataplayer.prototype.loadLibs = function() {
+    console.log("Loading Libs");
+    // Localize jQuery variable
+    IriSP.jQuery = null;
+    var $L = $LAB.script(IriSP.getLib("jQuery")).script(IriSP.getLib("swfObject")).wait().script(IriSP.getLib("jQueryUI"));
+
+    if(this.config.player.type === "jwplayer" || this.config.player.type === "allocine" || this.config.player.type === "dailymotion") {
+        // load our popcorn.js lookalike
+        $L.script(IriSP.getLib("jwplayer"));
+    } else {
+        // load the real popcorn
+        $L.script(IriSP.getLib("popcorn")).script(IriSP.getLib("popcorn.code"));
+        // load plugins if necessary
+        if(this.config.player.type === "youtube") {
+            $L.script(IriSP.getLib("popcorn.youtube"));
+        }
+        if(this.config.player.type === "vimeo"){
+            $L.script(IriSP.getLib("popcorn.vimeo"));
+        }
+    }
+
+    /* widget specific requirements */
+    for(var _i = 0; _i < this.config.gui.widgets.length; _i++) {
+        if(this.config.gui.widgets[_i].type === "PolemicWidget" || this.config.gui.widgets[_i].type === "StackGraphWidget" || this.config.gui.widgets[_i].type === "SparklineWidget") {
+            $L.script(IriSP.getLib("raphael"));
+        }
+        if(this.config.gui.widgets[_i].type === "TraceWidget") {
+            $L.script(IriSP.getLib("tracemanager"))
+        }
+    }
+    
+    var _this = this;
+    
+    $L.wait(function() {
+        console.log("jQuery is loaded");
+        IriSP.jQuery = window.jQuery.noConflict(true);
+
+        var css_link_jquery = IriSP.jQuery("<link>", {
+            rel : "stylesheet",
+            type : "text/css",
+            href : IriSP.getLib("cssjQueryUI")
+        });
+        var css_link_custom = IriSP.jQuery("<link>", {
+            rel : "stylesheet",
+            type : "text/css",
+            href : _this.config.gui.css
+        });
+        console.log('Appending CSS');
 
-    /* insert one pixel of margin between the video and the first widget, using the
-     spacer.
+        css_link_jquery.appendTo('head');
+        css_link_custom.appendTo('head');
+        
+        console.log(_this);
+        _this.onLibsLoaded();
+        
+    });
+}
+
+IriSP.Metadataplayer.prototype.loadMetadata = function(_metadataInfo) {
+    if (typeof _metadataInfo.serializer === "undefined" && typeof _metadataInfo.format !== "undefined") {
+        _metadataInfo.serializer = IriSP.serializers[_metadataInfo.format];
+    }
+    if (typeof _metadataInfo.url === "undefined" && typeof _metadataInfo.src !== "undefined") {
+        _metadataInfo.url = _metadataInfo.src;
+    }
+    console.log(_metadataInfo);
+    if (typeof _metadataInfo.url !== "undefined" && typeof _metadataInfo.serializer !== "undefined") {
+        return this.sourceManager.remoteSource(_metadataInfo);
+    } else {
+        return this.sourceManager.newLocalSource(_metadataInfo);
+    }
+}
+
+IriSP.Metadataplayer.prototype.onLibsLoaded = function() {
+    console.log("Libs Loaded");
+    this.videoData = this.loadMetadata(this.video_metadata);
+    console.log(this.videoData);
+    this.$ = IriSP.jQuery('#' + this.config.gui.container);
+    this.$.css({
+        "width": this.config.gui.width,
+        "clear": "both"
+    });
+    if (typeof this.config.gui.height !== "undefined") {
+        this.$.css("height", this.config.gui.height);
+    }
+      
+    var _this = this;
+    console.log("calling OnLoad");
+    this.videoData.onLoad(function() {
+        _this.onVideoDataLoaded();
+    });
+}
+
+IriSP.Metadataplayer.prototype.onVideoDataLoaded = function() {
+    console.log("Video Data Loaded");
+    if (typeof this.videoData !== "undefined" && typeof this.config.player.video === "undefined") {
+        var _media = this.videoData.currentMedia;
+        if (typeof _media !== "undefined") {
+            config.player.video = _media.video;
+            if (typeof _media.streamer !== "undefined") {
+                config.player.streamer = _media.streamer;
+                config.player.video = _media.video.replace(_media.streamer,'');
+            }
+        }
+        
+    }
+    this.configurePopcorn(config.player);
+    this.widgets = [];
+    for(var i = 0; i < this.config.gui.widgets.length; i++) {
+        this.widgets.push(new IriSP.Widgets[_config.type](this, this.config.gui.widgets[i]));
+    };
+    this.$('.Ldt-loader').detach();
+}
+
+IriSP.Metadataplayer.prototype.configurePopcorn = function() {
+    var pop,
+        ret = this.layoutDivs(),
+        containerDiv = ret[0],
+        spacerDiv = ret[1];
+
+    /* insert one pixel of margin between the video and the first widget,
+     * using the spacer.
      */
-    IriSP.jQuery("#" + spacerDiv).css("height", "1px");
+    IriSP.jQuery("#" + spacerDiv).css("height", Math.max(1, this.config.gui.spacer_div_height) + "px");
 
     switch(options.type) {
         /*
@@ -72,134 +198,40 @@
             /* pass the options as-is to the allocine player and let it handle everything */
             pop = new IriSP.PopcornReplacement.allocine("#" + containerDiv, options);
             break;
-
+        
         default:
             pop = undefined;
     };
 
-    return pop;
-};
-/** Configure the gui and instantiate the widgets passed as parameters
- @param guiOptions the gui object as seen in the examples.
- */
-IriSP.configureWidgets = function(popcornInstance, layoutManager, guiOptions) {
-
-    var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader);
-    var params = {
-        width : guiOptions.width,
-        height : guiOptions.height
-    };
-
-    var default_options = guiOptions.default_options;
-    if(IriSP.null_or_undefined(default_options))
-        default_options = {};
-
-    var ret_widgets = [];
-    var index;
-
-    for( index = 0; index < guiOptions.widgets.length; index++) {
-        var widget = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, guiOptions.widgets[index], default_options);
-
-        ret_widgets.push(widget);
-    };
-
-    return ret_widgets;
-};
-/** configure modules. @see configureWidgets */
-IriSP.configureModules = function(popcornInstance, modulesList) {
-/*    if(IriSP.null_or_undefined(modulesList))
-        return;
-
-    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; */
-};
-/** instantiate a widget - only called by configureWidgets, never by the user. Handles widget
- dependencies.
- @param popcornInstance popcorn instance the widget will user
- @param serialFactory serializer factory to instantiate the widget with
- @param layoutManager layout manager
- @param widgetConfig configuration options for the widget
- @param defaultOptions a dictionnary with some options defined for every widget.
- */
-IriSP.instantiateWidget = function(popcornInstance, serialFactory, layoutManager, widgetConfig, defaultOptions) {
-
-    if(IriSP.null_or_undefined(defaultOptions))
-        defaultOptions = {};
-    widgetConfig = IriSP.underscore.defaults(widgetConfig, defaultOptions);
-
-    var arr = IriSP.jQuery.extend({}, widgetConfig);
+    this.popcorn = pop;
+}
 
-    /* create a div for those widgets who didn't already specify a container; */
-    if(!arr.hasOwnProperty("container")) {
-        /* 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];
-        arr.container = container;
-        arr.spacer = spacer;
-        arr.layoutManager = layoutManager;
-    }
-    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"], _configobj = IriSP.jQuery.extend({}, widgetConfig.requires[i]), _div = document.createElement('div'), _container = IriSP.guid(arr.container + '_' + widgetName + '_');
-            _configobj.container = _container;
-            _div.id = _container;
-            widget.selector.append(_div);
-            widget[widgetName] = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, _configobj, defaultOptions);
-        }
+/** create a subdiv with an unique id, and a spacer div as well.
+    @param widgetName the name of the widget.
+    @return an array of the form [createdivId, spacerdivId].
+*/
+IriSP.Metadataplayer.prototype.layoutDivs = function(_name) {
+    if (typeof(_name) === "undefined") {
+       _name = "";
     }
-
-    serializer.sync(IriSP.wrap(widget, function() {
-        this.draw();
-    }));
-    return widget;
-};
-/** single point of entry for the metadataplayer */
-IriSP.initPlayer = function(config, metadata_url, format) {
-    document.getElementById(config.gui.container).innerHTML = IriSP.templToHTML(IriSP.loading_template, config.gui);
-    IriSP.loadLibs(config, metadata_url, format, function() {
+    var newDiv = IriSP.guid(this.container + "_widget_" + _name + "_"),
+        spacerDiv = IriSP.guid("LdtPlayer_spacer_"),
+        divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative; clear: both;'></div>",
+        spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}}px;'></div>",
+        divHtml = Mustache.to_html( divTempl,
+            {
+                id: newDiv,
+                width: this.config.gui.width
+            }),
+        spacerHtml = Mustache.to_html( spacerTempl,
+            {
+                spacer_id: spacerDiv,
+                width: this.config.gui.width,
+                spacer_div_height: this.config.gui.height
+            });
+            
+    this.$.append(divCode);
+    this.$.append(spacerCode);
 
-        var layoutManager = new IriSP.LayoutManager(config.gui);
-        
-        if (typeof IriSP._videoData !== "undefined" && typeof config.player.video === "undefined") {
-            var _media = IriSP._videoData.currentMedia;
-            if (typeof _media !== "undefined") {
-                config.player.video = _media.video;
-                if (typeof _media.streamer !== "undefined") {
-                    config.player.streamer = _media.streamer;
-                    config.player.video = _media.video.replace(_media.streamer,'');
-                }
-            }
-            
-        }
-        
-        var pop = IriSP.configurePopcorn(layoutManager, config.player);
-
-        IriSP._widgets = IriSP.configureWidgets(pop, layoutManager, config.gui);
-        IriSP.jQuery('#Ldt-loader').detach();
-    });
+    return [newDiv, spacerDiv];
 };
--- a/src/js/layout.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/layout.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,77 +1,3 @@
 /* layout.js - very basic layout management */
 
-/**
-  @class 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,
-        "clear": "both"
-    });
-    
-    if (this._height !== undefined)
-      this.selector.css("height", this._height);
-};
-
-/** 
-   Set the popcorn instance used by the manager.
-   
-   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;
-}
-
-/** create a subdiv with an unique id, and a spacer div as well.
-    @param widgetName the name of the widget.
-    @return an array of the form [createdivId, spacerdivId].
-*/
-IriSP.LayoutManager.prototype.createDiv = function(widgetName) {
-    if (typeof(widgetName) === "undefined")
-       widgetName = "";
-
-    var newDiv = IriSP.guid(this._div + "_widget_" + widgetName + "_");
-    var spacerDiv = IriSP.guid("LdtPlayer_spacer_");
-    this._widgets.push([widgetName, newDiv]);    
-
-    var divTempl = "<div id='{{id}}' style='width: {{width}}px; position: relative; clear: both;'></div";
-    var spacerTempl = "<div id='{{spacer_id}}' style='width: {{width}}px; position: relative; height: {{spacer_div_height}}px;'></div";
-    
-    var divCode = Mustache.to_html(divTempl, {id: newDiv, width: this._width});
-    var spacerCode = Mustache.to_html(spacerTempl, {spacer_id: spacerDiv, width: this._width,
-                                                    spacer_div_height: IriSP.widgetsDefaults.LayoutManager.spacer_div_height });
-
-    this.selector.append(divCode);
-    this.selector.append(spacerCode);
-
-    return [newDiv, spacerDiv];
-};
\ No newline at end of file
+/* Has been integrated to init.js */
--- a/src/js/main.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/main.js	Tue Apr 17 20:19:46 2012 +0200
@@ -34,66 +34,3 @@
         )
     )
 }
-
-IriSP.loadLibs = function(config, metadata_url, format, callback) {
-    // Localize jQuery variable
-    IriSP.jQuery = null;
-    var $L = $LAB.script(IriSP.getLib("jQuery")).script(IriSP.getLib("swfObject")).wait().script(IriSP.getLib("jQueryUI"));
-
-    if(config.player.type === "jwplayer" || config.player.type === "allocine") {
-        // load our popcorn.js lookalike
-        $L.script(IriSP.getLib("jwplayer"));
-    } else {
-        // load the real popcorn
-        $L.script(IriSP.getLib("popcorn")).script(IriSP.getLib("popcorn.code"));
-        if(config.player.type === "youtube") {
-            $L.script(IriSP.getLib("popcorn.youtube"));
-        }
-        if(config.player.type === "vimeo")
-            $L.script(IriSP.getLib("popcorn.vimeo"));
-
-        /* do nothing for html5 */
-    }
-
-    /* widget specific requirements */
-    for(var idx in config.gui.widgets) {
-        if(config.gui.widgets[idx].type === "PolemicWidget" || config.gui.widgets[idx].type === "StackGraphWidget" || config.gui.widgets[idx].type === "SparklineWidget") {
-            $L.script(IriSP.getLib("raphael"));
-        }
-        if(config.gui.widgets[idx].type === "TraceWidget") {
-            $L.script(IriSP.getLib("tracemanager"))
-        }
-    }
-
-
-    $L.wait(function() {
-        IriSP.jQuery = window.jQuery.noConflict(true);
-
-        var css_link_jquery = IriSP.jQuery("<link>", {
-            rel : "stylesheet",
-            type : "text/css",
-            href : IriSP.getLib("cssjQueryUI"),
-            'class' : "dynamic_css"
-        });
-        var css_link_custom = IriSP.jQuery("<link>", {
-            rel : "stylesheet",
-            type : "text/css",
-            href : config.gui.css,
-            'class' : "dynamic_css"
-        });
-
-        css_link_jquery.appendTo('head');
-        css_link_custom.appendTo('head');
-
-        IriSP._directory = new IriSP.Model.Directory();
-        IriSP._videoData = _directory.remoteSource({
-            url : metadata_url,
-            namespace : "metadataplayer",
-            serializer : IriSP.serializers[format]
-        });
-        if (typeof callback !== "undefined") {
-            IriSP._videoData.onLoad(callback);
-        }
-        
-    });
-};
--- a/src/js/model.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/model.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,12 +1,12 @@
 /* model.js is where data is stored in a standard form, whatever the serializer */
 
 IriSP.Model = {
-    SOURCE_STATUS_EMPTY : 0,
-    SOURCE_STATUS_WAITING : 1,
-    SOURCE_STATUS_READY : 2,
-    ID_AUTO_INCREMENT : 0,
+    _SOURCE_STATUS_EMPTY : 0,
+    _SOURCE_STATUS_WAITING : 1,
+    _SOURCE_STATUS_READY : 2,
+    _ID_AUTO_INCREMENT : 0,
     getAI : function() {
-        return "autoid-" + (++this.ID_AUTO_INCREMENT);
+        return "autoid-" + (++this._ID_AUTO_INCREMENT);
     },
     isoToDate : function(_str) {
         // http://delete.me.uk/2005/03/iso8601.html
@@ -44,8 +44,9 @@
     }
 }
 
-/* */
-
+/*
+ * IriSP.Model.List is a class for a list of elements (e.g. annotations, medias, etc. that each have a distinct ID)
+ */
 IriSP.Model.List = function(_directory) {
     Array.call(this);
     this.directory = _directory;
@@ -67,6 +68,9 @@
     return (IriSP._(this.idIndex).indexOf(_id) !== -1);
 }
 
+/* On recent browsers, forEach and map are defined and do what we want.
+ * Otherwise, we'll use the Underscore.js functions
+ */
 if (typeof Array.prototype.forEach === "undefined") {
     IriSP.Model.List.prototype.forEach = function(_callback) {
         var _this = this;
@@ -85,7 +89,8 @@
     }
 }
 
-/* We override Array's filter function because it doesn't return an IriSP.Model.List */
+/* We override Array's filter function because it doesn't return an IriSP.Model.List
+ */
 IriSP.Model.List.prototype.filter = function(_callback) {
     var _this = this,
         _res = new IriSP.Model.List(this.directory);
@@ -95,6 +100,9 @@
     return _res;
 }
 
+/* Array has a sort function, but it's not as interesting as Underscore.js's sortBy
+ * and won't return a new IriSP.Model.List
+ */
 IriSP.Model.List.prototype.sortBy = function(_callback) {
     var _this = this,
         _res = new IriSP.Model.List(this.directory);
@@ -104,6 +112,9 @@
     return _res;
 }
 
+/* Title and Description are basic information for (almost) all element types,
+ * here we can search by these criteria
+ */
 IriSP.Model.List.prototype.searchByTitle = function(_text) {
     var _rgxp = new RegExp('(' + _text.replace(/(\W)/gm,'\\$1') + ')','gim');
     return this.filter(function(_element) {
@@ -137,8 +148,13 @@
     if (typeof this.directory.getElement(_el.id) === "undefined") {
         this.directory.addElement(_el);
     }
-    this.idIndex.push(_el.id);
-    Array.prototype.push.call(this, _el);
+    var _index = (IriSP._(this.idIndex).indexOf(_el.id));
+    if (_index === -1) {
+        this.idIndex.push(_el.id);
+        Array.prototype.push.call(this, _el);
+    } else {
+        this[_index] = _el;
+    }
 }
 
 IriSP.Model.List.prototype.addIds = function(_array) {
@@ -157,7 +173,9 @@
     });
 }
 
-/* */
+/* A simple time management object, that helps converting millisecs to seconds and strings,
+ * without the clumsiness of the original Date object.
+ */
 
 IriSP.Model.Time = function(_milliseconds) {
     this.milliseconds = parseInt(typeof _milliseconds !== "undefined" ? _milliseconds : 0);
@@ -197,7 +215,8 @@
     return _res;
 }
 
-/* */
+/* IriSP.Model.Reference handles references between elements
+ */
 
 IriSP.Model.Reference = function(_source, _idRef) {
     this.source = _source;
@@ -209,14 +228,10 @@
         }));
     } else {
         this.isList = false;
-        this.contents = _source.getNamespaced(_idRef).fullname;
+        this.contents = this.source.directory.getElement(_source.getNamespaced(_idRef).fullname);
     }
 }
 
-IriSP.Model.Reference.prototype.getContents = function() {
-    return (this.isList ? this.contents : this.source.directory.getElement(this.contents));
-}
-
 /* */
 
 IriSP.Model.Element = function(_id, _source) {
@@ -243,7 +258,7 @@
 
 IriSP.Model.Element.prototype.getReference = function(_elementType) {
     if (typeof this[_elementType] !== "undefined") {
-        return this[_elementType].getContents();
+        return this[_elementType].contents;
     }
 }
 
@@ -255,7 +270,7 @@
             return _ref.contents.hasId(_this.id);
         }
         else {
-            return _ref.contents === _this.id;
+            return _ref.contents.id === _this.id;
         }
     });
 }
@@ -352,7 +367,7 @@
 /* */
 
 IriSP.Model.Source = function(_config) {
-    this.status = IriSP.Model.SOURCE_STATUS_EMPTY;
+    this.status = IriSP.Model._SOURCE_STATUS_EMPTY;
     if (typeof _config !== "undefined") {
         var _this = this;
         IriSP._(_config).forEach(function(_v, _k) {
@@ -448,7 +463,7 @@
 }
 
 IriSP.Model.Source.prototype.get = function() {
-    this.status = IriSP.Model.SOURCE_STATUS_READY;
+    this.status = IriSP.Model._SOURCE_STATUS_READY;
     var _this = this;
     if (_this.callbackQueue.length) {
         IriSP._(_this.callbackQueue).forEach(function(_callback) {
@@ -463,9 +478,14 @@
 }
 
 IriSP.Model.Source.prototype.onLoad = function(_callback) {
-    if (this.status === IriSP.Model.SOURCE_STATUS_READY) {
-        callback.call(this);
+    if (this.status === IriSP.Model._SOURCE_STATUS_READY) {
+        console.log("Called on load, Ready");
+        var _this = this;
+        IriSP._.defer(function() {
+            _callback.call(_this);
+        });        
     } else {
+        console.log("Called on load, not ready");
         this.callbackQueue.push(_callback);
     }
 }
@@ -505,17 +525,18 @@
 IriSP.Model.RemoteSource.prototype = new IriSP.Model.Source();
 
 IriSP.Model.RemoteSource.prototype.get = function() {
-    this.status = IriSP.Model.SOURCE_STATUS_WAITING;
+    this.status = IriSP.Model._SOURCE_STATUS_WAITING;
     var _this = this;
     IriSP.jQuery.getJSON(this.url, function(_result) {
         _this.serializer.deSerialize(_result, _this);
+        console.log('Received data, we have '+_this.callbackQueue.length+' callbacks waiting');
         if (_this.callbackQueue.length) {
             IriSP._(_this.callbackQueue).forEach(function(_callback) {
                 _callback.call(_this);
             });
         }
         _this.callbackQueue = [];
-        _this.status = IriSP.Model.SOURCE_STATUS_READY;
+        _this.status = IriSP.Model._SOURCE_STATUS_READY;
     });
 }
 
--- a/src/js/serializers/CinecastSerializer.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/serializers/CinecastSerializer.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,3 +1,5 @@
+/* Cinecast Cinelab Serializer */
+
 if (typeof IriSP.serializers === "undefined") {
     IriSP.serializers = {}
 }
@@ -179,4 +181,5 @@
         }
         _source.setDefaultCurrentMedia();
     }
-}
\ No newline at end of file
+}
+
--- a/src/js/serializers/PlatformSerializer.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/serializers/PlatformSerializer.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,8 +1,10 @@
+/* LDT Platform Serializer */
+
 if (typeof IriSP.serializers === "undefined") {
     IriSP.serializers = {}
 }
 
-IriSP.serializers.platform = {
+IriSP.serializers.ldt = {
     types :  {
         media : {
             serialized_name : "medias",
@@ -147,4 +149,5 @@
         }
         _source.setDefaultCurrentMedia();
     }
-}
\ No newline at end of file
+}
+
--- a/src/js/widgets.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/widgets.js	Tue Apr 17 20:19:46 2012 +0200
@@ -1,90 +1,79 @@
 /* the widget classes and definitions */
 
 /**
-  * @class Widget is an "abstract" class. It's mostly used to define some properties common to every widget.
-  *
-  *  Note that widget constructors are never called directly by the user. Instead, the widgets are instantiated by functions
-  *  defined in init.js
-  *  
-  * @constructor
-  * @param Popcorn a reference to the popcorn Object
-  * @param config configuration options for the widget
-  * @param Serializer a serializer instance from which the widget reads data fromCharCode  
-*/
-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);
-  }
-
+ * @class IriSP.Widget is an "abstract" class. It's mostly used to define some properties common to every widget.
+ *
+ *  Note that widget constructors are never called directly by the user. Instead, the widgets are instantiated by functions
+ *  defined in init.js
+ *
+ * @constructor
+ * @param player - a reference to the player widget
+ * @param config - configuration options for the widget
+ */
+IriSP.Widget = function(player, config) {
 
-  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;     
-  } 
-
-  if (config.hasOwnProperty("layoutManager")) {
-     this.layoutManager = config.layoutManager;
-  }
-  if (typeof this.selector != "undefined") {
-      this.selector.addClass("Ldt-TraceMe").addClass("Ldt-Widget");
-      this.selector.attr("widget-type", this._config.type);
-  }
-  
-  // Parsing Widget Defaults
-  var _this = this;
-  
-  if (typeof config.type == "string" && typeof IriSP.widgetsDefaults[config.type] == "object") {
-      config = IriSP._.defaults(IriSP.widgetsDefaults[config.type]);
-  }
-  
-};
-
-
-IriSP.Widget.prototype.currentMedia = function() {
-    return this._serializer.currentMedia();
-}
-
-IriSP.Widget.prototype.getDuration = function() {
-    return this._serializer.getDuration();
-}
-
-/**
-  * This method responsible of drawing a widget on screen.
-  */
-IriSP.Widget.prototype.draw = function() {
-  /* implemented by "sub-classes" */  
+    if( typeof player === "undefined") {
+        /* Probably an abstract call of the class when
+         * individual widgets set their prototype */
+        return;
+    }
+    
+    /* Setting all the configuration options */
+    var _type = config.type,
+        _config = IriSP._.defaults({}, config, _player.config.gui.default_options, IriSP.widgetsDefaults[_type]),
+        _this = this;
+    
+    /* Creating containers if needed */
+    if (typeof _config.container === "undefined") {
+        var _divs = _player.layoutDivs(_type);
+        _config.container = _divs[0];
+        _config.spacer = _divs[1];
+    }
+    
+    IriSP._(_config).forEach(function(_value, _key) {
+       _this[_key] = _value;
+    });
+    
+    /* Setting this.player at the end in case it's been overriden
+     * by a configuration option of the same name :-(
+     */
+    this.player = player;
+    
+    /* Getting metadata */
+    this.source = _player.loadMetadata(this.metadata);
+    
+    /* Call draw when loaded */
+    this.source.onLoad(function() {
+        _this.draw();
+    })
+   
+    /* Adding classes and html attributes */
+    this.selector = IriSP.jQuery(this.container);
+    this.selector.addClass("Ldt-TraceMe").addClass("Ldt-Widget").attr("widget-type", _type);
+    
+    /* Does the widget require other widgets ? */
+    if (typeof this.requires !== "undefined") {
+        for (var _i = 0; _i < this.requires.length; _i++) {
+            var _subconfig = this.requires[_i],
+                _div = IriSP.jQuery('<div>');
+            _subconfig.container = IriSP.guid(this.container + '_' + _subconfig.type + '_');
+            _div.id = _subconfig.container;
+            this.selector.append(_div);
+            this[_subconfig.type] = new IriSP.Widgets(_player, _subconfig);
+        }
+    }
+    
 };
 
 /**
-  * Optional method if you want your widget to support redraws.
-  */
+ * This method responsible of drawing a widget on screen.
+ */
+IriSP.Widget.prototype.draw = function() {
+    /* implemented by "sub-classes" */
+};
+/**
+ * Optional method if you want your widget to support redraws.
+ */
 IriSP.Widget.prototype.redraw = function() {
-  /* implemented by "sub-classes" */  
+    /* implemented by "sub-classes" */
 };
--- a/src/js/widgets/helloWorldWidget.js	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/js/widgets/helloWorldWidget.js	Tue Apr 17 20:19:46 2012 +0200
@@ -6,12 +6,10 @@
 
 IriSP.HelloWorldWidget.prototype.draw = function() {
     this.selector
-        .html('Hello, world')
+        .append('Hello, world')
         .css({
             "text-align" : "center",
             "padding": "10px 0",
             "font-size" : "14px"
         });
-        
-    console.log(this);
 }
--- a/src/templates/loading.html	Tue Apr 17 15:03:40 2012 +0200
+++ b/src/templates/loading.html	Tue Apr 17 20:19:46 2012 +0200
@@ -1,1 +1,1 @@
-<div id='Ldt-loader' style='width: {{width}}px; height: {{height}}px;'>{{l10n.loading_wait}}</div>
+<div class='Ldt-loader' style='width: {{width}}px;'>{{l10n.loading_wait}}</div>
--- a/test/integration/polemic.htm	Tue Apr 17 15:03:40 2012 +0200
+++ b/test/integration/polemic.htm	Tue Apr 17 20:19:46 2012 +0200
@@ -23,17 +23,17 @@
   <script  type="text/javascript">
   IriSP.libFiles.defaultDir = "/metadataplayer/src/js/libs/";
 IriSP.jwplayer_swf_path = "../libs/player.swf";
-    var file = "polemic_fr.json";
-    var config = {            
+    var _metadata = {
+        url: 'polemic_fr.json',
+        format: 'ldt'
+    };
+    var _config = {            
         gui:{
             width:640,
             height:800,              
             container:'LdtPlayer',
 			default_options: {
-				metadata:{
-				  format:'cinelab',
-				  src:file,
-				  type:'json'}
+				metadata: _metadata
 			},
             css:'../../src/css/LdtPlayer.css',
             widgets: [
@@ -97,7 +97,7 @@
 
     };
     
-    IriSP.initPlayer(config, file);
+    var _myPlayer = new IriSP.Metadataplayer(_config, _metadata);
   </script>