(function(global) {
  'use strict';
  var app = global.app || {};
  var m = global.m;
  var util = global.util;

  var translateX = util.translateX;

  var TimelineController = function(option) {
    this.title = m.prop(option.title);
    this.type = m.prop(option.type);
    this.data = m.prop(option.data);
    this.daysAgo = m.prop(option.daysAgo);
    this.daysAfter = m.prop(option.daysAfter);
    this.pixelsPerDay = m.prop(option.pixelsPerDay);
    this.selectedIndex = selectedIndexProp();
    this.titleElement = m.prop(null);
  };

  TimelineController.prototype.scrollLeft = function(value) {
    var titleElement = this.titleElement();
    if (titleElement)
      translateX(titleElement, value);
  };

  TimelineController.prototype.dispatchEvent = function(event) {
    switch (event.type) {
    case 'init':
      this.titleElement(event.titleElement);
      break;
    case 'select':
      this.selectedIndex(event.selectedIndex);
      break;
    default:
      break;
    }
  };

  var selectedIndexProp = function() {
    var selectedIndex = m.prop(null);
    return function(value) {
      if (typeof value === 'undefined') {
        value = selectedIndex();
        var type = this.type();
        if (value === null)
          return (type === TimelineController.TYPE_GANTT_CHART) ? [-1, -1] : -1;
        else
          return value;
      }
      selectedIndex(value);
    };
  };

  TimelineController.TYPE_LINE_CHART = 'line-chart';
  TimelineController.TYPE_BAR_CHART = 'bar-chart';
  TimelineController.TYPE_SCHEDULE = 'schedule';
  TimelineController.TYPE_GANTT_CHART = 'gantt-chart';

  app.TimelineController = TimelineController;
  global.app = app;
})(this);
@@ -185,24 +185,122 @@
 n(option) %7B%0A
+    this.url = m.prop(option.url);%0A    this.state = m.prop(TimelineController.STATE_INITIALIZED);%0A
     this.tit
@@ -322,24 +322,24 @@
 ion.title);%0A
-
     this.typ
@@ -625,32 +625,288 @@
 op(null);%0A  %7D;%0A%0A
+  TimelineController.prototype.fetch = function() %7B%0A    var url = this.url();%0A    return m.request(%7B%0A      method: 'GET',%0A      url: url,%0A      extract: requestExtract,%0A    %7D).then(requestSuccessCallback.bind(this), requestErrorCallback.bind(this));%0A  %7D;%0A%0A
   TimelineContro
@@ -1747,22 +1747,1157 @@
 %0A    %7D;%0A
-
   %7D;%0A%0A
+  var requestExtract = function(xhr) %7B%0A    return xhr.status %3E 200 ? JSON.stringify(xhr.responseText) : xhr.responseText;%0A  %7D;%0A%0A  var requestSuccessCallback = function(result) %7B%0A    var title = result.title;%0A    var type = result.type;%0A    var data = result.data;%0A%0A    if (type === TimelineController.TYPE_GANTT_CHART) %7B%0A      data = data.map(function(item) %7B%0A        item.data = parseDateProperty(item.data);%0A        item.deadline = new Date(item.deadline);%0A        return item;%0A      %7D);%0A    %7D else %7B%0A      data = parseDateProperty(data);%0A    %7D%0A%0A    this.title(title);%0A    this.type(type);%0A    this.data(data);%0A    this.state(TimelineController.STATE_LOAD_COMPLETE);%0A    return this;%0A  %7D;%0A%0A  var requestErrorCallback = function() %7B%0A    this.state(TimelineController.STATE_LOAD_ERROR);%0A    return this;%0A  %7D;%0A%0A  var parseDateProperty = function(array) %7B%0A    return array.map(function(item) %7B%0A      item.date = new Date(item.date);%0A      return item;%0A    %7D);%0A  %7D;%0A%0A  TimelineController.STATE_INITIALIZED = 'initialized';%0A  TimelineController.STATE_LOAD_COMPLETE = 'load-complete';%0A  TimelineController.STATE_LOAD_ERROR = 'load-error';%0A%0A
   Timeli

Support fetching timeline data using JSON