• Jump To … +
    backend.dataproxy.js backend.memory.js ecma-fixes.js model.js view.flot.js view.graph.js view.grid.js view.map.js view.multiview.js view.slickgrid.js view.timeline.js widget.facetviewer.js widget.fields.js widget.filtereditor.js widget.pager.js widget.queryeditor.js widget.valuefilter.js
  • view.timeline.js

  • ¶
    /*jshint multistr:true */
    
    this.recline = this.recline || {};
    this.recline.View = this.recline.View || {};
    
    (function($, my) {
      "use strict";
  • ¶

    turn off unnecessary logging from VMM Timeline

    if (typeof VMM !== 'undefined') {
      VMM.debug = false;
    }
  • ¶

    Timeline

    Timeline view using http://timeline.verite.co/

    my.Timeline = Backbone.View.extend({
      template: ' \
        <div class="recline-timeline"> \
          <div id="vmm-timeline-id"></div> \
        </div> \
      ',
  • ¶

    These are the default (case-insensitive) names of field that are used if found. If not found, the user will need to define these fields on initialization

      startFieldNames: ['date','startdate', 'start', 'start-date'],
      endFieldNames: ['end','endDate'],
      elementId: '#vmm-timeline-id',
    
      initialize: function(options) {
        var self = this;
        this.timeline = new VMM.Timeline(this.elementId);
        this._timelineIsInitialized = false;
        this.listenTo(this.model.fields, 'reset', function() {
          self._setupTemporalField();
        });
        this.listenTo(this.model.records, 'all', function() {
          self.reloadData();
        });
        var stateData = _.extend({
            startField: null,
            endField: null,
  • ¶

    by default timelinejs (and browsers) will parse ambiguous dates in US format (mm/dd/yyyy) set to true to interpret dd/dd/dddd as dd/mm/yyyy

            nonUSDates: false,
            timelineJSOptions: {}
          },
          options.state
        );
        this.state = new recline.Model.ObjectState(stateData);
        this._setupTemporalField();
      },
    
      render: function() {
        var tmplData = {};
        var htmls = Mustache.render(this.template, tmplData);
        this.$el.html(htmls);
  • ¶

    can only call _initTimeline once view in DOM as Timeline uses $ internally to look up element

        if ($(this.elementId).length > 0) {
          this._initTimeline();
        }
      },
    
      show: function() {
  • ¶

    only call _initTimeline once view in DOM as Timeline uses $ internally to look up element

        if (this._timelineIsInitialized === false) {
          this._initTimeline();
        }
      },
    
      _initTimeline: function() {
        var data = this._timelineJSON();
        var config = this.state.get("timelineJSOptions");
        config.id = this.elementId;
        this.timeline.init(config, data);
        this._timelineIsInitialized = true
      },
    
      reloadData: function() {
        if (this._timelineIsInitialized) {
          var data = this._timelineJSON();
          this.timeline.reload(data);
        }
      },
  • ¶

    Convert record to JSON for timeline

    Designed to be overridden in client apps

      convertRecord: function(record, fields) {
        return this._convertRecord(record, fields);
      },
  • ¶

    Internal method to generate a Timeline formatted entry

      _convertRecord: function(record, fields) {
        var start = this._parseDate(record.get(this.state.get('startField')));
        var end = this._parseDate(record.get(this.state.get('endField')));
        if (start) {
          var tlEntry = {
            "startDate": start,
            "endDate": end,
            "headline": String(record.get('title') || ''),
            "text": record.get('description') || record.summary(),
            "tag": record.get('tags')
          };
          return tlEntry;
        } else {
          return null;
        }
      },
    
      _timelineJSON: function() {
        var self = this;
        var out = {
          'timeline': {
            'type': 'default',
            'headline': '',
            'date': [
            ]
          }
        };
        this.model.records.each(function(record) {
          var newEntry = self.convertRecord(record, self.fields);
          if (newEntry) {
            out.timeline.date.push(newEntry); 
          }
        });
  • ¶

    if no entries create a placeholder entry to prevent Timeline crashing with error

        if (out.timeline.date.length === 0) {
          var tlEntry = {
            "startDate": '2000,1,1',
            "headline": 'No data to show!'
          };
          out.timeline.date.push(tlEntry);
        }
        return out;
      },
  • ¶

    convert dates into a format TimelineJS will handle TimelineJS does not document this at all so combo of read the code + trial and error Summary (AFAICt): Preferred: [-]yyyy[,mm,dd,hh,mm,ss] Supported: mm/dd/yyyy

      _parseDate: function(date) {
        if (!date) {
          return null;
        }
        var out = $.trim(date);
        out = out.replace(/(\d)th/g, '$1');
        out = out.replace(/(\d)st/g, '$1');
        out = $.trim(out);
        if (out.match(/\d\d\d\d-\d\d-\d\d(T.*)?/)) {
          out = out.replace(/-/g, ',').replace('T', ',').replace(':',',');
        }
        if (out.match(/\d\d-\d\d-\d\d.*/)) {
          out = out.replace(/-/g, '/');
        }
        if (this.state.get('nonUSDates')) {
          var parts = out.match(/(\d\d)\/(\d\d)\/(\d\d.*)/);
          if (parts) {
            out = [parts[2], parts[1], parts[3]].join('/');
          }
        }
        return out;
      },
    
      _setupTemporalField: function() {
        this.state.set({
          startField: this._checkField(this.startFieldNames),
          endField: this._checkField(this.endFieldNames)
        });
      },
    
      _checkField: function(possibleFieldNames) {
        var modelFieldNames = this.model.fields.pluck('id');
        for (var i = 0; i < possibleFieldNames.length; i++){
          for (var j = 0; j < modelFieldNames.length; j++){
            if (modelFieldNames[j].toLowerCase() == possibleFieldNames[i].toLowerCase())
              return modelFieldNames[j];
          }
        }
        return null;
      }
    });
    
    })(jQuery, recline.View);