diff -r 00a3532ad8cf -r bf6adf981cc2 timeline/js/timeline.js --- /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 = '
' + + '
--/--
' + + '
' + + '
{{#timescales}}
{{label}}
{{/timescales}}
' + + '
' + + '
' + + '
  • Ajout d\'une occurrence
  • Narrative
  • ' + + '
  • De Publication
' + + '
' + + +'

Filtres :

' + + '

Univers :

    ' + + '

    Type d\'occurrence :

    • Narratives
    • de Publication
    ' + + '

    Statut :

    • À réaliser
    • À valider
    • Validé
    ' + + '

    Est au JT :

    • Oui
    • Non
    ' + + '

    Recherche par titre :

    Date :

    ' + + '

    Occurrences :

    '; + +Tlns.Templates.Univers = '{{title}}'; + +Tlns.Templates.Univers_List = '{{#univers}}
  • {{title}}
  • {{/univers}}'; + +Tlns.Templates.Occurrence = '{{#clusters}}
    ' + + '
    {{occurrences.length}}
    {{/clusters}}' + + '{{#occurrences}}
    ' +// + '{{#locked}}
    {{/locked}}' + + '
    {{/occurrences}}{{#open_cluster}}
    ' + + '{{#occurrences}}
    ' + + '{{#locked}}
    {{/locked}}
    {{/occurrences}}
    {{/open_cluster}}'; + +Tlns.Templates.Occurrence_List = '{{#occurrences}}
  • {{title}}

    ' + + '

    {{formatted_date}} — {{univers.title}} — {{translated_status}} — {{#jt}}Au JT{{/jt}}{{^jt}}Hors JT{{/jt}}

  • {{/occurrences}}'; + +Tlns.Templates.OccurrenceTooltip = '

    {{title}}

    {{formatted_date}} — {{translated_status}}

    ' + + '

    {{description}}

    ' +// + '

    {{univers.mainCharacter}}{{#characters}}, {{.}}{{/characters}}

    ' + +/* 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: '', + 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 += '
    ' + + '
    ' + Tlns.Utils.dateFormat(_t, _timescale.grid_date_format) + '
    '; + } + } + if (this.start_time <= _now && this.end_time >= _now) { + _html += '
    ' + } + 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, "$1")); + }); + } +} + +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 = $('
  • ').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 + '…'); + } +} + +/* + * 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 || ""; + } + 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 = $('

    ').html(_data.accroche || ""); + this.description = _tmp.text().trim().replace(/(^.{60,80})[\s].+$/m,'$1…'); +} + +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 + '"'; +}