// Generated by CoffeeScript 1.11.0 var AppRouter, DynamicChartView, DynamicWidget, DynamicWidgetView, LinePresenter, PageInfo, PageInfoList, PageTitleView, PageTitlesView, SensorInfo, SensorInfoList, SensorInfoListView, SeriesPresenter, StackPresenter, TimelinePresenter, Widget, WidgetChartView, WidgetList, WidgetListView, WidgetPresenter, WidgetView,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty;
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
String.prototype.strip = function() {
if (String.prototype.trim != null) { return this.trim(); } else { return this.replace(/^\s+|\s+$/g, ""); }
};
Number.prototype.humanize = function() {
var d, h, interval, m, res, s; interval = this; res = ""; s = interval % 60; if (s > 0) { res = s + " s"; } interval = (interval - s) / 60; if (!(interval > 0)) { return res; } m = interval % 60; if (m > 0) { res = (m + " m " + res).strip(); } interval = (interval - m) / 60; if (!(interval > 0)) { return res; } h = interval % 24; if (h > 0) { res = (h + " h " + res).strip(); } d = (interval - h) / 24; if (d > 0) { return (d + " d " + res).strip(); } else { return res; }
};
PageInfo = Backbone.Model.extend({});
Widget = Backbone.Model.extend({
initialize: function() { this.updating = false; this.needRefresh = true; this.setNextFetch(); return this.timespanInc = 0; }, setStartTime: function(startTime) { this.startTime = startTime; }, setEndTime: function(endTime) { this.endTime = endTime; }, increaseTimespan: function(inc) { this.timespanInc = this.timespanInc + inc; return this.forceUpdate(); }, resetTimespan: function() { this.timespanInc = 0; this.startTime = null; this.endTime = null; return this.forceUpdate(); }, timespan: function() { return this.get('timespan') + this.timespanInc; }, url: function() { var timespan, url; timespan = this.timespan(); url = (this.collection.url()) + "/" + (this.get('id')) + "?"; if (!_.isNaN(timespan)) { url += "×pan=" + timespan; } if (this.startTime) { url += "&startTime=" + this.startTime; } if (this.endTime) { url += "&endTime=" + this.endTime; } return url; }, time: function() { return (new Date()).getTime(); }, setNextFetch: function() { return this.nextFetch = this.time() + this.get('redrawInterval') * 1000; }, setRefresh: function(needRefresh) { return this.needRefresh = needRefresh; }, needFetch: function() { var interval; interval = this.get('redrawInterval'); return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0; }, refetch: function() { if (this.needFetch()) { this.forceUpdate(); return this.setNextFetch(); } }, setUpdated: function() { return this.updating = false; }, forceUpdate: function() { var xhr; if (this.updating) { return; } this.updating = true; xhr = this.fetch({ success: (function(_this) { return function(model, response) { return _this.trigger('redraw'); }; })(this) }); xhr.always((function(_this) { return function() { return _this.updating = false; }; })(this)); return xhr.fail((function(_this) { return function(xhr, textStatus, errorThrown) { return console.log("xhr fail", _this.get('id'), textStatus, errorThrown); }; })(this)); }
});
DynamicWidget = Backbone.Model.extend({
setStartTime: function(startTime) { this.startTime = startTime; }, setEndTime: function(endTime) { this.endTime = endTime; }, increaseTimespan: function(inc) { return this.set('timespan', this.timespan() + inc); }, resetTimespan: function() { this.startTime = null; this.endTime = null; return this.set('timespan', null); }, timespan: function() { return this.get('timespan'); }, sensorArgs: function() { return _.map(this.get('sensorIds'), function(name) { return "sensor[]=" + name; }).join('&'); }, url: function() { var timespan, url; timespan = this.timespan(); url = ROOT + "dynamic_widget?" + (this.sensorArgs()) + "&type=" + (this.get('type')); if ((timespan != null) && !_.isNaN(timespan)) { url += "×pan=" + timespan; } if (this.startTime) { url += "&startTime=" + this.startTime; } if (this.endTime) { url += "&endTime=" + this.endTime; } return url; }, forceUpdate: function() { return this.fetch({ success: function(model, response) { return model.trigger('redraw'); } }); }
});
SensorInfo = Backbone.Model.extend({});
PageInfoList = Backbone.Collection.extend({
model: PageInfo, selected: function() { return this.find(function(m) { return m.get('selected'); }); }, selectFirst: function() { if (this.length > 0) { return this.at(0).set('selected', true); } }, selectNone: function() { return this.each(function(m) { return m.set('selected', false); }); }, selectPage: function(id) { return this.each(function(m) { return m.set('selected', m.id === id); }); }
});
SensorInfoList = Backbone.Collection.extend({
model: SensorInfo, url: function() { return ROOT + 'sensors'; }
});
WidgetList = Backbone.Collection.extend({
model: Widget, setContext: function(pageInfos1) { this.pageInfos = pageInfos1; }, url: function() { return ROOT + 'pages/' + this.pageInfos.selected().id + '/widgets'; }, startPolling: function() { return setInterval((function(_this) { return function() { if (_this.pageInfos.selected()) { return _this.each(function(w) { return w.refetch(); }); } }; })(this), 200); }
});
WidgetPresenter = (function() {
function WidgetPresenter(pageInfos1, model1, el1) { this.pageInfos = pageInfos1; this.model = model1; this.el = el1; this.chartEl = this.el.find('#chart')[0]; this.legendEl = this.el.find('#legend')[0]; this.chart = new Dygraph.GVizChart(this.chartEl); this.draw(); } WidgetPresenter.prototype.get = function(arg) { return this.model.get(arg); }; WidgetPresenter.prototype.globalOptions = function() { return gon.options; }; WidgetPresenter.prototype.dateOffset = function() { if (this.globalOptions.useUtc) { return (new Date).getTimezoneOffset() * 60000; } else { return 0; } }; WidgetPresenter.prototype.options = function() { return { labelsDiv: this.legendEl, labelsSeparateLines: false, rightGap: 30, highlightCircleSize: 2, highlightSeriesOpts: { strokeWidth: 2, strokeBorderWidth: 1, highlightCircleSize: 5 }, axisLabelWidth: 80 }; }; WidgetPresenter.prototype.mergedOptions = function() { var pageOptions; pageOptions = this.pageInfos.selected() ? this.pageInfos.selected().get('dygraphsOptions') : {}; return $.extend(true, this.options(), this.globalOptions().dygraphsOptions, pageOptions, this.get('dygraphsOptions')); }; WidgetPresenter.prototype.data = function() { return new google.visualization.DataTable; }; WidgetPresenter.prototype.draw = function() { return this.chart.draw(this.data(), this.mergedOptions()); }; return WidgetPresenter;
})();
WidgetPresenter.create = function(pageInfos, model, el) {
var presenterClass, type; type = model.get('type'); if ((type != null) && type.match(/^\w+$/)) { presenterClass = eval((type.capitalize()) + "Presenter"); return new presenterClass(pageInfos, model, el); } else { return null; }
};
TimelinePresenter = (function(superClass) {
extend(TimelinePresenter, superClass); function TimelinePresenter() { return TimelinePresenter.__super__.constructor.apply(this, arguments); } TimelinePresenter.prototype.data = function() { var data, dateOffset, series; data = TimelinePresenter.__super__.data.call(this); data.addColumn('datetime', 'Time'); dateOffset = this.dateOffset() + this.get('interval') * 1000; series = this.get('series'); _.each(series.titles, function(t) { return data.addColumn('number', t); }); _.each(series.rows, function(row) { row[0] = new Date(row[0] + dateOffset); return data.addRow(row); }); return data; }; return TimelinePresenter;
})(WidgetPresenter);
SeriesPresenter = (function(superClass) {
extend(SeriesPresenter, superClass); function SeriesPresenter() { return SeriesPresenter.__super__.constructor.apply(this, arguments); } SeriesPresenter.prototype.options = function() { return $.extend(true, SeriesPresenter.__super__.options.call(this), { title: this.get('title'), legend: 'always', height: 300, ylabel: this.valuesTitle(), colors: this.colors() }); }; SeriesPresenter.prototype.valuesTitle = function() { if (this.get('valuesTitle')) { return (this.get('valuesTitle')) + " / " + (this.humanizedInterval()); } else { return this.humanizedInterval(); } }; SeriesPresenter.prototype.colors = function() { return _.map(this.get('series').options, function(o) { return o.color; }); }; SeriesPresenter.prototype.humanizedInterval = function() { return this.get('interval').humanize(); }; return SeriesPresenter;
})(TimelinePresenter);
LinePresenter = (function(superClass) {
extend(LinePresenter, superClass); function LinePresenter() { return LinePresenter.__super__.constructor.apply(this, arguments); } return LinePresenter;
})(SeriesPresenter);
StackPresenter = (function(superClass) {
extend(StackPresenter, superClass); function StackPresenter() { return StackPresenter.__super__.constructor.apply(this, arguments); } return StackPresenter;
})(SeriesPresenter);
PageTitleView = Backbone.View.extend({
tagName: 'li', template: _.template('<a href="#/pages/<%= id %>"><%= title %></a>'), initialize: function() { this.model.bind('change', this.render, this); return this.model.bind('destroy', this.remove, this); }, render: function() { this.$el.html(this.template(this.model.toJSON())); if (this.model.get('selected')) { return this.$el.addClass('active'); } else { return this.$el.removeClass('active'); } }
});
PageTitlesView = Backbone.View.extend({
initialize: function(pageInfos1) { this.pageInfos = pageInfos1; return this.pageInfos.bind('reset', this.render, this); }, addOne: function(pageInfo) { var view; view = new PageTitleView({ model: pageInfo }); view.render(); return $('#page-titles').append(view.el); }, render: function() { $('#page-titles').empty(); return this.pageInfos.each(this.addOne); }
});
SensorInfoListView = Backbone.View.extend({
tagName: 'div', template: function() { return _.template($("#sensor-list").html()); }, initialize: function(sensorInfo) { this.sensorInfo = sensorInfo; return this.sensorInfo.bind('reset', this.render, this); }, render: function() { return this.$el.html(this.template()({ sensors: this.sensorInfo.toJSON() })); }, selectedSensors: function() { var checked, ids, selected; checked = _.filter(this.$el.find('.sensor-box'), function(el) { return $(el).is(':checked'); }); ids = {}; _.each(checked, function(box) { return ids[box.id] = true; }); return selected = this.sensorInfo.filter(function(sensor) { return ids[sensor.id]; }); }
});
DynamicChartView = Backbone.View.extend({
initialize: function(options) { this.pageInfos = options['pageInfos']; this.sensors = []; this.type = 'Area'; this.widget = new DynamicWidget; this.widget.bind('destroy', this.remove, this); return this.widget.bind('redraw', this.redrawChart, this); }, tagName: 'div', events: { "click #refresh-chart": 'update', "click #extend-timespan": 'extendTimespan', "click #reset-timespan": 'resetTimespan', "change #start-time input": 'maybeEnableStopTime', "click #set-interval": 'setTimelineInterval' }, template: function() { return _.template($("#dynamic-widget-plotarea").html()); }, chartContainerTemplate: '<div id="chart"></div><div id="legend"></div>', render: function() { this.$el.html(this.template()()); return this.initDatePickers(); }, initDatePickers: function() { this.$el.find(".datepicker").each(function(i) { return $(this).datetimepicker({ showOtherMonths: true, selectOtherMonths: true }); }); return this.$el.find("#end-time input").prop("disabled", true); }, setTimelineInterval: function() { var end, start; start = this.unixtimeFromDatepicker("#start-time input"); end = this.unixtimeFromDatepicker("#end-time input"); this.widget.setStartTime(start); this.widget.setEndTime(end); return this.update(); }, dateFromDatepicker: function(id) { return this.$el.find(id).datetimepicker("getDate"); }, unixtimeFromDatepicker: function(id) { var date; date = this.dateFromDatepicker(id); if (date) { return date.getTime() / 1000; } else { return null; } }, maybeEnableStopTime: function() { var date, disabled; date = this.dateFromDatepicker("#start-time input"); disabled = date ? false : true; return this.$el.find("#end-time input").prop("disabled", disabled); }, extendTimespan: function() { var select, val; select = this.$el.find("#extend-timespan-val"); val = select.first().val(); this.widget.increaseTimespan(parseInt(val)); return this.update(); }, resetTimespan: function() { this.widget.resetTimespan(); return this.update(); }, sensorIds: function() { return _.map(this.sensors, function(s) { return s.id; }); }, redrawChart: function() { if (this.presenter) { return this.presenter.draw(); } else { return this.presenter = WidgetPresenter.create(this.pageInfos, this.widget, this.chartContainer()); } }, chartContainer: function() { return $(this.$el.find('#chart-widget')[0]); }, update: function() { if (this.sensors.length > 0) { return this.widget.forceUpdate(); } }, draw: function(sensors, type) { this.sensors = sensors; this.type = type; this.widget.set('sensorIds', this.sensorIds()); this.widget.set('type', this.type); this.presenter = null; this.chartContainer().html(this.chartContainerTemplate); return this.widget.forceUpdate(); }
});
DynamicWidgetView = Backbone.View.extend({
tagName: 'div', initialize: function(options) { this.pageInfos = options['pageInfos']; this.sensorInfo = new SensorInfoList; this.sensorListView = new SensorInfoListView(this.sensorInfo); this.chartView = new DynamicChartView({ pageInfos: this.pageInfos }); this.$el.html(this.template()()); this.$el.find('#sensor-list-area').append(this.sensorListView.el); this.chartView.render(); return this.$el.find('#dynamic-plotarea').append(this.chartView.el); }, events: { "click #sensor-controls #refresh": 'refresh', "click #sensor-controls #draw": 'drawChart' }, template: function() { return _.template($("#dynamic-widget").html()); }, errorTemplate: function() { return _.template($("#dynamic-widget-error").html()); }, error: function(error) { return this.$el.find('#errors').append(this.errorTemplate()({ error: error })); }, refresh: function() { return this.sensorInfo.fetch(); }, intervalsEqual: function(sensors) { var badIntervals, interval; interval = sensors[0].get('interval'); badIntervals = _.filter(sensors, function(s) { return s.get('interval') !== interval; }); return badIntervals.length === 0; }, drawChart: function() { var selectedSensors, type; selectedSensors = this.sensorListView.selectedSensors(); if (!(selectedSensors.length > 0)) { return; } if (!this.intervalsEqual(selectedSensors)) { this.error('Selected sensors have different intervals'); return; } type = this.$el.find('#chart-type').val(); return this.chartView.draw(selectedSensors, type); }, render: function(container) { container.empty(); container.append(this.$el); this.sensorInfo.fetch(); return this.chartView.update(); }
});
WidgetChartView = Backbone.View.extend({
tagName: 'div', template: '<div id="chart"></div><div id="legend"></div>', initialize: function(options) { this.$el.html(this.template); this.pageInfos = options['pageInfos']; return this.model.bind('destroy', this.remove, this); }, updateData: function() { return this.presenter.draw(); }, render: function() { return this.presenter = WidgetPresenter.create(this.pageInfos, this.model, this.$el); }
});
WidgetView = Backbone.View.extend({
tagName: 'div', template: function(args) { return _.template($(".widget-template[data-widget-type=\"" + (this.model.get('type')) + "\"]").html())(args); }, initialize: function(options) { this.pageInfos = options['pageInfos']; this.model.bind('destroy', this.remove, this); return this.model.bind('redraw', this.updateChart, this); }, events: { "click #refresh": 'refresh', "click #need-refresh": 'setRefresh', "click #extend-timespan": 'extendTimespan', "click #reset-timespan": 'resetTimespan', "change #start-time input": 'maybeEnableStopTime', "click #set-interval": 'setTimelineInterval' }, refresh: function() { return this.model.forceUpdate(); }, setRefresh: function() { var needRefresh; needRefresh = this.$el.find('#need-refresh').is(":checked"); this.model.setRefresh(needRefresh); return true; }, extendTimespan: function() { var select, val; select = this.$el.find("#extend-timespan-val"); val = select.first().val(); return this.model.increaseTimespan(parseInt(val)); }, setTimelineInterval: function() { var end, start; start = this.unixtimeFromDatepicker("#start-time input"); end = this.unixtimeFromDatepicker("#end-time input"); this.model.setStartTime(start); return this.model.setEndTime(end); }, maybeEnableStopTime: function() { var date, disabled; date = this.dateFromDatepicker("#start-time input"); disabled = date ? false : true; return this.$el.find("#end-time input").prop("disabled", disabled); }, resetTimespan: function() { return this.model.resetTimespan(); }, renderChart: function() { return this.chartView.render(); }, updateChart: function() { return this.chartView.updateData(); }, setIds: function() { this.$el.find('#configure-button').prop('href', "#configure-" + this.model.id); this.$el.find('#configure').attr('id', "configure-" + this.model.id); this.$el.find('#start-time input').attr('id', "start-time-" + this.model.id); return this.$el.find('#end-time input').attr('id', "end-time-" + this.model.id); }, render: function() { this.$el.html(this.template(this.model.toJSON())); this.setIds(); this.chartView = new WidgetChartView({ pageInfos: this.pageInfos, model: this.model }); this.$el.find("#plotarea").append(this.chartView.el); this.$el.addClass("span" + (this.model.get('width'))); return this.initDatePickers(); }, initDatePickers: function() { this.$el.find(".datepicker").each(function(i) { return $(this).datetimepicker({ showOtherMonths: true, selectOtherMonths: true }); }); return this.$el.find("#end-time input").prop("disabled", true); }, controlValue: function(id) { var val; return val = this.$el.find(id).first().val(); }, dateFromDatepicker: function(id) { return this.$el.find(id).datetimepicker("getDate"); }, unixtimeFromDatepicker: function(id) { var date; date = this.dateFromDatepicker(id); if (date) { return date.getTime() / 1000; } else { return null; } }
});
WidgetListView = Backbone.View.extend({
initialize: function(options) { this.widgetList = options['widgetList']; this.pageInfos = options['pageInfos']; return this.widgetList.bind('reset', this.render, this); }, render: function() { var container; container = $('#widgets'); container.empty(); return this.widgetList.each((function(_this) { return function(w) { var view; view = new WidgetView({ pageInfos: _this.pageInfos, model: w }); view.render(); container.append(view.el); return view.renderChart(); }; })(this)); }
});
AppRouter = Backbone.Router.extend({
initialize: function(pageInfos1, widgetList1) { this.pageInfos = pageInfos1; this.widgetList = widgetList1; }, routes: { 'pages/:id': 'getPage', 'custom': 'custom', '*actions': 'defaultRoute' }, getPage: function(ids) { var id; id = parseInt(ids); this.pageInfos.selectPage(id); return this.widgetList.fetch(); }, custom: function() { var dynamicWidget; this.pageInfos.selectNone(); dynamicWidget = new DynamicWidgetView({ pageInfos: this.pageInfos }); return dynamicWidget.render($('#widgets')); }, defaultRoute: function(actions) { if (this.pageInfos.length > 0) { return this.navigate('//pages/1'); } else { return this.navigate('//custom'); } }
});
document.startApp = function() {
var appRouter, pageInfos, pageTitlesApp, widgetList, widgetListApp; pageInfos = new PageInfoList; pageTitlesApp = new PageTitlesView(pageInfos); pageInfos.reset(gon.pageInfos); widgetList = new WidgetList; widgetList.setContext(pageInfos); widgetList.startPolling(); widgetListApp = new WidgetListView({ widgetList: widgetList, pageInfos: pageInfos }); appRouter = new AppRouter(pageInfos, widgetList); return Backbone.history.start();
};