JS file was accidentally deleted
authorveltr
Thu, 19 Jul 2012 14:09:23 +0200
changeset 81 bf6adf981cc2
parent 80 00a3532ad8cf
child 82 f00eb382bff1
JS file was accidentally deleted
timeline/css/timeline.css
timeline/js/timeline.js
timeline/timeline.html
--- a/timeline/css/timeline.css	Wed Jul 18 18:23:49 2012 +0200
+++ b/timeline/css/timeline.css	Thu Jul 19 14:09:23 2012 +0200
@@ -47,8 +47,8 @@
 
 /*************************************************/
 
-.Onglets {
-    display: inline-block; margin: 0 10px;
+ul.Onglets {
+    margin: 0 10px; text-align: left;
 }
 
 .Onglets li {
@@ -64,7 +64,7 @@
 /************************************************/
 
 .Tl-Main {
-    border: 1px solid #ccc; font-family: Arial, Helvetica, sans-serif;
+    border: 1px solid #ccc; font-family: Arial, Helvetica, sans-serif; text-align: left;
 }
 
 .Tl-TopBar {
@@ -333,7 +333,7 @@
 /**********************************/
 
 .Ls-Main {
-    display: none; width: 950px; height: 200px; background: #fafafa; border: 1px solid #cccccc;
+    display: none; width: 950px; height: 200px; background: #fafafa; border: 1px solid #cccccc; text-align: left;
 }
 
 .Ls-Filtres {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/timeline/js/timeline.js	Thu Jul 19 14:09:23 2012 +0200
@@ -0,0 +1,1067 @@
+/*
+ * Main Timeline code
+ */
+
+window.Tlns = {
+    Utils : {},
+    Defaults : {},
+    Templates : {},
+    Classes : {}
+};
+
+/* Utility Functions */
+
+Tlns.Utils.zeroPad = function(_n) {
+    return (_n < 10 ? "0" : "") + _n;
+}
+
+Tlns.Utils.SetDefaults = function(_object, _defaults, _options) {
+    var _options = _options || {};
+    _(_defaults).each(function(_v, _k) {
+        if(/^m(in|ax)_/.test(_k)) {
+            var _tab = _k.split('_')
+            if( typeof _object[_tab[1]] !== "undefined") {
+                var _fn = (_tab[0] === "min" ? Math.max : Math.min);
+                _object[_tab[1]] = _fn(_object[_tab[1]], _v);
+            }
+        } else {
+            if( typeof _options[_k] !== "undefined") {
+                _object[_k] = _options[_k];
+            } else {
+                _object[_k] = _v;
+            }
+        }
+    });
+}
+
+Tlns.Utils.dateFormat = function(_date, _template) {
+    if (typeof _date !== "object") {
+        _date = new Date(parseInt(_date));
+    }
+    var _params = {
+        hours: _date.getHours(),
+        "0hours": Tlns.Utils.zeroPad(_date.getHours()),
+        minutes: _date.getMinutes(),
+        "0minutes": Tlns.Utils.zeroPad(_date.getMinutes()),
+        seconds: _date.getSeconds(),
+        "0seconds": Tlns.Utils.zeroPad(_date.getSeconds()),
+        dayOfWeek: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"][_date.getDay()],
+        shortDayOfWeek: ["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"][_date.getDay()],
+        dayOfMonth: _date.getDate(),
+        "0dayOfMonth": Tlns.Utils.zeroPad(_date.getDate()),
+        monthNumber: 1+_date.getMonth(),
+        "0monthNumber": Tlns.Utils.zeroPad(1+_date.getMonth()),
+        monthName: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"][_date.getMonth()],
+        shortMonthName: ["jan","fev","mar","avr","mai","jun","jul","aou","sep","oct","nov","dec"][_date.getMonth()],
+        year: _date.getFullYear()
+    }
+    return Mustache.to_html(_template, _params);
+}
+
+Tlns.Utils.guid = function() {
+    return 'xxxx-xxxx-xxxx-xxxx'.replace(/x/g,function() {
+        return Math.floor(Math.random()*16).toString(16);
+    });
+}
+
+Tlns.Utils.drawArrow = function(_ctx, _color, _x1, _y1, _x2, _y2) {
+    _ctx.strokeStyle = _color;
+    _ctx.fillStyle = _color;
+    _ctx.beginPath();
+    _ctx.moveTo(_x1,_y1);
+    _ctx.lineTo(_x2,_y2);
+    _ctx.stroke();
+    var _mod = Math.sqrt(Math.pow(_x2 - _x1, 2) + Math.pow(_y2 - _y1, 2)),
+        _xu = (_x2 - _x1) / _mod,
+        _yu = (_y2 - _y1) / _mod,
+        _xm = (_x1 + _x2) / 2,
+        _ym = (_y1 + _y2) / 2,
+        _arrowWidth = 4,
+        _arrowLength = 8,
+        _x3 = _xm - _arrowLength * _xu + _arrowWidth * _yu,
+        _y3 = _ym - _arrowLength * _yu - _arrowWidth * _xu,
+        _x4 = _xm - _arrowLength * _xu - _arrowWidth * _yu,
+        _y4 = _ym - _arrowLength * _yu + _arrowWidth * _xu;
+    _ctx.beginPath();
+    _ctx.moveTo(_x3, _y3);
+    _ctx.lineTo(_xm, _ym);
+    _ctx.lineTo(_x4, _y4);
+    _ctx.fill();
+    _ctx.stroke();
+}
+
+Tlns.Utils.timeFieldProcess = function(_val) {
+    var _h = 0,
+        _m = 0,
+        _matches = _val.match(/(\d+)/g);
+    if (_matches && _matches.length) {
+        _h = Math.min(23, +(_matches[0]));
+        if (_matches.length > 1) {
+            _m = Math.min(59, +(_matches[1]));
+        }
+    }
+    return {
+        hours: _h,
+        minutes: _m,
+        text: Tlns.Utils.zeroPad(_h) + ':' + Tlns.Utils.zeroPad(_m)
+    }
+}
+
+Tlns.Utils.dateFieldProcess = function(_val) {
+    var _now = new Date(),
+        _y = _now.getFullYear(),
+        _m = 1 + _now.getMonth(),
+        _d = _now.getDate(),
+        _matches = _val.match(/(\d+)/g);
+    if (_matches && _matches.length) {
+        _d = Math.min(31, +(_matches[0]));
+        if (_matches.length > 1) {
+            _m = Math.min(12, +(_matches[1]));
+        }
+        if (_matches.length > 2) {
+            _y = parseInt(_matches[2]);
+            if (_y < 2000) {
+                _y += 2000;
+            }
+            _y = Math.min(2020, Math.max(2000, _y));
+        }
+    }
+    return {
+        year: _y,
+        month: _m,
+        date: _d,
+        text: Tlns.Utils.zeroPad(_d) + '/' + Tlns.Utils.zeroPad(_m) + '/' + _y
+    }
+}
+
+/* Defaults */
+
+Tlns.Defaults.Timeline = {
+    container : "timeline",
+    width : 950,
+    height : 200,
+    url_univers : '',
+    min_width : 400,
+    min_height : 100,
+    main_width : 800,
+    timescales : [{
+        label : "Mois",
+        span : 32 * 86400 * 1000,
+        grid_interval : 5 * 86400 * 1000,
+        grid_date_format : '{{dayOfMonth}} {{shortMonthName}}',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
+        end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{year}}'
+    }, {
+        label : "Semaine",
+        span : 8 * 86400 * 1000,
+        grid_interval : 86400 * 1000,
+        grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}}',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
+        end_date_format : '{{dayOfMonth}} {{shortMonthName}}'
+    }, {
+        label : "2 jours",
+        span : 2 * 86400 * 1000,
+        grid_interval : 8 * 3600 * 1000,
+        grid_date_format : '{{shortDayOfWeek}} {{0dayOfMonth}}/{{0monthNumber}} {{hours}}h',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}}',
+        end_date_format : '{{dayOfMonth}} {{shortMonthName}}'
+    }, {
+        label : "Demi-Journée",
+        span : 12 * 3600 * 1000,
+        grid_interval : 2 * 3600 * 1000,
+        grid_date_format : '{{hours}}h',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h',
+        end_date_format : '{{dayOfMonth}} {{shortMonthName}} {{hours}}h'
+    }, {
+        label : "3 Heures",
+        span : 3 * 3600 * 1000,
+        grid_interval : 30 * 60 * 1000,
+        grid_date_format : '{{0hours}}:{{0minutes}}',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}',
+        end_date_format : '{{0hours}}:{{0minutes}}'
+    }, {
+        label : "1 Heure",
+        span : 60 * 60 * 1000,
+        grid_interval : 15 * 60 * 1000,
+        grid_date_format : '{{0hours}}:{{0minutes}}',
+        start_date_format : '{{dayOfMonth}} {{shortMonthName}} {{0hours}}:{{0minutes}}',
+        end_date_format : '{{0hours}}:{{0minutes}}'
+    }],
+    level: 0,
+    central_time: 0,
+    sync_now: true,
+    urls_occurrences: [],
+    occurrences: [],
+    cluster_spacing: 12,
+    tooltip_date_format: '{{dayOfMonth}} {{shortMonthName}} {{year}} {{0hours}}:{{0minutes}}',
+    statuses: {
+        "valide": "Validée",
+        "a_valider": "A valider",
+        "a_realiser": "A réaliser"
+    }
+}
+
+for (var _i = 0; _i < Tlns.Defaults.Timeline.timescales.length; _i++) {
+    Tlns.Defaults.Timeline.timescales[_i].level = _i;
+}
+
+/* Templates */
+
+Tlns.Templates.Timeline = '<ul class="Onglets"><li class="Onglet-Tl active">Frise chronologique</li><li class="Onglet-Ls">Liste des occurrences</li></ul><div class="Tl-Main"><div class="Tl-TopBar"><div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-AddButton"></div></div><div class="Tl-TopBar-Spacer Tl-Border-Right"></div>'
+    + '<div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-PreviousButton"></div></div><div class="Tl-TopBar-TimeSpan Tl-TopBar-TextBtn Tl-Border-Right">--/--</div>'
+    + '<div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-SyncButton"></div></div><div class="Tl-TopBar-Button Tl-Border-Right"><div class="Tl-TopBar-NextButton"></div></div><div class="Tl-TopBar-Spacer Tl-Border-Right"></div>'
+    + '<div class="Tl-TopBar-Timescales">{{#timescales}}<div class="Tl-TopBar-Button Tl-TopBar-TextBtn Tl-Border-Right" data-level="{{level}}">{{label}}</div>{{/timescales}}</div></div>'
+    + '<div class="Tl-BottomPart"><ul class="Tl-UniversLabels"></ul>'
+    + '<div class="Tl-MainPart"><div class="Tl-Layer Tl-Grid"></div><canvas class="Tl-Layer Tl-Canvas"></canvas><canvas class="Tl-Layer Tl-Linking-Canvas"></canvas><div class="Tl-Layer Tl-Occurrences"></div>'
+    + '<ul class="Tl-Adding"><li class="Tl-AddingTitle">Ajout d\'une occurrence</li><li><span>Narrative</span><div class="Tl-AddOccurrence Tl-Occnarrative" occurrence-type="narrative" title="Glisser sur la frise chronologique pour ajouter"></div></li>'
+    + '<li><span>De Publication</span><div class="Tl-AddOccurrence Tl-Occpublication" occurrence-type="publication" title="Glisser sur la frise chronologique pour ajouter"></div></li></ul></div>'
+    + '<div class="Tl-Overlay-Container"><div class="Tl-Overlay-Box"><div class="Tl-Overlay"><div class="Tl-Overlay-Tip-Top"></div><div class="Tl-Overlay-Main"></div><div class="Tl-Overlay-Tip-Bottom"></div></div></div></div></div></div>'
+    
+    +'<div class="Ls-Main"><div class="Ls-Filtres"><h2>Filtres&nbsp;:</h2>'
+    + '<div class="Ls-Column"><h3>Univers&nbsp;:</h3><ul class="Ls-Univers"></ul></div>'
+    + '<div class="Ls-Column"><h3>Type d\'occurrence&nbsp;:</h3><ul class="Ls-Occtypes"><li data="narrative" class="Ls-Critere Ls-Active Ls-CrWithIcon"><div class="Ls-OccIcon Tl-Occnarrative"></div>Narratives</li><li data="publication" class="Ls-Critere Ls-Active Ls-CrWithIcon"><div class="Ls-OccIcon Tl-Occpublication"></div>de Publication</li></ul>'
+    + '<h3>Statut&nbsp;:</h3><ul class="Ls-Occstatuses"><li data="a_realiser" class="Ls-Critere Ls-Active Ls-CrWithIcon"><div class="Ls-OccIcon Tl-Occpublication Tl-Occa_realiser"></div>À réaliser</li><li data="a_valider" class="Ls-Critere Ls-Active Ls-CrWithIcon"><div class="Ls-OccIcon Tl-Occpublication Tl-Occa_valider"></div>À valider</li><li data="valide" class="Ls-Critere Ls-Active Ls-CrWithIcon"><div class="Ls-OccIcon Tl-Occpublication Tl-Occvalide"></div>Validé</li></ul>'
+    + '<h3>Est au JT&nbsp;:</h3><ul class="Ls-IsJt"><li class="Ls-Critere Ls-Active" data="1">Oui</li><li class="Ls-Critere Ls-Active" data="0">Non</li></ul></div>'
+    + '<div class="Ls-Column"><h3>Recherche par titre&nbsp;:</h3><p><input class="Ls-Search" type="search" placeholder="Rechercher" /></p><h3>Date&nbsp;:</h3><p><label class="Ls-Label">Du </label><input class="Ls-From-Date Ls-Input" /></p><p><label class="Ls-Label">à </label><input class="Ls-From-Time Ls-Input" /></p><p><label class="Ls-Label">Au </label><input class="Ls-To-Date Ls-Input" /></p><p><label class="Ls-Label">à </label><input class="Ls-To-Time Ls-Input" /></p></div>'
+    + '</div><div class="Ls-Resultats"><h2>Occurrences&nbsp;:</h2><ul class="Ls-Occurrences"></ul></div></div>';
+
+Tlns.Templates.Univers = '<span class="Tl-UniversText">{{title}}</span>';
+
+Tlns.Templates.Univers_List = '{{#univers}}<li data="{{id}}" class="Ls-Critere Ls-Active">{{title}}</li>{{/univers}}';
+
+Tlns.Templates.Occurrence = '{{#clusters}}<div class="Tl-Cluster" style="left: {{x}}px; top: {{y}}px;" cluster-contents="{{contents}}">'
+    + '<div class="Tl-ClusterCount">{{occurrences.length}}</div></div>{{/clusters}}'
+    + '{{#occurrences}}<div class="Tl-Occurrence Tl-OccOnGrid Tl-Occ{{type}} Tl-Occ{{status}}{{#editing}} Tl-Editing{{/editing}}" occurrence-id="{{id}}" style="left: {{x}}px; top: {{y}}px;">'
+//  + '{{#locked}}<div class="Tl-Locked"></div>{{/locked}}'
+    + '<div class="Tl-Link"{{#editing}} style="display: block"{{/editing}}></div></div>{{/occurrences}}{{#open_cluster}}<div class="Tl-ClusterOverlay" style="left: {{x}}px; top: {{y}}px;">'
+    + '{{#occurrences}}<div class="Tl-Occurrence Tl-OccInCluster Tl-Occ{{type}} Tl-Occ{{status}}{{#editing}} Tl-Editing{{/editing}}" occurrence-id="{{id}}">'
+    + '{{#locked}}<div class="Tl-Locked"></div>{{/locked}}<div class="Tl-Link"{{#editing}} style="display: block"{{/editing}}></div></div>{{/occurrences}}</div>{{/open_cluster}}';
+
+Tlns.Templates.Occurrence_List = '{{#occurrences}}<li class="Ls-Occurrence"><div class="Ls-OccIcon Tl-Occ{{type}} Tl-Occ{{status}}"></div><h4 class="Ls-Occurrence-Title">{{title}}</h4>'
+    + '<p class="Ls-Occ-More">{{formatted_date}} &mdash; {{univers.title}} &mdash; {{translated_status}} &mdash; {{#jt}}Au JT{{/jt}}{{^jt}}Hors JT{{/jt}}</p><div style="clear:both;"></div></li>{{/occurrences}}';
+
+Tlns.Templates.OccurrenceTooltip = '<h3 class="Tl-Tooltip-Title">{{title}}</h3><p class="Tl-Tooltip-Date">{{formatted_date}} &mdash; {{translated_status}}</p>'
+    + '<p class="Tl-Tooltip-Description">{{description}}</p>'
+//    + '<p class="Tl-Tooltip-Characters">{{univers.mainCharacter}}{{#characters}}, {{.}}{{/characters}}</p>'
+
+/* Classes */
+
+Tlns.Classes.Timeline = function(_options) {
+
+    /* Setting Defaults */
+    Tlns.Utils.SetDefaults(this, Tlns.Defaults.Timeline, _options);
+
+    /* Setting container CSS */
+    this.$ = $('#' + this.container).html(Mustache.to_html(Tlns.Templates.Timeline, this));
+    
+    this.$.find('.Tl-Main').css({
+        width : this.width + "px",
+        height : this.height + "px"
+    });
+    this.main_height = this.height - this.$.find('.Tl-TopBar').outerHeight();
+    this.$.find('.Tl-BottomPart').css("height", this.main_height + "px");
+    this.$.find('.Tl-MainPart').css("width", this.main_width + "px");
+    this.$.find('.Tl-Overlay-Container').css("left", (this.$.find('.Tl-BottomPart').outerWidth() - this.main_width) + "px");
+    this.$.find('canvas.Tl-Layer').attr({
+        width: this.main_width,
+        height: this.main_height
+    });
+    var _o = this.$.find('.Tl-MainPart').offset();
+    this.dragging_bounds = {
+        left: _o.left,
+        top: _o.top,
+        right: _o.left + this.$.find('.Tl-MainPart').outerWidth(),
+        bottom: _o.top + this.$.find('.Tl-MainPart').outerHeight(),
+    };
+    
+    var _this = this;
+    
+    this.throttledDrawGrid = _.throttle(function() {
+        _this.drawGrid();
+    }, 150);
+    
+    this.throttledDrawList = _.throttle(function() {
+        _this.drawList();
+    }, 150);
+    
+    this.setLevel(this.level);
+    
+    this.$.find('.Tl-TopBar-Timescales>div').click(function() {
+        _this.setLevel($(this).attr("data-level"));
+    });
+    
+    this.$.find('.Tl-TopBar-SyncButton').click(function() {
+        _this.sync_now = !_this.sync_now;
+        _this.changeSpan();
+    })
+    
+    this.$.find('.Tl-TopBar-PreviousButton').click(function() {
+        _this.offsetTime(-_this.timescales[_this.level].span / 4);
+    });
+    
+    this.$.find('.Tl-TopBar-NextButton').click(function() {
+        _this.offsetTime(_this.timescales[_this.level].span / 4);
+    });
+    
+    this.$.find('.Tl-MainPart').mousedown(function(_event) {
+        _this.onMouseDown(_event);
+        return false;
+    });
+    
+    this.$.find('.Tl-MainPart').mousemove(function(_event) {
+        _this.onMouseMove(_event);
+        return false;
+    });
+    
+    this.$.find('.Tl-MainPart').mouseup(function(_event) {
+        _this.onMouseUp(_event);
+        return false;
+    });
+    
+    this.$.find('.Tl-MainPart').mousewheel(function(_event, _delta) {
+        var _newLevel = Math.max(0,Math.min(_this.timescales.length-1, (_delta < 0 ? -1 : 1) + parseInt(_this.level)));
+        if (_newLevel != _this.level) {
+            _this.hideTooltip();
+            var _deltaX = _event.pageX - _this.dragging_bounds.left,
+                _tAtMouse = _this.timeFromMouse(_event.pageX),
+                _newScale = _this.main_width / (_this.timescales[_newLevel].span),
+                _newStart = _tAtMouse - _deltaX / _newScale;
+            _this.central_time = _newStart + _this.timescales[_newLevel].span / 2;
+            _this.setLevel(_newLevel);
+        }
+        return false;
+    });
+    
+    this.$.find('.Tl-Overlay-Box').mouseover(function(_event) {
+        $(this).show();
+    }).mouseout(function(_event) {
+        $(this).hide();
+    });
+    
+    this.$.find('.Tl-TopBar-AddButton').click(function() {
+        $(this).toggleClass('active');
+        _this.$.find('.Tl-Adding').toggle();
+    });
+    
+    this.$.find('.Tl-AddOccurrence').mousedown(function(_event) {
+        var _el = $(this),
+            _type = _el.attr("occurrence-type"),
+            _d = _this.timeFromMouse(_event.pageX),
+            _u = _this.universFromMouse(_event.pageY),
+            _occ = _this.createOrUpdateOccurrence(
+                _type,
+                {
+                    datePublication: Math.floor(_d / 1000),
+                    titre: '<Nouvelle occurrence>',
+                    idUnivers: _this.univers[_u].id,
+                    statut: 'a_realiser',
+                    jt: false
+                }
+            );
+        _occ.just_created = true;
+        _occ.editing = true;
+        _this.editing_occurrence = _occ;
+        _this.dragging_type = "occurrence";
+        window.setTimeout(function () {
+            _this.$.find('.Tl-TopBar-AddButton').removeClass('active');
+            _this.$.find('.Tl-Adding').hide();
+        }, 200);
+        _this.throttledDrawGrid();
+    }).mouseup(function(_event) {
+        _this.onMouseUp(_event);
+        return false;
+    });
+    
+    /* Loading Univers */
+    $.getJSON(this.url_univers, function(_data) {
+        _this.onUniversLoaded(_data);
+    });
+    
+    /* LIST */
+    
+    this.$.find("li.Ls-Critere").click(function() {
+        $(this).toggleClass("Ls-Active");
+        _this.throttledDrawList();
+    });
+    this.$.find(".Ls-Search").bind("keyup change click", function() {
+        _this.throttledDrawList();
+    });
+    this.$.find(".Ls-From-Date, .Ls-To-Date").datepicker(
+        {
+            dateFormat: "dd/mm/yy",
+            dayNames: [ "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi" ],
+            dayNamesShort: [ "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam" ],
+            dayNamesMin: [ "D", "L", "Ma", "Me", "J", "V", "S" ],
+            monthNames:  [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" ],
+            monthNamesShort: [ "Jan", "Fév", "Mar", "Avr", "Mai", "Jun", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc" ],
+            showOtherMonths: true,
+            selectOtherMonths: true
+        }
+    ).change(function() {
+        var _val = $(this).val();
+        if (_val) {
+            $(this).val(Tlns.Utils.dateFieldProcess( _val ).text);
+        }
+        _this.drawList();
+    }).bind("keyup", function() {
+        _this.throttledDrawList();
+    });
+    this.$.find(".Ls-From-Time, .Ls-To-Time").change(function() {
+        var _val = $(this).val();
+        if (_val) {
+            $(this).val(Tlns.Utils.timeFieldProcess( _val ).text);
+        }
+        _this.throttledDrawList();
+    }).bind("keyup", function() {
+        _this.throttledDrawList();
+    });
+    
+    this.$.find(".Onglet-Tl").click(function() {
+        _this.$.find(".Tl-Main").show();
+        _this.$.find(".Ls-Main").hide();
+        _this.$.find(".Onglet-Ls").removeClass("active");
+        _this.$.find(".Onglet-Tl").addClass("active");
+        _this.throttledDrawGrid();
+    });
+    
+    this.$.find(".Onglet-Ls").click(function() {
+        _this.$.find(".Ls-Main").show();
+        _this.$.find(".Tl-Main").hide();
+        _this.$.find(".Onglet-Tl").removeClass("active");
+        _this.$.find(".Onglet-Ls").addClass("active");
+        _this.throttledDrawList();
+    });
+    
+    
+    /* BINDING MEDIADATA EVENTS */
+   
+    $("body").bind("AjoutOccurrenceEditeur MiseAJourOccurrenceEditeur", function(_event, _data) {
+        var _type = _data.typeOccurrence.replace(/^occurrence/i,'').toLowerCase();
+        _this.createOrUpdateOccurrence(_type, _data);
+        _this.throttledDrawGrid();
+    });
+    
+    $("body").bind("SuppressionOccurrenceEditeur", function(_event, _data) {
+        var _id = _data.typeOccurrence.replace(/^occurrence/i,'').toLowerCase() + '_' + _data.id;
+        _this.deleteOccurrence(_id);
+        _this.throttledDrawGrid();
+    });
+    
+    $("body").bind("AjoutDependanceEditeur", function(_event, _data) {
+        var _sourceId = _data.typeOccurrence.replace(/^occurrence/i,'').toLowerCase() + '_' + _data.id,
+            _targetId = _data.typeOccurrenceCible.replace(/^occurrence/i,'').toLowerCase() + '_' + _data.idCible;
+        _this.getOccurrence(_sourceId).addDependency(_targetId);
+        _this.throttledDrawGrid();
+    });
+    
+    $("body").bind("SuppressionDependanceEditeur", function(_event, _data) {
+        var _sourceId = _data.typeOccurrence.replace(/^occurrence/i,'').toLowerCase() + '_' + _data.id,
+            _targetId = _data.typeOccurrenceCible.replace(/^occurrence/i,'').toLowerCase() + '_' + _data.idCible;
+        _this.getOccurrence(_sourceId).addDependency(_targetId);
+        _this.throttledDrawGrid();
+    });
+    
+    
+}
+
+Tlns.Classes.Timeline.prototype.onMouseDown = function(_event) {
+    this.mouse_down = true;
+    this.is_dragging = false;
+    this.start_pos = {
+        x: _event.pageX,
+        y: _event.pageY
+    };
+    if (typeof this.dragging_type === "undefined") {
+        this.time_at_start = this.central_time;
+        this.dragging_type = "timeline";
+    }
+}
+
+Tlns.Classes.Timeline.prototype.onMouseUp = function(_event) {
+    if (this.is_dragging) {
+        switch (this.dragging_type) {
+            case "occurrence":
+                var _event = ( this.editing_occurrence.just_created ? "Ajout" : "MiseAJour" ) + "OccurrenceTimeline",
+                    _data = {
+                        id: this.editing_occurrence.original_id,
+                        typeOccurrence: "occurrence" + this.editing_occurrence.type.replace(/^./,function(_l) { return _l.toUpperCase()}),
+                        datePublication : Math.floor(this.editing_occurrence.date / 1000),
+                        titre : this.editing_occurrence.title,
+                        idUnivers: this.editing_occurrence.univers_id,
+                        statut: this.statuses[this.editing_occurrence.status],
+                        JT: +!!this.editing_occurrence.jt
+                    }
+                $("body").trigger(_event, _data);
+                this.editing_occurrence.editing = false;
+                this.editing_occurrence.just_created = false;
+                this.throttledDrawGrid();
+            break;
+            case "link":
+                this.editing_occurrence.editing = false;
+                this.throttledDrawGrid();
+                var _ctx = this.$.find('.Tl-Linking-Canvas')[0].getContext('2d');
+                _ctx.clearRect(0,0,this.main_width, this.main_height);
+            break;
+        }
+    } else {
+        if (this.dragging_type == "occurrence" || this.dragging_type == "link") {
+            if (this.editing_occurrence.just_created) {
+                this.deleteOccurrence(this.editing_occurrence.id);
+                this.throttledDrawGrid();
+            } else {
+                var _data = {
+                    id: this.editing_occurrence.original_id,
+                    typeOccurrence: "occurrence" + this.editing_occurrence.type.replace(/^./,function(_l) { return _l.toUpperCase()})
+                }
+                $("body").trigger("SelectionOccurrenceTimeline", _data);
+            }
+        }
+    }
+    this.mouse_down = false;
+    this.is_dragging = false;
+    this.dragging_type = undefined;
+}
+
+Tlns.Classes.Timeline.prototype.timeFromX = function(_x) {
+    return Math.max(this.start_time,Math.min(this.end_time, this.start_time + _x / this.current_scale));
+}
+
+Tlns.Classes.Timeline.prototype.timeFromMouse = function(_pageX) {
+    return this.timeFromX(_pageX - this.dragging_bounds.left);
+}
+
+Tlns.Classes.Timeline.prototype.universFromY = function(_y) {
+    return Math.max(0,Math.min(this.univers.length, Math.floor(_y / this.univers_height)))
+}
+
+Tlns.Classes.Timeline.prototype.universFromMouse = function(_pageY) {
+    return this.universFromY(_pageY - this.dragging_bounds.top);
+}
+
+Tlns.Classes.Timeline.prototype.onMouseMove = function(_event) {
+    if (this.mouse_down) {
+        this.is_dragging = true;
+        this.hideTooltip();
+        switch (this.dragging_type) {
+            case "occurrence":
+                var _d = this.timeFromMouse(_event.pageX);
+                this.editing_occurrence.date = _d;
+                this.editing_occurrence.formatted_date = Tlns.Utils.dateFormat(this.editing_occurrence.date,this.tooltip_date_format);
+                var _u = this.universFromMouse(_event.pageY);
+                this.editing_occurrence.univers = this.univers[_u];
+                this.editing_occurrence.univers_id = this.univers[_u].id;
+                this.throttledDrawGrid();
+            break;
+            case "timeline":
+                this.setTime(this.time_at_start + Math.floor(( this.start_pos.x - _event.pageX ) / this.current_scale));
+            break;
+            case "link":
+                var _ctx = this.$.find('.Tl-Linking-Canvas')[0].getContext('2d');
+                _ctx.clearRect(0,0,this.main_width, this.main_height);
+                Tlns.Utils.drawArrow(
+                    _ctx,
+                    '#800080',
+                    this.editing_occurrence.x,
+                    this.editing_occurrence.y + Math.floor(this.univers_height / 2),
+                    _event.pageX - this.dragging_bounds.left,
+                    _event.pageY - this.dragging_bounds.top
+                );
+            break;
+        }
+    }
+}
+
+Tlns.Classes.Timeline.prototype.onUniversLoaded = function(_data) {
+    this.univers = [];
+    if(_data.length) {
+        this.univers_height = Math.floor(this.main_height / _data.length);
+    }
+    for(var _i = 0; _i < _data.length; _i++) {
+        this.univers.push(new Tlns.Classes.Univers(_data[_i], this, _i));
+    }
+    
+    this.$.find(".Ls-Univers").html(Mustache.to_html(Tlns.Templates.Univers_List, this));
+    var _this = this;
+    this.$.find(".Ls-Univers li.Ls-Critere").click( function() {
+        $(this).toggleClass("Ls-Active");
+        _this.throttledDrawList();
+    });
+    this.loadOccurrences();
+}
+
+Tlns.Classes.Timeline.prototype.offsetTime = function(_timeOffset) {
+    this.setTime(this.central_time + _timeOffset);
+}
+
+Tlns.Classes.Timeline.prototype.setTime = function(_centralTime) {
+    this.sync_now = false;
+    this.central_time = _centralTime;
+    this.changeSpan();
+}
+
+Tlns.Classes.Timeline.prototype.setLevel = function(_level) {
+    if (_level >= 0 && _level < this.timescales.length) {
+        this.$.find('.Tl-TopBar-Timescales>div').each(function() {
+            var _el = $(this);
+            if (_el.attr("data-level") == _level) {
+                _el.addClass("active");
+            } else {
+                _el.removeClass("active");
+            }
+        });
+        this.level = _level;
+        this.changeSpan();
+    }
+}
+
+Tlns.Classes.Timeline.prototype.changeSpan = function() {
+    var _now = new Date().valueOf();
+    if (this.sync_now) {
+        this.central_time = _now;
+    }
+    var _timescale = this.timescales[this.level];
+    this.current_scale = this.main_width / (_timescale.span);
+    this.start_time = this.central_time - (_timescale.span / 2);
+    this.end_time = this.central_time + (_timescale.span / 2);
+    this.$.find(".Ls-From-Time").val(Tlns.Utils.dateFormat(this.start_time, '{{0hours}}:{{0minutes}}'));
+    this.$.find(".Ls-From-Date").val(Tlns.Utils.dateFormat(this.start_time, '{{0dayOfMonth}}/{{0monthNumber}}/{{year}}'));
+    this.$.find(".Ls-To-Time").val(Tlns.Utils.dateFormat(this.end_time, '{{0hours}}:{{0minutes}}'));
+    this.$.find(".Ls-To-Date").val(Tlns.Utils.dateFormat(this.end_time, '{{0dayOfMonth}}/{{0monthNumber}}/{{year}}'));
+    this.throttledDrawGrid();
+    this.throttledDrawList();
+}
+
+Tlns.Classes.Timeline.prototype.drawGrid = function() {
+    if (this.sync_now) {
+        this.$.find('.Tl-TopBar-SyncButton').addClass("active");
+    } else {
+        this.$.find('.Tl-TopBar-SyncButton').removeClass("active");
+    }
+    var _now = new Date().valueOf(),
+        _timescale = this.timescales[this.level],
+        _offset = new Date().getTimezoneOffset() * 60000,
+        _grid_width = Math.floor(_timescale.grid_interval * this.current_scale),
+        _roundstart = Math.floor((this.start_time - _offset) / _timescale.grid_interval) * _timescale.grid_interval + _offset,
+        _html = '';
+    this.$.find('.Tl-TopBar-TimeSpan').html(Tlns.Utils.dateFormat(this.start_time, _timescale.start_date_format) + ' - ' + Tlns.Utils.dateFormat(this.end_time, _timescale.end_date_format));
+    for (var _t = _roundstart; _t < this.end_time; _t += _timescale.grid_interval) {
+        var _x = this.current_scale * (_t - this.start_time);
+        if (_x > 0) {
+            _html += '<div class="Tl-Grid-Column" style="width:' + _grid_width + 'px; left: ' + _x + 'px">'
+            + '<div class="Tl-Grid-Label">' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '</div></div>';
+        }
+    }
+    if (this.start_time <= _now && this.end_time >= _now) {
+        _html += '<div class="Tl-Grid-Now" style="left: ' + this.current_scale * (_now - this.start_time) + 'px"></div>'
+    }
+    this.$.find('.Tl-Grid').html(_html);
+    this.drawOccurrences();
+}
+
+Tlns.Classes.Timeline.prototype.loadOccurrences = function() {
+    var _this = this;
+    _(this.urls_occurrences).each(function(_url_occ) {
+        $.getJSON(_url_occ.url, function(_data) {
+            _this.onOccurrencesLoaded(_data, _url_occ.type);
+        });
+    });
+    
+}
+
+Tlns.Classes.Timeline.prototype.onOccurrencesLoaded = function(_data, _type) {
+    for (var _i = 0; _i < _data.length; _i++) {
+        this.createOrUpdateOccurrence(_type, _data[_i]);
+    }
+    if (!this.mouse_down) {
+        this.drawOccurrences();
+    }
+    this.throttledDrawList();
+}
+
+Tlns.Classes.Timeline.prototype.deleteOccurrence = function(_id) {
+    this.occurrences = _(this.occurrences).reject(function(_occ) {
+        return _occ.id == _id;
+    });
+}
+
+Tlns.Classes.Timeline.prototype.getOccurrence = function(_id) {
+    return _(this.occurrences).find(function(_occ) {
+        return _occ.id == _id;
+    });
+}
+
+Tlns.Classes.Timeline.prototype.createOrUpdateOccurrence = function(_type, _data) {
+    var _id = _type + "_" + _data.id,
+        _occurrence = this.getOccurrence(_id);
+    if (typeof _occurrence === "undefined") {
+        _occurrence = new Tlns.Classes.Occurrence(this);
+        this.occurrences.push(_occurrence);
+    }
+    _occurrence.update(_type, _data);
+    return _occurrence;
+}
+
+Tlns.Classes.Timeline.prototype.showTooltip = function(_x, _y, _html, _isUp) {
+    this.$.find('.Tl-Overlay-Box')
+        .removeClass(_isUp ? 'Tl-Overlay-Down' : 'Tl-Overlay-Up')
+        .addClass(_isUp ? 'Tl-Overlay-Up' : 'Tl-Overlay-Down')
+        .show()
+        .css({
+            left: _x + "px",
+            top: _y + "px"
+        });
+    this.$.find('.Tl-Overlay-Main').html(_html);
+}
+
+Tlns.Classes.Timeline.prototype.hideTooltip = function() {
+    this.$.find('.Tl-Overlay-Box').hide();
+}
+
+Tlns.Classes.Timeline.prototype.drawOccurrences = function() {
+    var _this = this,
+        _visible = _(this.occurrences).filter(function(_occ) {
+        return (_occ.date >= _this.start_time && _occ.date <= _this.end_time && _occ.status);
+    });
+    _(_visible).each(function(_occ) {
+        _occ.x = _this.current_scale * (_occ.date - _this.start_time);
+        _occ.y = _occ.univers.y;
+        _occ.in_cluster = false;
+    });
+    
+    var _moved = true;
+    while (_moved) {
+        _moved = false;
+        for (var _i = 0; _i < _visible.length; _i++) {
+            for (var _j = 0; _j < _i; _j++) {
+                if (_visible[_j].univers_id == _visible[_i].univers_id
+                    && _visible[_j].x != _visible[_i].x
+                    && Math.abs(_visible[_j].x-_visible[_i].x) < this.cluster_spacing
+                ) {
+                    _moved = true;
+                    _visible[_i].x = this.cluster_spacing * Math.round(_visible[_i].x / this.cluster_spacing);
+                    _visible[_j].x = this.cluster_spacing * Math.round(_visible[_j].x / this.cluster_spacing);
+                }
+            }
+        }
+    }
+    var _clusters = [],
+        _openCluster = false;
+    for (var _i = 0; _i < _visible.length; _i++) {
+        for (var _j = 0; _j < _i; _j++) {
+            if (_visible[_j].univers_id == _visible[_i].univers_id && _visible[_j].x == _visible[_i].x) {
+                _visible[_j].in_cluster = true;
+                _visible[_i].in_cluster = true;
+                var _x = _visible[_j].x,
+                    _y = _visible[_j].y;
+                    _cluster = _(_clusters).find(function(_c) { return _c.x == _x && _c.y == _y });
+                if (typeof _cluster === "undefined") {
+                    _cluster = { x: _x, y: _y, occurrences: [] };
+                    _clusters.push(_cluster);
+                }
+                if ("undefined" === typeof _(_cluster.occurrences).find(function(_o) {
+                    return _o.type == _visible[_j].type && _o.id == _visible[_j].id;
+                })) {
+                    _cluster.occurrences.push(_visible[_j]);
+                }
+                if ("undefined" === typeof _(_cluster.occurrences).find(function(_o) {
+                    return _o.type == _visible[_i].type && _o.id == _visible[_i].id;
+                })) {
+                    _cluster.occurrences.push(_visible[_i]);
+                }
+            }
+        }
+    }
+    _(_clusters).each(function(_cluster) {
+        _cluster.occurrences = _(_cluster.occurrences).sortBy(function(_o) {
+            return _o.date;
+        });
+        _cluster.contents = _cluster.occurrences.map(function(_o) {
+            return _o.type + ":" + _o.id;
+        }).join("|");
+        if (_cluster.contents == _this.open_cluster) {
+            _openCluster = _cluster;
+        }
+    });
+    
+    
+    var _links = [];
+    
+    _(_visible).each(function(_occurrence) {
+        _(_occurrence.dependsOn).each(function(_dependance) {
+            var _parent = _(_visible).find(function(_o) {
+                return _o.id == _dependance;
+            });
+            if (typeof _parent !== "undefined") {
+                _links.push({
+                    from_x: _occurrence.x,
+                    from_y: _occurrence.y + Math.floor(_this.univers_height / 2),
+                    to_x: _parent.x,
+                    to_y: _parent.y + Math.floor(_this.univers_height / 2)
+                });
+            }
+        });
+    });
+    
+    var _ctx = this.$.find('.Tl-Canvas')[0].getContext('2d');
+    _ctx.clearRect(0,0,this.main_width, this.main_height);
+    _(_links).each(function(_link) {
+        Tlns.Utils.drawArrow(_ctx, "#505050", _link.from_x,_link.from_y, _link.to_x,_link.to_y);
+    });
+    
+    var _html = Mustache.to_html(Tlns.Templates.Occurrence, {
+        occurrences:_(_visible).reject(function(_o) {return _o.in_cluster}),
+        clusters: _clusters,
+        open_cluster: _openCluster
+    });
+    this.$.find('.Tl-Occurrences').html(_html);
+    
+    
+    if (_openCluster) {
+        var _w = this.$.find('.Tl-Occurrence').width(),
+            _ww = _w * _openCluster.occurrences.length;
+        this.$.find('.Tl-ClusterOverlay').css({
+            "margin-left": - Math.floor(_ww/2) + "px",
+            width: _ww
+        });
+        _(_openCluster.occurrences).each(function(_o, _i) {
+            _o.y = _o.y - 20;
+            _o.x = _o.x - (_ww / 2) + ((_i + .5) * _w);
+        });
+    }
+    
+    this.$.find('.Tl-Occurrence').mousedown(function() {
+        var _el = $(this),
+            _id = _el.attr("occurrence-id");
+        if (typeof _id !== "undefined") {
+            _this.editing_occurrence = _this.getOccurrence(_id);
+            if (typeof _this.dragging_type === "undefined" && typeof _this.editing_occurrence !== "undefined" /* && !_this.editing_occurrence.locked */ ) {
+                _this.dragging_type = "occurrence";
+                _this.editing_occurrence.editing = true;
+            }
+        }
+    }).mouseover(function(_event) {
+        var _el = $(this),
+            _id = _el.attr("occurrence-id");
+        if (typeof _id !== "undefined") {
+            var _occurrence = _this.getOccurrence(_id);
+//            if (!_occurrence.locked) {
+            _el.find('.Tl-Link').show();
+//            }
+            if (!_this.is_dragging) {
+                var _html = Mustache.to_html(Tlns.Templates.OccurrenceTooltip, _occurrence);
+                _this.showTooltip(_occurrence.x, _occurrence.y, _html, (_event.pageY - _this.dragging_bounds.top) >= (.4 * _this.main_height) );
+            }
+        }
+    }).mouseout(function() {
+        var _el = $(this),
+            _id = _el.attr("occurrence-id");
+        if (typeof _id !== "undefined") {
+            var _occurrence = _this.getOccurrence(_id);
+            _this.hideTooltip();
+            if (!_occurrence.editing) {
+                $(this).find('.Tl-Link').hide();
+            }
+        }
+    }).mouseup(function() {
+        var _el = $(this);
+        if (_this.dragging_type == "link") {
+            var _target = _el.attr("occurrence-id");
+            if (_target != _this.editing_occurrence.id) {
+                _this.editing_occurrence.addDependency(_target);
+                $("body").trigger("AjoutDependanceTimeline",
+                    {
+                        id: _this.editing_occurrence.original_id,
+                        typeOccurrence: "occurrence" + _this.editing_occurrence.type.replace(/^./,function(_l) { return _l.toUpperCase()}),
+                        idCible: _target.replace(/^.*_/,''),
+                        typeOccurrenceCible: "occurrence" + _target.replace(/_.*$/,'').replace(/^./,function(_l) { return _l.toUpperCase()})
+                    }
+                );
+            }
+        }
+    });
+    
+    this.$.find('.Tl-Link').mousedown(function() {
+        var _el = $(this).parent(),
+            _id = _el.attr("occurrence-id");
+        _this.editing_occurrence = _this.getOccurrence(_id);
+        if (typeof _this.editing_occurrence !== "undefined" /* && !_this.editing_occurrence.locked */ ) {
+            _this.dragging_type = "link";
+            _this.editing_occurrence.editing = true;
+        }
+    })
+    
+    this.$.find('.Tl-Cluster').click(function() {
+        var _el = $(this),
+            _contents = _el.attr("cluster-contents");
+        if (_this.open_cluster == _contents) {
+            _this.open_cluster = false;
+        } else {
+            _this.open_cluster = _contents;
+        }
+        _this.throttledDrawGrid();
+    })
+}
+
+Tlns.Classes.Timeline.prototype.drawList = function() {
+    var _universfilter = this.$.find(".Ls-Univers li.Ls-Active").map(function(){return $(this).attr("data")}),
+        _occtypefilter = this.$.find(".Ls-Occtypes li.Ls-Active").map(function(){return $(this).attr("data")}),
+        _statusfilter = this.$.find(".Ls-Occstatuses li.Ls-Active").map(function(){return $(this).attr("data")}),
+        _jtfilter = this.$.find(".Ls-IsJt li.Ls-Active").map(function(){return !!+$(this).attr("data")}),
+        _title = this.$.find(".Ls-Search").val() || "",
+        _titleregexp = new RegExp( "(" + _title.replace(/(\W)/gm, "\\$1") + ")", "gim" ),
+        _startdate = false,
+        _enddate = false,
+        _fromDate = this.$.find(".Ls-From-Date").val(),
+        _toDate = this.$.find(".Ls-To-Date").val();
+    if (_fromDate) {
+        var _date = Tlns.Utils.dateFieldProcess(_fromDate),
+            _time = Tlns.Utils.timeFieldProcess(this.$.find(".Ls-From-Time").val());
+        _startdate = new Date(_date.year, _date.month - 1, _date.date, _time.hours, _time.minutes);
+    }
+    if (_toDate) {
+        var _date = Tlns.Utils.dateFieldProcess(_toDate),
+            _time = Tlns.Utils.timeFieldProcess(this.$.find(".Ls-To-Time").val());
+        _enddate = new Date(_date.year, _date.month - 1, _date.date, _time.hours, _time.minutes);
+    }
+    this.$.find(".Ls-Occurrences").html(
+        Mustache.to_html(
+            Tlns.Templates.Occurrence_List,
+            {
+                occurrences: this.occurrences.filter(function(_occ) {
+                    var _titletest = (!!_occ.title.match(_titleregexp)),
+                        _keep = (
+                               ( !_title || _titletest )
+                            && (_(_occtypefilter).indexOf(_occ.type) !== -1)
+                            && (_(_universfilter).indexOf(_occ.univers_id) !== -1)
+                            && (_(_statusfilter).indexOf(_occ.status) !== -1)
+                            && (_(_jtfilter).indexOf(_occ.jt) !== -1)
+                            && ( !_fromDate || _occ.date >= _startdate )
+                            && ( !_toDate || _occ.date <= _enddate )
+                        );
+                    return _keep;
+                })
+            }
+        )
+    );
+    if (_title) {
+        this.$.find(".Ls-Occurrence-Title").each(function() {
+            $(this).html($(this).text().replace(_titleregexp, "<span style='background:yellow'>$1</span>"));
+        });
+    }
+}
+
+Tlns.Classes.Timeline.prototype.getUnivers = function(_id) {
+    return _(this.univers).find(function(_univ) {
+        return (_univ.id == _id);
+    });
+}
+
+/*
+ * Univers
+ */
+
+Tlns.Classes.Univers = function(_data, _timeline, _index) {
+    this.id = _data.idUnivers;
+    this.index = _index;
+    this.title = _data.nomUnivers;
+//    this.mainCharacter = _data.personnage;
+    this.y = (_timeline.univers_height * _index);
+
+    this.$label = $('<li>').css({
+        height : _timeline.univers_height + "px"
+    }).html(Mustache.to_html(Tlns.Templates.Univers, this))
+      .addClass((_index % 2) ? 'Tl-Line-Odd' : 'Tl-Line-Even');
+    
+    _timeline.$.find('.Tl-UniversLabels').append(this.$label);
+    var _txt = this.title,
+        _span = this.$label.find('span');
+    while (_span.outerWidth() > (_timeline.width - _timeline.main_width) && _txt) {
+        _txt = _txt.substr(0, _txt.length - 1);
+        _span.html(_txt + '&hellip;');
+    }
+}
+
+/*
+ * Occurrence
+ */
+
+Tlns.Classes.Occurrence = function(_timeline) {
+    this.timeline = _timeline;
+}
+
+Tlns.Classes.Occurrence.prototype.update = function(_type, _data) {
+    this.type = _type;
+    if (typeof _data.idOccurrencePublication !== "undefined" || typeof _data.id !== "undefined" || typeof this.original_id === "undefined") {
+        this.original_id = _data.idOccurrencePublication || _data.id || Tlns.Utils.guid();
+    }
+    this.id = _type + "_" + this.original_id;
+    if (typeof _data.date !== "undefined" || typeof _data.datePublication !== "undefined") {
+        this.date = 1000 * (_data.datePublication || _data.date);
+    } else {
+        if (typeof this.date === "undefined") {
+            this.date = new Date().valueOf();
+        }
+    }
+    this.formatted_date = Tlns.Utils.dateFormat(this.date,Tlns.Defaults.Timeline.tooltip_date_format);
+    if (typeof _data.titre !== "undefined" || typeof this.title === "undefined") {
+        this.title = _data.titre || "<untitled>";
+    }
+    if (typeof _data.idUnivers !== "undefined") {
+        this.univers_id = _data.idUnivers;
+    }
+    this.univers = this.timeline.getUnivers(this.univers_id);
+    if (typeof _data.statut !== "undefined" || typeof this.status === "undefined") {
+        switch(_data.statut) {
+            case "Validée":
+            case "valide":
+                this.status = "valide"
+            break;
+            case "A valider":
+            case "a_valider":
+                this.status = "a_valider";
+            break;
+            case "A réaliser":
+            case "a_realiser":
+                this.status = "a_realiser";
+            break;
+            default:
+                this.status = false;
+        }
+    }
+    if (typeof _data.JT !== "undefined") {
+        this.jt = !!+_data.JT;
+    }
+    this.translated_status = Tlns.Defaults.Timeline.statuses[this.status];
+//    this.published = (_data.publication && _data.publication == "En ligne");
+//    this.locked = _data.verrouille || false;
+//    this.characters = _data.personnagesSecondaires || [];
+    this.dependsOn = [];
+    if (_data.dependanceNarrative) {
+        for (var _i = 0; _i < _data.dependanceNarrative.length; _i++) {
+            this.dependsOn.push("narrative_" + _data.dependanceNarrative[_i])
+        }
+    }
+    if (_data.dependancePublication) {
+        for (var _i = 0; _i < _data.dependancePublication.length; _i++) {
+            this.dependsOn.push("publication_" + _data.dependancePublication[_i])
+        }
+    }
+    var _tmp = $('<p>').html(_data.accroche || "");
+    this.description = _tmp.text().trim().replace(/(^.{60,80})[\s].+$/m,'$1&hellip;');
+}
+
+Tlns.Classes.Occurrence.prototype.addDependency = function(_id) {
+    if (_(this.dependsOn).indexOf(_id) == -1) {
+        this.dependsOn.push(_id);
+    }
+}
+
+Tlns.Classes.Occurrence.prototype.removeDependency = function(_id) {
+    this.dependsOn = _(this.dependsOn).reject(function(_n) {
+        return _n == _id;
+    });
+}
+
+Tlns.Classes.Occurrence.prototype.toString = function() {
+    return "Occurrence " + this.type + ': "' + this.title + '"';
+}
--- a/timeline/timeline.html	Wed Jul 18 18:23:49 2012 +0200
+++ b/timeline/timeline.html	Thu Jul 19 14:09:23 2012 +0200
@@ -13,7 +13,7 @@
                 text-align: center; font-size: 20px; font-weight: bold; margin: 5px;
             }
             #timeline {
-                width: 950px; margin: 5px auto;
+                width: 950px; margin: 5px auto; text-align: center;
             }
         </style>
         <script type="text/javascript" src="lib/jquery-min.js"> </script>