diff --git a/static/scripts/bundled/analysis.bundled.js b/static/scripts/bundled/analysis.bundled.js index 6dd3ba9b877..99186c9585e 100644 --- a/static/scripts/bundled/analysis.bundled.js +++ b/static/scripts/bundled/analysis.bundled.js @@ -1,24867 +1,12 @@ -webpackJsonp([0,1],[ -/* 0 */ -/*!*****************************************!*\ - !*** ./galaxy/scripts/apps/analysis.js ***! - \*****************************************/ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(_, Backbone) { - var jQuery = __webpack_require__( /*! jquery */ 3 ), - $ = jQuery, - GalaxyApp = __webpack_require__( /*! galaxy */ 4 ).GalaxyApp, - QUERY_STRING = __webpack_require__( /*! utils/query-string-parsing */ 11 ), - PANEL = __webpack_require__( /*! layout/panel */ 12 ), - ToolPanel = __webpack_require__( /*! ./tool-panel */ 13 ), - HistoryPanel = __webpack_require__( /*! ./history-panel */ 60 ), - PAGE = __webpack_require__( /*! layout/page */ 99 ), - ToolForm = __webpack_require__( /*! mvc/tool/tool-form */ 20 ); - - /** define the 'Analyze Data'/analysis/main/home page for Galaxy - * * has a masthead - * * a left tool menu to allow the user to load tools in the center panel - * * a right history menu that shows the user's current data - * * a center panel - * Both panels (generally) persist while the center panel shows any - * UI needed for the current step of an analysis, like: - * * tool forms to set tool parameters, - * * tables showing the contents of datasets - * * etc. - */ - window.app = function app( options, bootstrapped ){ - window.Galaxy = new GalaxyApp( options, bootstrapped ); - Galaxy.debug( 'analysis app' ); - // TODO: use router as App base (combining with Galaxy) - - // .................................................... panels and page - var config = options.config, - toolPanel = new ToolPanel({ - el : '#left', - userIsAnonymous : Galaxy.user.isAnonymous(), - search_url : config.search_url, - toolbox : config.toolbox, - toolbox_in_panel : config.toolbox_in_panel, - stored_workflow_menu_entries : config.stored_workflow_menu_entries, - nginx_upload_path : config.nginx_upload_path, - ftp_upload_site : config.ftp_upload_site, - default_genome : config.default_genome, - default_extension : config.default_extension, - }), - centerPanel = new PANEL.CenterPanel({ - el : '#center' - }), - historyPanel = new HistoryPanel({ - el : '#right', - galaxyRoot : Galaxy.root, - userIsAnonymous : Galaxy.user.isAnonymous(), - allow_user_dataset_purge: config.allow_user_dataset_purge, - }), - analysisPage = new PAGE.PageLayoutView( _.extend( options, { - el : 'body', - left : toolPanel, - center : centerPanel, - right : historyPanel, - })); - - // .................................................... decorate the galaxy object - // TODO: most of this is becoming unnecessary as we move to apps - Galaxy.page = analysisPage; - Galaxy.params = Galaxy.config.params; - - // add tool panel to Galaxy object - Galaxy.toolPanel = toolPanel.tool_panel; - Galaxy.upload = toolPanel.uploadButton; - - Galaxy.currHistoryPanel = historyPanel.historyView; - Galaxy.currHistoryPanel.listenToGalaxy( Galaxy ); - - //HACK: move there - Galaxy.app = { - display : function( view, target ){ - // TODO: Remove this line after select2 update - $( '.select2-hidden-accessible' ).remove(); - centerPanel.display( view ); - }, - }; - - // .................................................... routes - /** */ - var router = new ( Backbone.Router.extend({ - // TODO: not many client routes at this point - fill and remove from server. - // since we're at root here, this may be the last to be routed entirely on the client. - initialize : function( options ){ - this.options = options; - }, - - /** override to parse query string into obj and send to each route */ - execute: function( callback, args, name ){ - Galaxy.debug( 'router execute:', callback, args, name ); - var queryObj = QUERY_STRING.parse( args.pop() ); - args.push( queryObj ); - if( callback ){ - callback.apply( this, args ); - } - }, - - routes : { - '(/)' : 'home', - // TODO: remove annoying 'root' from root urls - '(/)root*' : 'home', - }, - - /** */ - home : function( params ){ - // TODO: to router, remove Globals - // load a tool by id (tool_id) or rerun a previous tool execution (job_id) - if( ( params.tool_id || params.job_id ) && params.tool_id !== 'upload1' ){ - this._loadToolForm( params ); - - } else { - // show the workflow run form - if( params.workflow_id ){ - this._loadCenterIframe( 'workflow/run?id=' + params.workflow_id ); - // load the center iframe with controller.action: galaxy.org/?m_c=history&m_a=list -> history/list - } else if( params.m_c ){ - this._loadCenterIframe( params.m_c + '/' + params.m_a ); - // show the workflow run form - } else { - this._loadCenterIframe( 'welcome' ); - } - } - }, - - /** load the center panel with a tool form described by the given params obj */ - _loadToolForm : function( params ){ - //TODO: load tool form code async - params.id = params.tool_id; - centerPanel.display( new ToolForm.View( params ) ); - }, - - /** load the center panel iframe using the given url */ - _loadCenterIframe : function( url, root ){ - root = root || Galaxy.root; - url = root + url; - centerPanel.$( '#galaxy_main' ).prop( 'src', url ); - }, - - }))( options ); - - // .................................................... when the page is ready - // render and start the router - $(function(){ - analysisPage - .render() - .right.historyView.loadCurrentHistory(); - - // use galaxy to listen to history size changes and then re-fetch the user's total size (to update the quota meter) - // TODO: we have to do this here (and after every page.render()) because the masthead is re-created on each - // page render. It's re-created each time because there is no render function and can't be re-rendered without - // re-creating it. - Galaxy.listenTo( analysisPage.right.historyView, 'history-size-change', function(){ - // fetch to update the quota meter adding 'current' for any anon-user's id - Galaxy.user.fetch({ url: Galaxy.user.urlRoot() + '/' + ( Galaxy.user.id || 'current' ) }); - }); - analysisPage.right.historyView.connectToQuotaMeter( analysisPage.masthead.quotaMeter ); - - // start the router - which will call any of the routes above - Backbone.history.start({ - root : Galaxy.root, - pushState : true, - }); - }); - }; - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! underscore */ 1), __webpack_require__(/*! libs/backbone */ 2))) - -/***/ }, -/* 1 */, -/* 2 */, -/* 3 */, -/* 4 */, -/* 5 */, -/* 6 */, -/* 7 */, -/* 8 */, -/* 9 */, -/* 10 */, -/* 11 */ -/*!******************************************************!*\ - !*** ./galaxy/scripts/utils/query-string-parsing.js ***! - \******************************************************/ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ - // ============================================================================ - function get( key, queryString ){ - queryString = queryString || window.location.search.substr( 1 ); - var keyRegex = new RegExp( key + '=([^&#$]+)' ), - matches = queryString.match( keyRegex ); - if( !matches || !matches.length ){ - return undefined; - } - matches = matches.splice( 1 ); - if( matches.length === 1 ){ - return matches[0]; - } - return matches; - } - - function parse( queryString ){ - if( !queryString ){ return {}; } - var parsed = {}, - split = queryString.split( '&' ); - split.forEach( function( pairString ){ - var pair = pairString.split( '=' ); - parsed[ pair[0] ] = decodeURI( pair[1] ); - }); - return parsed; - } - - // ============================================================================ - return { - get : get, - parse : parse, - }; - }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - - -/***/ }, -/* 12 */, -/* 13 */ -/*!*******************************************!*\ - !*** ./galaxy/scripts/apps/tool-panel.js ***! - \*******************************************/ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function($, _) {var LeftPanel = __webpack_require__( /*! layout/panel */ 12 ).LeftPanel, - Tools = __webpack_require__( /*! mvc/tool/tools */ 14 ), - Upload = __webpack_require__( /*! mvc/upload/upload-view */ 48 ), - _l = __webpack_require__( /*! utils/localization */ 7 ); - - /* Builds the tool menu panel on the left of the analysis page */ - var ToolPanel = LeftPanel.extend({ - - title : _l( 'Tools' ), - - initialize: function( options ){ - LeftPanel.prototype.initialize.call( this, options ); - this.log( this + '.initialize:', options ); - - /** @type {Object[]} descriptions of user's workflows to be shown in the tool menu */ - this.stored_workflow_menu_entries = options.stored_workflow_menu_entries || []; - - // create tool search, tool panel, and tool panel view. - var tool_search = new Tools.ToolSearch({ - search_url : options.search_url, - hidden : false - }); - var tools = new Tools.ToolCollection( options.toolbox ); - this.tool_panel = new Tools.ToolPanel({ - tool_search : tool_search, - tools : tools, - layout : options.toolbox_in_panel - }); - this.tool_panel_view = new Tools.ToolPanelView({ model: this.tool_panel }); - - // add upload modal - this.uploadButton = new Upload({ - nginx_upload_path : options.nginx_upload_path, - ftp_upload_site : options.ftp_upload_site, - default_genome : options.default_genome, - default_extension : options.default_extension, - }); - }, - - render : function(){ - var self = this; - LeftPanel.prototype.render.call( self ); - self.$( '.panel-header-buttons' ).append( self.uploadButton.$el ); - - // if there are tools, render panel and display everything - if (self.tool_panel.get( 'layout' ).size() > 0) { - self.tool_panel_view.render(); - //TODO: why the hide/show? - self.$( '.toolMenu' ).show(); - } - self.$( '.toolMenuContainer' ).prepend( self.tool_panel_view.$el ); - - self._renderWorkflowMenu(); - - // if a tool link has the minsizehint attribute, handle it here (gen. by hiding the tool panel) - self.$( 'a[minsizehint]' ).click( function() { - if ( parent.handle_minwidth_hint ) { - parent.handle_minwidth_hint( $( self ).attr( 'minsizehint' ) ); - } - }); - }, - - /** build the dom for the workflow portion of the tool menu */ - _renderWorkflowMenu : function(){ - var self = this; - // add internal workflow list - self.$( '#internal-workflows' ).append( self._templateTool({ - title : _l( 'All workflows' ), - href : 'workflow/list_for_run' - })); - _.each( self.stored_workflow_menu_entries, function( menu_entry ){ - self.$( '#internal-workflows' ).append( self._templateTool({ - title : menu_entry.stored_workflow.name, - href : 'workflow/run?id=' + menu_entry.encoded_stored_workflow_id - })); - }); - }, - - /** build a link to one tool */ - _templateTool: function( tool ) { - return [ - '
', - // global - '', tool.title, '', - '
' - ].join(''); - }, - - /** override to include inital menu dom and workflow section */ - _templateBody : function(){ - return [ - '
', - '
', - '', - '
', - '
', - '
', - '', _l( 'Workflows' ), '', - '
', - '
', - '
', - '
', - '
', - '
' - ].join(''); - }, - - toString : function(){ return 'ToolPanel'; } - }); - - module.exports = ToolPanel; - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! jquery */ 3), __webpack_require__(/*! underscore */ 1))) - -/***/ }, -/* 14 */ -/*!******************************************!*\ - !*** ./galaxy/scripts/mvc/tool/tools.js ***! - \******************************************/ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(Backbone, $) {/** - * Model, view, and controller objects for Galaxy tools and tool panel. - */ - - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ - __webpack_require__(/*! libs/underscore */ 1), - __webpack_require__(/*! viz/trackster/util */ 15), - __webpack_require__(/*! mvc/dataset/data */ 16), - __webpack_require__(/*! mvc/tool/tool-form */ 20) - - ], __WEBPACK_AMD_DEFINE_RESULT__ = function(_, util, data, ToolForm) { - 'use strict'; - - /** - * Mixin for tracking model visibility. - */ - var VisibilityMixin = { - hidden: false, - - show: function() { - this.set("hidden", false); - }, - - hide: function() { - this.set("hidden", true); - }, - - toggle: function() { - this.set("hidden", !this.get("hidden")); - }, - - is_visible: function() { - return !this.attributes.hidden; - } - - }; - - /** - * A tool parameter. - */ - var ToolParameter = Backbone.Model.extend({ - defaults: { - name: null, - label: null, - type: null, - value: null, - html: null, - num_samples: 5 - }, - - initialize: function(options) { - this.attributes.html = unescape(this.attributes.html); - }, - - copy: function() { - return new ToolParameter(this.toJSON()); - }, - - set_value: function(value) { - this.set('value', value || ''); - } - }); - - var ToolParameterCollection = Backbone.Collection.extend({ - model: ToolParameter - }); - - /** - * A data tool parameter. - */ - var DataToolParameter = ToolParameter.extend({}); - - /** - * An integer tool parameter. - */ - var IntegerToolParameter = ToolParameter.extend({ - set_value: function(value) { - this.set('value', parseInt(value, 10)); - }, - - /** - * Returns samples from a tool input. - */ - get_samples: function() { - return d3.scale.linear() - .domain([this.get('min'), this.get('max')]) - .ticks(this.get('num_samples')); - } - }); - - var FloatToolParameter = IntegerToolParameter.extend({ - set_value: function(value) { - this.set('value', parseFloat(value)); - } - }); - - /** - * A select tool parameter. - */ - var SelectToolParameter = ToolParameter.extend({ - /** - * Returns tool options. - */ - get_samples: function() { - return _.map(this.get('options'), function(option) { - return option[0]; - }); - } - }); - - // Set up dictionary of parameter types. - ToolParameter.subModelTypes = { - 'integer': IntegerToolParameter, - 'float': FloatToolParameter, - 'data': DataToolParameter, - 'select': SelectToolParameter - }; - - /** - * A Galaxy tool. - */ - var Tool = Backbone.Model.extend({ - // Default attributes. - defaults: { - id: null, - name: null, - description: null, - target: null, - inputs: [], - outputs: [] - }, - - urlRoot: Galaxy.root + 'api/tools', - - initialize: function(options) { - - // Set parameters. - this.set('inputs', new ToolParameterCollection(_.map(options.inputs, function(p) { - var p_class = ToolParameter.subModelTypes[p.type] || ToolParameter; - return new p_class(p); - }))); - }, - - /** - * - */ - toJSON: function() { - var rval = Backbone.Model.prototype.toJSON.call(this); - - // Convert inputs to JSON manually. - rval.inputs = this.get('inputs').map(function(i) { return i.toJSON(); }); - return rval; - }, - - /** - * Removes inputs of a particular type; this is useful because not all inputs can be handled by - * client and server yet. - */ - remove_inputs: function(types) { - var tool = this, - incompatible_inputs = tool.get('inputs').filter( function(input) { - return ( types.indexOf( input.get('type') ) !== -1); - }); - tool.get('inputs').remove(incompatible_inputs); - }, - - /** - * Returns object copy, optionally including only inputs that can be sampled. - */ - copy: function(only_samplable_inputs) { - var copy = new Tool(this.toJSON()); - - // Return only samplable inputs if flag is set. - if (only_samplable_inputs) { - var valid_inputs = new Backbone.Collection(); - copy.get('inputs').each(function(input) { - if (input.get_samples()) { - valid_inputs.push(input); - } - }); - copy.set('inputs', valid_inputs); - } - - return copy; - }, - - apply_search_results: function(results) { - ( _.indexOf(results, this.attributes.id) !== -1 ? this.show() : this.hide() ); - return this.is_visible(); - }, - - /** - * Set a tool input's value. - */ - set_input_value: function(name, value) { - this.get('inputs').find(function(input) { - return input.get('name') === name; - }).set('value', value); - }, - - /** - * Set many input values at once. - */ - set_input_values: function(inputs_dict) { - var self = this; - _.each(_.keys(inputs_dict), function(input_name) { - self.set_input_value(input_name, inputs_dict[input_name]); - }); - }, - - /** - * Run tool; returns a Deferred that resolves to the tool's output(s). - */ - run: function() { - return this._run(); - }, - - /** - * Rerun tool using regions and a target dataset. - */ - rerun: function(target_dataset, regions) { - return this._run({ - action: 'rerun', - target_dataset_id: target_dataset.id, - regions: regions - }); - }, - - /** - * Returns input dict for tool's inputs. - */ - get_inputs_dict: function() { - var input_dict = {}; - this.get('inputs').each(function(input) { - input_dict[input.get('name')] = input.get('value'); - }); - return input_dict; - }, - - /** - * Run tool; returns a Deferred that resolves to the tool's output(s). - * NOTE: this method is a helper method and should not be called directly. - */ - _run: function(additional_params) { - // Create payload. - var payload = _.extend({ - tool_id: this.id, - inputs: this.get_inputs_dict() - }, additional_params); - - // Because job may require indexing datasets, use server-side - // deferred to ensure that job is run. Also use deferred that - // resolves to outputs from tool. - var run_deferred = $.Deferred(), - ss_deferred = new util.ServerStateDeferred({ - ajax_settings: { - url: this.urlRoot, - data: JSON.stringify(payload), - dataType: "json", - contentType: 'application/json', - type: "POST" - }, - interval: 2000, - success_fn: function(response) { - return response !== "pending"; - } - }); - - // Run job and resolve run_deferred to tool outputs. - $.when(ss_deferred.go()).then(function(result) { - run_deferred.resolve(new data.DatasetCollection(result)); - }); - return run_deferred; - } - }); - _.extend(Tool.prototype, VisibilityMixin); - - /** - * Tool view. - */ - var ToolView = Backbone.View.extend({ - - }); - - /** - * Wrap collection of tools for fast access/manipulation. - */ - var ToolCollection = Backbone.Collection.extend({ - model: Tool - }); - - /** - * Label or section header in tool panel. - */ - var ToolSectionLabel = Backbone.Model.extend(VisibilityMixin); - - /** - * Section of tool panel with elements (labels and tools). - */ - var ToolSection = Backbone.Model.extend({ - defaults: { - elems: [], - open: false - }, - - clear_search_results: function() { - _.each(this.attributes.elems, function(elt) { - elt.show(); - }); - - this.show(); - this.set("open", false); - }, - - apply_search_results: function(results) { - var all_hidden = true, - cur_label; - _.each(this.attributes.elems, function(elt) { - if (elt instanceof ToolSectionLabel) { - cur_label = elt; - cur_label.hide(); - } - else if (elt instanceof Tool) { - if (elt.apply_search_results(results)) { - all_hidden = false; - if (cur_label) { - cur_label.show(); - } - } - } - }); - - if (all_hidden) { - this.hide(); - } - else { - this.show(); - this.set("open", true); - } - } - }); - _.extend(ToolSection.prototype, VisibilityMixin); - - /** - * Tool search that updates results when query is changed. Result value of null - * indicates that query was not run; if not null, results are from search using - * query. - */ - var ToolSearch = Backbone.Model.extend({ - defaults: { - search_hint_string: "search tools", - min_chars_for_search: 3, - clear_btn_url: "", - search_url: "", - visible: true, - query: "", - results: null, - // ESC (27) will clear the input field and tool search filters - clear_key: 27 - }, - - urlRoot: Galaxy.root + 'api/tools', - - initialize: function() { - this.on("change:query", this.do_search); - }, - - /** - * Do the search and update the results. - */ - do_search: function() { - var query = this.attributes.query; - - // If query is too short, do not search. - if (query.length < this.attributes.min_chars_for_search) { - this.set("results", null); - return; - } - - // Do search via AJAX. - var q = query; - // Stop previous ajax-request - if (this.timer) { - clearTimeout(this.timer); - } - // Start a new ajax-request in X ms - $("#search-clear-btn").hide(); - $("#search-spinner").show(); - var self = this; - this.timer = setTimeout(function () { - // log the search to analytics if present - if ( typeof ga !== 'undefined' ) { - ga( 'send', 'pageview', Galaxy.root + '?q=' + q ); - } - $.get( self.urlRoot, { q: q }, function (data) { - self.set("results", data); - $("#search-spinner").hide(); - $("#search-clear-btn").show(); - }, "json" ); - }, 400 ); - }, - - clear_search: function() { - this.set("query", ""); - this.set("results", null); - } - - }); - _.extend(ToolSearch.prototype, VisibilityMixin); - - /** - * Tool Panel. - */ - var ToolPanel = Backbone.Model.extend({ - - initialize: function(options) { - this.attributes.tool_search = options.tool_search; - this.attributes.tool_search.on("change:results", this.apply_search_results, this); - this.attributes.tools = options.tools; - this.attributes.layout = new Backbone.Collection( this.parse(options.layout) ); - }, - - /** - * Parse tool panel dictionary and return collection of tool panel elements. - */ - parse: function(response) { - // Recursive function to parse tool panel elements. - var self = this, - // Helper to recursively parse tool panel. - parse_elt = function(elt_dict) { - var type = elt_dict.model_class; - // There are many types of tools; for now, anything that ends in 'Tool' - // is treated as a generic tool. - if ( type.indexOf('Tool') === type.length - 4 ) { - return self.attributes.tools.get(elt_dict.id); - } - else if (type === 'ToolSection') { - // Parse elements. - var elems = _.map(elt_dict.elems, parse_elt); - elt_dict.elems = elems; - return new ToolSection(elt_dict); - } - else if (type === 'ToolSectionLabel') { - return new ToolSectionLabel(elt_dict); - } - }; - - return _.map(response, parse_elt); - }, - - clear_search_results: function() { - this.get('layout').each(function(panel_elt) { - if (panel_elt instanceof ToolSection) { - panel_elt.clear_search_results(); - } - else { - // Label or tool, so just show. - panel_elt.show(); - } - }); - }, - - apply_search_results: function() { - var results = this.get('tool_search').get('results'); - if (results === null) { - this.clear_search_results(); - return; - } - - var cur_label = null; - this.get('layout').each(function(panel_elt) { - if (panel_elt instanceof ToolSectionLabel) { - cur_label = panel_elt; - cur_label.hide(); - } - else if (panel_elt instanceof Tool) { - if (panel_elt.apply_search_results(results)) { - if (cur_label) { - cur_label.show(); - } - } - } - else { - // Starting new section, so clear current label. - cur_label = null; - panel_elt.apply_search_results(results); - } - }); - } - }); - - /** - * View classes for Galaxy tools and tool panel. - * - * Views use the templates defined below for rendering. Views update as needed - * based on (a) model/collection events and (b) user interactions; in this sense, - * they are controllers are well and the HTML is the real view in the MVC architecture. - */ - - /** - * Base view that handles visibility based on model's hidden attribute. - */ - var BaseView = Backbone.View.extend({ - initialize: function() { - this.model.on("change:hidden", this.update_visible, this); - this.update_visible(); - }, - update_visible: function() { - ( this.model.attributes.hidden ? this.$el.hide() : this.$el.show() ); - } - }); - - /** - * Link to a tool. - */ - var ToolLinkView = BaseView.extend({ - tagName: 'div', - - render: function() { - // create element - var $link = $('
'); - $link.append(templates.tool_link(this.model.toJSON())); - - // open upload dialog for upload tool - if (this.model.id === 'upload1') { - $link.find('a').on('click', function(e) { - e.preventDefault(); - Galaxy.upload.show(); - }); - } - else if ( this.model.get( 'model_class' ) === 'Tool' ) { // regular tools - var self = this; - $link.find('a').on('click', function(e) { - e.preventDefault(); - var form = new ToolForm.View( { id : self.model.id, version : self.model.get('version') } ); - form.deferred.execute(function() { - Galaxy.app.display( form ); - }); - }); - } - - // add element - this.$el.append($link); - return this; - } - }); - - /** - * Panel label/section header. - */ - var ToolSectionLabelView = BaseView.extend({ - tagName: 'div', - className: 'toolPanelLabel', - - render: function() { - this.$el.append( $("").text(this.model.attributes.text) ); - return this; - } - }); - - /** - * Panel section. - */ - var ToolSectionView = BaseView.extend({ - tagName: 'div', - className: 'toolSectionWrapper', - - initialize: function() { - BaseView.prototype.initialize.call(this); - this.model.on("change:open", this.update_open, this); - }, - - render: function() { - // Build using template. - this.$el.append( templates.panel_section(this.model.toJSON()) ); - - // Add tools to section. - var section_body = this.$el.find(".toolSectionBody"); - _.each(this.model.attributes.elems, function(elt) { - if (elt instanceof Tool) { - var tool_view = new ToolLinkView({model: elt, className: "toolTitle"}); - tool_view.render(); - section_body.append(tool_view.$el); - } - else if (elt instanceof ToolSectionLabel) { - var label_view = new ToolSectionLabelView({model: elt}); - label_view.render(); - section_body.append(label_view.$el); - } - else { - // TODO: handle nested section bodies? - } - }); - return this; - }, - - events: { - 'click .toolSectionTitle > a': 'toggle' - }, - - /** - * Toggle visibility of tool section. - */ - toggle: function() { - this.model.set("open", !this.model.attributes.open); - }, - - /** - * Update whether section is open or close. - */ - update_open: function() { - (this.model.attributes.open ? - this.$el.children(".toolSectionBody").slideDown("fast") : - this.$el.children(".toolSectionBody").slideUp("fast") - ); - } - }); - - var ToolSearchView = Backbone.View.extend({ - tagName: 'div', - id: 'tool-search', - className: 'bar', - - events: { - 'click': 'focus_and_select', - 'keyup :input': 'query_changed', - 'click #search-clear-btn': 'clear' - }, - - render: function() { - this.$el.append( templates.tool_search(this.model.toJSON()) ); - if (!this.model.is_visible()) { - this.$el.hide(); - } - this.$el.find('[title]').tooltip(); - return this; - }, - - focus_and_select: function() { - this.$el.find(":input").focus().select(); - }, - - clear: function() { - this.model.clear_search(); - this.$el.find(":input").val(''); - this.focus_and_select(); - return false; - }, - - query_changed: function( evData ) { - // check for the 'clear key' (ESC) first - if( ( this.model.attributes.clear_key ) && - ( this.model.attributes.clear_key === evData.which ) ){ - this.clear(); - return false; - } - this.model.set("query", this.$el.find(":input").val()); - } - }); - - /** - * Tool panel view. Events triggered include: - * tool_link_click(click event, tool_model) - */ - var ToolPanelView = Backbone.View.extend({ - tagName: 'div', - className: 'toolMenu', - - /** - * Set up view. - */ - initialize: function() { - this.model.get('tool_search').on("change:results", this.handle_search_results, this); - }, - - render: function() { - var self = this; - - // Render search. - var search_view = new ToolSearchView( { model: this.model.get('tool_search') } ); - search_view.render(); - self.$el.append(search_view.$el); - - // Render panel. - this.model.get('layout').each(function(panel_elt) { - if (panel_elt instanceof ToolSection) { - var section_title_view = new ToolSectionView({model: panel_elt}); - section_title_view.render(); - self.$el.append(section_title_view.$el); - } - else if (panel_elt instanceof Tool) { - var tool_view = new ToolLinkView({model: panel_elt, className: "toolTitleNoSection"}); - tool_view.render(); - self.$el.append(tool_view.$el); - } - else if (panel_elt instanceof ToolSectionLabel) { - var label_view = new ToolSectionLabelView({model: panel_elt}); - label_view.render(); - self.$el.append(label_view.$el); - } - }); - - // Setup tool link click eventing. - self.$el.find("a.tool-link").click(function(e) { - // Tool id is always the first class. - var - tool_id = $(this).attr('class').split(/\s+/)[0], - tool = self.model.get('tools').get(tool_id); - - self.trigger("tool_link_click", e, tool); - }); - - return this; - }, - - handle_search_results: function() { - var results = this.model.get('tool_search').get('results'); - if (results && results.length === 0) { - $("#search-no-results").show(); - } - else { - $("#search-no-results").hide(); - } - } - }); - - /** - * View for working with a tool: setting parameters and inputs and executing the tool. - */ - var ToolFormView = Backbone.View.extend({ - className: 'toolForm', - - render: function() { - this.$el.children().remove(); - this.$el.append( templates.tool_form(this.model.toJSON()) ); - } - }); - - /** - * Integrated tool menu + tool execution. - */ - var IntegratedToolMenuAndView = Backbone.View.extend({ - className: 'toolMenuAndView', - - initialize: function() { - this.tool_panel_view = new ToolPanelView({collection: this.collection}); - this.tool_form_view = new ToolFormView(); - }, - - render: function() { - // Render and append tool panel. - this.tool_panel_view.render(); - this.tool_panel_view.$el.css("float", "left"); - this.$el.append(this.tool_panel_view.$el); - - // Append tool form view. - this.tool_form_view.$el.hide(); - this.$el.append(this.tool_form_view.$el); - - // On tool link click, show tool. - var self = this; - this.tool_panel_view.on("tool_link_click", function(e, tool) { - // Prevents click from activating link: - e.preventDefault(); - // Show tool that was clicked on: - self.show_tool(tool); - }); - }, - - /** - * Fetch and display tool. - */ - show_tool: function(tool) { - var self = this; - tool.fetch().done( function() { - self.tool_form_view.model = tool; - self.tool_form_view.render(); - self.tool_form_view.$el.show(); - $('#left').width("650px"); - }); - } - }); - - // TODO: move into relevant views - var templates = { - // the search bar at the top of the tool panel - tool_search : _.template([ - '', - ' ', - //TODO: replace with icon - '', - ].join('')), - - // the category level container in the tool panel (e.g. 'Get Data', 'Text Manipulation') - panel_section : _.template([ - '
', - '<%- name %>', - '
', - '