1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/6f56754324a6/ Changeset: 6f56754324a6 User: guerler Date: 2014-01-13 11:53:01 Summary: Visualization plugin: Wrapper for nvd3/d3 Affected #: 28 files diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/config/charts.xml --- /dev/null +++ b/config/plugins/visualizations/charts/config/charts.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE visualization SYSTEM "../../visualization.dtd"> +<visualization name="charts"> + <data_sources> + <data_source> + <model_class>HistoryDatasetAssociation</model_class> + <test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test> + <to_param param_attr="id">dataset_id</to_param> + </data_source> + </data_sources> + <params> + <param type="dataset" var_name_in_template="hda" required="true">dataset_id</param> + </params> + <template>charts.mako</template> +</visualization> diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/app.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/app.js @@ -0,0 +1,67 @@ +// dependencies +define(['library/portlet', 'library/ui', 'library/utils', + 'main', 'viewport', 'create', 'config', + 'models/datasets', 'models/chart', 'models/charts', 'models/types'], + function( Portlet, Ui, Utils, + Main, Viewport, Create, Config, + Datasets, Chart, Charts, Types + ) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(options) + { + // link options + this.options = options; + + // link galaxy + this.modal = parent.Galaxy.modal; + + // create chart objects + this.types = new Types(); + this.chart = new Chart(); + this.charts = new Charts(this); + + // create dataset handler + this.datasets = new Datasets(this); + + // create views + this.main = new Main(this); + this.viewport = new Viewport(this); + this.config = new Config(this); + this.create = new Create(this); + + // portlet + this.portlet = new Portlet({icon : 'fa-bar-chart-o', label : 'Charts'}); + this.portlet.append(this.main.$el); + this.portlet.append(this.config.$el); + this.portlet.append(this.create.$el); + + // append main + this.main.append(this.viewport.$el); + + // create + this.config.$el.hide(); + this.create.$el.hide(); + + // set elements + this.setElement(this.portlet.$el); + }, + + // execute command + execute: function(options) { + }, + + // unload + onunload: function() { + }, + + // log + log: function(location, message) { + console.log(location + ' ' + message); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/bardiagram.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/bardiagram.js @@ -0,0 +1,34 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + self.d3_chart = nv.models.multiBarChart(); + + self.d3_chart.xAxis.tickFormat(d3.format('.2f')) + self.d3_chart.yAxis.tickFormat(d3.format('.1f')) + + d3.select(self.options.svg_id) + .datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/horizontal.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/horizontal.js @@ -0,0 +1,33 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + self.d3_chart = nv.models.multiBarHorizontalChart(); + + self.d3_chart.xAxis.tickFormat(function() { return ''; }); + + d3.select(self.options.svg_id) + .datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/line.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/line.js @@ -0,0 +1,39 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + self.chart_3d = nv.models.lineChart(); + + self.chart_3d.xAxis + .tickFormat(d3.format(',f')); + + self.chart_3d.yAxis + .tickFormat(d3.format(',.2f')); + + d3.select(self.options.svg_id) + .datum(data) + .call(self.chart_3d); + + nv.utils.windowResize(self.chart_3d.update); + + return self.chart_3d; + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/linewithfocus.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/linewithfocus.js @@ -0,0 +1,37 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + self.chart_3d = nv.models.lineWithFocusChart(); + + self.chart_3d.xAxis + .tickFormat(d3.format(',f')); + + self.chart_3d.yAxis + .tickFormat(d3.format(',.2f')); + + d3.select(self.options.svg_id) + .datum(data) + .call(self.chart_3d); + + nv.utils.windowResize(self.chart_3d.update); + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/piechart.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/piechart.js @@ -0,0 +1,59 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function() + { + // add graph to screen + var self = this; + nv.addGraph(function(data) { + self.chart_3d = nv.models.pieChart() + .x(function(d) { return d.key }) + .y(function(d) { return d.y }) + .color(d3.scale.category10().range()) + .height(250) + .width(250); + + d3.select(self.options.svg_id) + .datum(self._data()) + .transition().duration(1200) + .attr('height', 250) + .attr('width', 250) + .call(self.chart_3d); + + nv.utils.windowResize(self.chart_3d.update); + }); + }, + + _data : function() { + return [ + { + key: "Cumulative Return", + values: [ + { + key : "CDS / Options" , + y : 29.765957771107 + }, + { + key : "Options" , + y : 19.765957771107 + }, + { + key : "Other" , + y : 12.765957771107 + }] + }]; + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/scatterplot.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/scatterplot.js @@ -0,0 +1,37 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + self.d3_chart = nv.models.scatterChart() + .showDistX(true) + .showDistY(true) + .color(d3.scale.category10().range()); + + self.d3_chart.xAxis.tickFormat(d3.format('.02f')) + self.d3_chart.yAxis.tickFormat(d3.format('.02f')) + + d3.select(self.options.svg_id) + .datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/charts/stackedarea.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/charts/stackedarea.js @@ -0,0 +1,59 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// widget +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + this.app = app; + this.options = options; + this.chart = options.chart; + }, + + // render + refresh : function(data) + { + // add graph to screen + var self = this; + nv.addGraph(function() { + // check data + var valid = true; + var length = 0; + for (var key in data) { + // evalute length + if (length == 0) { + length = data[key].values.length; + } else { + if (length != data[key].values.length) { + valid = false; + break; + } + } + } + if (!valid) { + return; + } + + // make plot + self.d3_chart = nv.models.stackedAreaChart() + .x(function(d) { + return d.x + }) + .y(function(d) { + return d.y + }) + .clipEdge(true); + + self.d3_chart.xAxis.tickFormat(function() { return ''; }); + + d3.select(self.options.svg_id) + .datum(data) + .call(self.d3_chart); + + nv.utils.windowResize(self.d3_chart.update); + }); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/config.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/config.js @@ -0,0 +1,219 @@ +// dependencies +define(['library/portlet', 'library/table', 'library/ui', 'library/utils', 'models/group'], + function(Portlet, Table, Ui, Utils, Group) { + +// chart config +return Backbone.View.extend( +{ + // model + group: new Group(), + + // columns + columns: [], + + // initialize + initialize: function(app, options) { + // link app + this.app = app; + + // get current chart object + this.chart = this.app.chart; + + // ui elements + this.message = new Ui.Message(); + this.label = new Ui.Input({placeholder: 'Group label'}); + this.table = new Table({content: 'No data column.'}); + + // add table to portlet + var self = this; + this.portlet = new Portlet({ + icon : 'fa-edit', + label : 'Define group properties:', + operations : { + 'save' : new Ui.ButtonIcon({ + icon : 'fa-save', + tooltip : 'Save', + onclick : function() { + // save/add group + self._saveGroup(); + } + }), + 'back' : new Ui.ButtonIcon({ + icon : 'fa-caret-left', + tooltip : 'Return', + onclick : function() { + self.$el.hide(); + self.app.create.$el.show(); + } + }) + } + }); + this.portlet.append(this.message.$el); + this.portlet.append(this.label.$el); + this.portlet.append(this.table.$el); + + // add element + this.setElement(this.portlet.$el); + + // change + var self = this; + this.chart.on('change:dataset_id', function() { + self._refreshDataset(); + }); + this.chart.on('change:type', function() { + self._refreshType(); + }); + this.group.on('change:label', function() { + self._refreshLabel(); + }); + this.group.on('change', function() { + self._refreshGroup(); + }); + }, + + // show + show: function() { + this.$el.show(); + }, + + // reset + reset: function() { + this.group.reset(); + this.group.set('id', Utils.uuid()); + this.group.set('label', 'Group label'); + }, + + // update dataset + _refreshDataset: function() { + // identify datasets + var dataset_id = this.chart.get('dataset_id'); + + // check if dataset is available + if (!dataset_id) { + return; + } + + // get dataset + var dataset = this.app.datasets.get({id : dataset_id}); + + // check + if (!dataset) { + this.app.log('Config::render()', 'Failed to retrieve dataset.'); + return; + } + + // configure columns + this.columns = []; + var meta = dataset.metadata_column_types; + for (var key in meta){ + this.columns.push({ + 'label' : key + ' [' + meta[key] + ']', + 'value' : key + }); + } + + // update select fields + for (var key in this.list) { + this.list[key].update(this.columns); + } + }, + + // update + _refreshType: function() { + // configure chart type + var self = this; + var chart_type = this.chart.get('type'); + if (chart_type) { + var chart_settings = this.app.types.get(chart_type); + + // table + this.table.removeAll(); + this.list = {}; + for (var id in chart_settings.data) { + // create select field + var data_def = chart_settings.data[id]; + var select = new Ui.Select({ + id : 'select_' + id, + gid : id, + data : this.columns, + onchange : function(value) { + self.group.set(this.gid, value); + } + }); + + // add row to table + this.table.add(data_def.title); + this.table.add(select.$el); + this.table.append(id); + + // add select field to list + this.list[id] = select; + } + } + }, + + // update + _refreshGroup: function() { + // update select fields + for (var id in this.list) { + var col = this.group.get(id); + if (col === undefined) { + col = 0; + } + this.list[id].value(col); + } + }, + + // update label + _refreshLabel: function() { + var label_text = this.group.get('label'); + if (label_text === undefined) { + label_text = ''; + } + this.label.value(label_text); + }, + + // create group + _saveGroup: function() { + // get current chart + var chart = this.chart; + + // update group object + var group = this.group; + for (var key in this.list) { + group.set(key, this.list[key].value()); + } + + // add label + group.set({ + dataset_id : this.chart.get('dataset_id'), + label : this.label.value(), + date : Utils.time() + }); + + // validate + if (!group.get('label')) { + this.message.update({message : 'Please enter a label for your group.'}); + return; + } + + // get groups of current chart + var groups = this.chart.groups; + + // create/update group + var group_update = groups.get(group.id); + if (group_update) { + group_update.set(group.attributes); + } else { + groups.add(group.clone()); + } + + // hide + this.$el.hide(); + + // update main + this.app.create.$el.show(); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/create.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/create.js @@ -0,0 +1,189 @@ +// dependencies +define(['library/portlet', 'library/table', 'library/ui', 'library/utils', 'models/chart', 'groups'], + function(Portlet, Table, Ui, Utils, Chart, Groups) { + +// widget +return Backbone.View.extend( +{ + // defaults options + optionsDefault: { + header : true, + content : 'No content available.' + }, + + // current chart + chart : null, + + // initialize + initialize: function(app, options) + { + // link application + this.app = app; + + // get current chart object + this.chart = this.app.chart; + + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // main elements + this.message = new Ui.Message(); + this.title = new Ui.Input({placeholder: 'Chart title'}); + this.dataset = new Ui.Input({value : app.options.dataset.id, disabled: true}); + + // configure dataset + this.groups = new Groups(this.app); + + // table + var self = this; + this.table = new Table({ + header : false, + onconfirm : function(type) { + if (self.chart.groups.length > 0) { + // show modal + self.app.modal.show({ + title : 'Switching the chart type?', + body : 'You configured data sources. If you switch chart types your configurations will be removed.', + buttons : { + 'Cancel' : function() { + // hide modal + self.app.modal.hide(); + }, + 'Continue' : function() { + // hide modal + self.app.modal.hide(); + + // confirm + self.table.confirm(type); + } + } + }); + } else { + // confirm + self.table.confirm(type); + } + }, + onchange : function(type) { + // update chart type + self.chart.set({type: type}); + + // reset groups + self.chart.groups.reset(); + }, + content: 'No chart types available' + }); + + // add types + var types_n = 0; + var types = app.types.attributes; + for (var id in types){ + var chart_type = types[id]; + this.table.add (++types_n + '.'); + this.table.add (chart_type.title); + this.table.append(id); + } + + // add table to portlet + var self = this; + this.portlet = new Portlet({ + icon : 'fa-edit', + label : 'Create a new chart:', + operations : { + 'save' : new Ui.ButtonIcon({ + icon : 'fa-save', + tooltip : 'Save', + onclick : function() { + self._saveChart(); + } + }), + 'back' : new Ui.ButtonIcon({ + icon : 'fa-caret-left', + tooltip : 'Return', + onclick : function() { + self.$el.hide(); + self.app.main.$el.show(); + } + }) + } + }); + this.portlet.append(this.message.$el); + this.portlet.append((new Ui.Label({ label : 'Provide a chart title:'})).$el); + this.portlet.append(this.title.$el); + this.portlet.append((new Ui.Label({ label : 'Select a dataset:'})).$el); + this.portlet.append(this.dataset.$el); + this.portlet.append((new Ui.Label({ label : 'Select a chart type:'})).$el); + this.portlet.append(this.table.$el); + this.portlet.append(this.groups.$el); + + // elements + this.setElement(this.portlet.$el); + + // events + var self = this; + this.chart.on('change:title', function(chart) { + self.title.value(chart.get('title')); + }); + this.chart.on('change:type', function(chart) { + self.table.value(chart.get('type')); + }); + }, + + // reset + reset: function() { + this.chart.reset(); + this.chart.set('id', Utils.uuid()); + this.chart.set('dataset_id', app.options.dataset.id); + this.chart.set('type', 'bardiagram'); + this.chart.set('title', 'Chart title'); + }, + + // set chart + setChart: function(new_chart) { + this.chart.copy(new_chart); + }, + + // create chart + _saveChart: function() { + // update chart data + this.chart.set({ + type : this.table.value(), + title : this.title.value(), + dataset_id : this.dataset.value(), + date : Utils.time() + }); + + // validate + if (!this.chart.get('title')) { + this.message.update({message : 'Please enter a title for your chart.'}); + return; + } + + if (!this.chart.get('type')) { + this.message.update({message : 'Please select a chart type.'}); + return; + } + + if (this.chart.groups.length == 0) { + this.message.update({message : 'Please configure at least one data source.'}); + return; + } + + // create/get chart + var current = this.app.charts.get(this.chart.id); + if (!current) { + current = this.chart.clone(); + this.app.charts.add(current); + } + + // update chart model + current.copy(this.chart); + + // hide + this.$el.hide(); + + // update main + this.app.main.$el.show(); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/groups.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/groups.js @@ -0,0 +1,154 @@ +// dependencies +define(['library/portlet', 'library/table', 'library/ui', 'library/utils'], function(Portlet, Table, Ui, Utils) { + +// chart config +return Backbone.View.extend( +{ + // initialize + initialize: function(app, options) { + // link app + this.app = app; + + // get current chart object + this.chart = this.app.chart; + + // table + this.table = new Table({ + content : 'Add data sources to this table.', + ondblclick : function(group_id) { + // get group + var group = self.app.chart.groups.get(group_id); + + // show edit + self.app.create.$el.hide(); + self.app.config.show(); + self.app.config.group.set(group.attributes); + } + }); + + // add table to portlet + var self = this; + this.portlet = new Portlet({ + icon : '', + label : 'Configure data sources:', + height : 100, + operations : { + 'new' : new Ui.ButtonIcon({ + icon : 'fa-plus', + tooltip: 'Create', + onclick: function() { + self.app.create.$el.hide(); + self.app.config.show(); + self.app.config.reset(); + } + }), + 'edit' : new Ui.ButtonIcon({ + icon : 'fa-pencil', + tooltip: 'Edit', + onclick: function() { + // check if element has been selected + var group_id = self.table.value(); + if (!group_id) { + return; + } + + // get group + var group = self.app.chart.groups.get(group_id); + + // show edit + self.app.create.$el.hide(); + self.app.config.show(); + self.app.config.group.set(group.attributes); + } + }), + 'delete' : new Ui.ButtonIcon({ + icon : 'fa-minus', + tooltip: 'Delete', + onclick: function() { + // check if element has been selected + var id = self.table.value(); + if (!id) { + return; + } + // remove group from chart + self.chart.groups.remove(id); + } + }) + } + }); + this.portlet.append(this.table.$el); + + // add element + this.setElement(this.portlet.$el); + + // change + var self = this; + this.chart.on('change', function() { + self._refresh(); + }); + this.chart.on('reset', function() { + self._removeGroupAll(); + }); + this.chart.on('change:type', function() { + self.app.config.trigger('change'); + }); + this.chart.groups.on('add', function(group) { + self._addGroup(group); + }); + this.chart.groups.on('remove', function(group) { + self._removeGroup(group); + }); + this.chart.groups.on('reset', function(group) { + self._removeGroupAll(); + }); + this.chart.groups.on('change', function(group) { + self._removeGroup(group); + self._addGroup(group); + }); + }, + + // refresh + _refresh: function() { + this._removeGroupAll(); + var self = this; + var groups = this.chart.groups; + if (groups) { + groups.each(function(group) { self._addGroup(group); }); + } + }, + + // add + _addGroup: function(group) { + // make custom info string + var info = '['; + var chart_type = this.chart.get('type'); + if (chart_type) { + var chart_settings = this.app.types.get(chart_type); + for (var key in chart_settings.data) { + info += key + '=' + group.get(key) + ', ' + } + } + info = info.substring(0, info.length - 2) + ']'; + + // add to table + this.table.add(group.get('label')); + this.table.add(info); + this.table.add('Last changed: ' + group.get('date')); + this.table.prepend(group.id); + this.table.value(group.id); + }, + + // remove + _removeGroup: function(group) { + // remove from to table + this.table.remove(group.id); + }, + + // data config reset + _removeGroupAll: function() { + // reset options table + this.table.removeAll(); + } +}); + +}); \ No newline at end of file diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/library/portlet.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/portlet.js @@ -0,0 +1,142 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// return +return Backbone.View.extend( +{ + // visibility + visible: false, + + // defaults options + optionsDefault: { + label : '', + icon : 'fa-tasks', + buttons : null, + body : null, + height : null, + operations : null, + placement : 'bottom', + overflow : 'auto' + }, + + // content + $content : null, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + // link content + this.$content = this.$el.find('#content'); + + // set content height + if (this.options.height) { + this.$el.find('#body').css('height', this.options.height); + this.$el.find('#content').css('overflow', this.options.overflow); + } + + // append buttons + this.$buttons = $(this.el).find('#buttons'); + if (this.options.buttons) { + // link functions + var self = this; + $.each(this.options.buttons, function(name, item) { + self.$buttons.append(item.$el); + }); + } else { + this.$buttons.remove(); + } + + // append operations + this.$operations = $(this.el).find('#operations'); + if (this.options.operations) { + // link functions + var self = this; + $.each(this.options.operations, function(name, item) { + self.$operations.append(item.$el); + }); + } + + // add body + if(this.options.body) { + this.append(this.options.body); + } + }, + + // append + append: function($el) { + this.$content.append(Utils.wrap($el)); + }, + + // content + content: function() { + return this.$content; + }, + + // hide modal + show: function(){ + // fade in + this.$el.fadeIn('fast'); + + // set flag + this.visible = true; + }, + + // hide modal + hide: function(){ + // fade out + this.$el.fadeOut('fast'); + + // set flag + this.visible = false; + }, + + // enable buttons + enableButton: function(name) { + this.$buttons.find('#' + String(name).toLowerCase()).prop('disabled', false); + }, + + // disable buttons + disableButton: function(name) { + this.$buttons.find('#' + String(name).toLowerCase()).prop('disabled', true); + }, + + // fill regular modal template + template: function(options) { + var tmpl = '<div class="toolForm">'; + + if (options.label) { + tmpl += '<div id="title" class="toolFormTitle" style="padding-bottom: 7px;">' + + '<div id="operations" style="float: right;"></div>' + + '<div>'; + + if (options.icon) + tmpl += '<i style="font-size: 1.2em" class="icon fa ' + options.icon + '"> </i>'; + + tmpl += options.label + + '</div>' + + '</div>'; + } + tmpl += '<div id="body" class="toolFormBody">'; + + if (options.placement == 'top') { + tmpl += '<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'; + } + + tmpl += '<div id="content" class="content" style="height: inherit; padding: 10px;"></div>'; + + if (options.placement == 'bottom') { + tmpl += '<div id="buttons" class="buttons" style="height: 50px; padding: 10px;"></div>'; + } + + tmpl += '</div>' + + '</div>'; + return tmpl; + } +}); + +}); diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/library/table.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/table.js @@ -0,0 +1,188 @@ +// dependencies +define(['library/utils'], function(Utils) { + +// return +return Backbone.View.extend( +{ + // current row + row: null, + + // count rows + row_count: 0, + + // defaults options + optionsDefault: { + content : 'No content available.', + onchange : null, + ondblclick : null, + onconfirm : null + }, + + // events + events : { + 'click' : 'onclick', + 'dblclick' : 'ondblclick' + }, + + // first + first: true, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(options)); + + // initialize row + this.row = $('<tr></tr>'); + }, + + // add header cell + addHeader: function($el) { + var wrapper = $('<th></th>'); + wrapper.append($el); + this.row.append(wrapper); + }, + + // header + appendHeader: function() { + // append header row + $(this.el).find('thead').append(this.row); + + // row + this.row = $('<tr></tr>'); + }, + + // add row cell + add: function($el) { + var wrapper = $('<td></td>'); + wrapper.append($el); + this.row.append(wrapper); + }, + + // append + append: function(id) { + this.commit(id); + }, + + // prepend + prepend: function(id) { + this.commit(id, true); + }, + + // commit + commit: function(id, prepend) { + // add + this.row.attr('id', id); + + // add row + if (prepend) { + $(this.el).find('tbody').prepend(this.row); + } else { + $(this.el).find('tbody').append(this.row); + } + + // row + this.row = $('<tr></tr>'); + + // row count + this.row_count++; + this.refresh(); + }, + + // remove + remove: function(id) { + $(this.el).find('#' + id).remove(); + this.row_count--; + this.refresh(); + }, + + // remove + removeAll: function() { + $(this.el).find('tbody').html(''); + this.row_count = 0; + this.refresh(); + }, + + // value + value: function(new_value) { + // get current id/value + this.before = this.$el.find('.current').attr('id'); + + // check if new_value is defined + if (new_value !== undefined) { + this.$el.find('tr').removeClass('current'); + if (new_value) { + this.$el.find('#' + new_value).addClass('current'); + } + } + + // get current id/value + var after = this.$el.find('.current').attr('id'); + if(after === undefined) { + return null; + } else { + // fire onchange + if (after != this.before && this.options.onchange) { + this.options.onchange(new_value); + } + + // return current value + return after; + } + }, + + // cancel last change + confirm: function(new_value) { + this.value(new_value); + }, + + // onclick + onclick: function(e) { + // get values + var old_value = this.value(); + var new_value = $(e.target).closest('tr').attr('id'); + + // check equality + if (new_value && old_value != new_value) { + if (this.options.onconfirm) { + this.options.onconfirm(new_value); + } else { + this.confirm(new_value); + } + } + }, + + // onclick + ondblclick: function(e) { + var value = this.value(); + if (value && this.options.ondblclick) { + this.options.ondblclick(value); + } + }, + + // refresh + refresh: function() { + if (this.row_count == 0) { + this.$el.find('tmessage').show(); + } else { + this.$el.find('tmessage').hide(); + } + }, + + // load html template + template: function(options) + { + return '<div>' + + '<table class="grid">' + + '<thead></thead>' + + '<tbody style="cursor: pointer;"></tbody>' + + '</table>' + + '<tmessage>' + options.content + '</tmessage>' + + '<div>'; + } +}); + +}); diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/library/ui.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/ui.js @@ -0,0 +1,472 @@ +// dependencies +define(['library/utils', 'library/ui.select'], function(Utils, Select) { + +// plugin +var Label = Backbone.View.extend( +{ + // options + optionsDefault: { + label : '' + }, + + // initialize + initialize : function(options) { + // get options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + }, + + // template + template: function(options) { + return '<label><b>' + options.label + '</b></label>'; + }, + + // value + value: function() { + return options.label; + } +}); + +// plugin +var Button = Backbone.View.extend( +{ + // options + optionsDefault: { + label : '', + float : 'right', + cls : 'btn-default', + type : 'submit', + icon : '' + }, + + // initialize + initialize : function(options) { + // get options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + // add event + $(this.el).on('click', options.onclick); + }, + + // element + template: function(options) { + var str = '<button type="' + options.type + '" style="margin-right: 5px; float: ' + options.float + ';" type="button" class="btn ' + options.cls + '">'; + if (options.icon) { + str += '<i class="icon fa ' + options.icon + '"></i> ' ; + } + str += options.label + + '</button>'; + return str; + } +}); + +// plugin +var Anchor = Backbone.View.extend( +{ + // options + optionsDefault: { + label : '' + }, + + // initialize + initialize : function(options) { + // get options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + // add event + $(this.el).on('click', options.onclick); + }, + + // element + template: function(options) { + return '<div><a href="javascript:void(0)">' + options.label + '</a></div>'; + } +}); + +// plugin +var Message = Backbone.View.extend( +{ + // options + optionsDefault: { + message : '', + status : 'info', + persistent : false + }, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement('<div></div>'); + }, + + // update + update : function(options) { + // get options + this.options = Utils.merge(options, this.optionsDefault); + + // show message + if (options.message != '') { + this.$el.html(this.template(this.options)); + this.$el.fadeIn(); + + // check if message is persistent + if (!options.persistent) { + // set timer + var self = this; + window.setTimeout(function() { + if (self.$el.is(':visible')) { + self.$el.fadeOut(); + } else { + self.$el.hide(); + } + }, 3000); + } + } else { + this.$el.fadeOut(); + } + }, + + // element + template: function(options) { + return '<div class="alert alert-' + options.status + '" style="padding: 2px 2px 2px 10px;">' + options.message + '</div>'; + } +}); + +// plugin +var Searchbox = Backbone.View.extend( +{ + // options + optionsDefault: { + onclick : null, + searchword : '' + }, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + // add click event + var self = this; + if (this.options.onclick) { + this.$el.on('submit', function(e) { + var search_field = self.$el.find('#search'); + self.options.onclick(search_field.val()); + }); + } + }, + + // element + template: function(options) { + return '<div class="search">' + + '<form onsubmit="return false;">' + + '<input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="' + options.searchword + '">' + + '<button type="submit" class="btn search-btn">' + + '<i class="fa fa-search"></i>' + + '</button>' + + '</form>' + + '</div>'; + } +}); + +// plugin +var Title = Backbone.View.extend( +{ + // options + optionsDefault: { + label : 'Unlabeled', + body : null + }, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + if (this.options.body) { + this.$el.find('.body').append(this.options.body); + } + }, + + // element + template: function(options) { + return '<div id="title" class="title">' + + options.label + ':' + + '</div>'; + } +}); + +// tab +var ButtonMenu = Backbone.View.extend( +{ + // main options + options: + { + id : '', + title : '', + target : '', + href : '', + onunload : null, + onclick : null, + visible : true, + icon : null, + tag : '' + }, + + // optional sub menu + $menu: null, + + // initialize + initialize: function (options) + { + // read in defaults + if (options) + this.options = _.defaults(options, this.options); + + // add template for tab + this.setElement($(this._template(this.options))); + + // find root + var $root = $(this.el).find('.root'); + + // link head + var self = this; + $root.on('click', function(e) + { + // prevent default + e.preventDefault(); + + // add click event + if(self.options.onclick) { + self.options.onclick(); + } + }); + + // visiblity + if (!this.options.visible) + this.hide(); + }, + + // show + show: function() + { + $(this.el).show(); + }, + + // hide + hide: function() + { + $(this.el).hide(); + }, + + // add menu item + addMenu: function (options) + { + // menu option defaults + var menuOptions = { + title : '', + target : '', + href : '', + onclick : null, + divider : false, + icon : null + } + + // read in defaults + if (options) + menuOptions = _.defaults(options, menuOptions); + + // check if submenu element is available + if (!this.$menu) + { + // insert submenu element into root + $(this.el).append(this._templateMenu()); + + // update element link + this.$menu = $(this.el).find('.menu'); + } + + // create + var $item = $(this._templateMenuItem(menuOptions)); + + // add events + $item.on('click', function(e) + { + // prevent default + e.preventDefault(); + + // add click event + if(menuOptions.onclick) { + menuOptions.onclick(); + } + }); + + // append menu + this.$menu.append($item); + + // append divider + if (menuOptions.divider) + this.$menu.append($(this._templateDivider())); + }, + + // fill template header + _templateMenuItem: function (options) + { + var tmpl = '<li>' + + '<a href="' + options.href + '" target="' + options.target + '">'; + + if (options.icon) + tmpl += '<i class="fa ' + options.icon + '"></i>'; + + tmpl += ' ' + options.title + + '</a>' + + '</li>'; + return tmpl; + }, + + // fill template header + _templateMenu: function () + { + return '<ul class="menu dropdown-menu pull-right" role="menu"></ul>'; + }, + + _templateDivider: function() + { + return '<li class="divider"></li>'; + }, + + // fill template + _template: function (options) + { + // start template + var tmpl = '<div id="' + options.id + '" class="button-menu btn-group">' + + '<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">'; + + if (options.icon) + tmpl += '<i class="fa ' + options.icon + '"></i>'; + + '</button>' + + '</div>'; + + // return template + return tmpl; + } +}); + +// plugin +var ButtonIcon = Backbone.View.extend( +{ + // options + optionsDefault: { + label : '', + float : 'right', + cls : 'icon-btn', + type : 'submit', + icon : '', + tooltip : '' + }, + + // initialize + initialize : function(options) { + // get options + if (options) + this.options = _.defaults(options, this.optionsDefault); + else + this.options = this.optionsDefault; + + // create new element + this.setElement(this.template(this.options)); + + // add event + $(this.el).on('click', options.onclick); + + // add tooltip + $(this.el).tooltip({title: options.tooltip, placement: 'bottom'}); + }, + + // element + template: function(options) { + var str = '<a style="margin-right: 5px; float: ' + options.float + ';" class="' + options.cls + '">'; + if (options.icon) { + str += '<i class="icon fa ' + options.icon + '"></i>'; + } + str += options.label + + '</a>'; + return str; + } +}); + + +// plugin +var Input = Backbone.View.extend( +{ + // options + optionsDefault: { + value : '', + type : 'text', + placeholder : '', + disabled : false + }, + + // initialize + initialize : function(options) { + // get options + if (options) + this.options = _.defaults(options, this.optionsDefault); + else + this.options = this.optionsDefault; + + // create new element + this.setElement(this.template(this.options)); + + // disable input field + if (this.options.disabled) { + this.$el.prop('disabled', true); + } + }, + + // value + value : function (new_val) { + if (new_val !== undefined) { + this.$el.val(new_val); + } + return this.$el.val(); + }, + + // element + template: function(options) { + return '<input id="' + options.id + '" type="' + options.type + '" value="' + options.value + '" placeholder="' + options.placeholder + '" class="form-control">'; + } +}); + +// return +return { + Label : Label, + Button : Button, + ButtonIcon : ButtonIcon, + Input : Input, + Anchor : Anchor, + Message : Message, + Searchbox : Searchbox, + Title : Title, + Select : Select, + ButtonMenu : ButtonMenu +} +}); diff -r c7986c31fd7447f7d1e2a85bdfa43be6bc4b3b8a -r 6f56754324a6cd91d9e4afccd1d268ca22861093 config/plugins/visualizations/charts/static/library/ui.select.js --- /dev/null +++ b/config/plugins/visualizations/charts/static/library/ui.select.js @@ -0,0 +1,117 @@ +// dependencies +define(['library/utils'], function(Utils) { + + +// plugin +return Backbone.View.extend( +{ + // options + optionsDefault: { + id : '', + cls : '' + }, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this.template(this.options)); + + // add change event + var self = this; + if (this.options.onchange) { + this.$el.on('change', function() { self.options.onchange(self.value()) }); + } + }, + + // value + value : function (new_val) { + if (new_val !== undefined) { + this.$el.val(new_val); + } + return this.$el.val(); + }, + + // label + label : function () { + return this.$el.find('option:selected').text(); + }, + + // disabled + disabled: function() { + return this.$el.is(':disabled'); + }, + + // render + update: function(options) { + // selected + var selected = this.$el.val(); + + // remove all options + $(this.el).find('option').remove(); + + // add new options + for (var key in options.data) { + $(this.el).append(this.templateOption(options.data[key])); + } + + // check if selected value exists + var exists = 0 != $(this.el).find('option[value=' + selected + ']').length; + + // add selected value + if (exists) + $(this.el).val(selected); + }, + + // update from url + updateUrl : function(options, callback) { + // get json + var self = this; + Utils.get(options.url, function(json) { + // write data into array + var data = []; + for (key in json) { + data.push({label: json[key].name, value: json[key].id}); + } + + // check if disabled. do not update disabled select elements. + if (!self.disabled()) { + self.update({data: data}); + } + + // callback + if (callback) { + callback(); + } + }); + }, + + // option + templateOption: function(options) { + return '<option value="' + options.value + '">' + options.label + '</option>'; + }, + + // element + template: function(options) { + var tmpl = '<select id="' + options.id + '" class="select ' + options.cls + ' ' + options.id + '">'; + for (key in options.data) { + // options + var item = options.data[key]; + + // identify selected value + var tag = ''; + if (item.value == options.selected || item.value == '') { + tag = 'selected'; + } + + // add template string + tmpl += '<option value="' + item.value + '" ' + tag + '>' + item.label + '</option>'; + } + tmpl += '</select>'; + return tmpl; + } +}); + +}); This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.