commit/galaxy-central: guerler: Grids: Finalize code separation, refactor filters and apply coding conventions
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/b20d93e64306/ Changeset: b20d93e64306 User: guerler Date: 2014-01-31 11:20:23 Summary: Grids: Finalize code separation, refactor filters and apply coding conventions iG: removed static/scripts/packed/galaxy.grids.js Affected #: 12 files diff -r be7ece9454471d655668f3997c29b90c2f6c312d -r b20d93e643068f3154752582db3d17e16c499633 lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py +++ b/lib/galaxy/web/framework/helpers/grids.py @@ -41,6 +41,7 @@ cur_sort_key_pref_name = ".sort_key" pass_through_operations = {} legend = None + info_text = None def __init__( self ): # Determine if any multiple row operations are defined self.has_multiple_item_operations = False @@ -286,6 +287,7 @@ url = url, status = status, message = message, + info_text=self.info_text, use_panels=self.use_panels, use_hide_message=self.use_hide_message, advanced_search=self.advanced_search, diff -r be7ece9454471d655668f3997c29b90c2f6c312d -r b20d93e643068f3154752582db3d17e16c499633 lib/galaxy/webapps/galaxy/controllers/history.py --- a/lib/galaxy/webapps/galaxy/controllers/history.py +++ b/lib/galaxy/webapps/galaxy/controllers/history.py @@ -104,6 +104,7 @@ preserve_state = False use_async = True use_paging = True + info_text = "Histories that have been deleted for more than a time period specified by the Galaxy administrator(s) may be permanently deleted." def get_current_item( self, trans, **kwargs ): return trans.get_history() diff -r be7ece9454471d655668f3997c29b90c2f6c312d -r b20d93e643068f3154752582db3d17e16c499633 static/scripts/galaxy.grids.js --- a/static/scripts/galaxy.grids.js +++ /dev/null @@ -1,984 +0,0 @@ -// External dependencies (for module management eventually): jQuery, Backbone, underscore - -// This is necessary so that, when nested arrays are used in ajax/post/get methods, square brackets ('[]') are -// not appended to the identifier of a nested array. -jQuery.ajaxSettings.traditional = true; - -// dependencies -define(['mvc/ui'], function() { - -/** - * A Galaxy grid. - */ -var Grid = Backbone.Model.extend({ - defaults: { - url_base: '', - async: false, - async_ops: [], - categorical_filters: [], - filters: {}, - sort_key: null, - show_item_checkboxes: false, - advanced_search: false, - cur_page: 1, - num_pages: 1, - operation: undefined, - item_ids: undefined - }, - - /** - * Return true if operation can be done asynchronously. - */ - can_async_op: function(op) { - return _.indexOf(this.attributes.async_ops, op) !== -1; - }, - - /** - * Add filtering criterion. - */ - add_filter: function(key, value, append) { - // Update URL arg with new condition. - if (append) { - // Update or append value. - var cur_val = this.attributes.filters[key], - new_val; - if (cur_val === null || cur_val === undefined) { - new_val = value; - } - else if (typeof(cur_val) == "string") { - if (cur_val == "All") { - new_val = value; - } else { - // Replace string with array. - var values = []; - values[0] = cur_val; - values[1] = value; - new_val = values; - } - } - else { - // Current value is an array. - new_val = cur_val; - new_val.push(value); - } - this.attributes.filters[key] = new_val; - } - else { - // Replace value. - this.attributes.filters[key] = value; - } - }, - - /** - * Remove filtering criterion. - */ - remove_filter: function(key, condition) { - var cur_val = this.attributes.filters[key]; - if (cur_val === null || cur_val === undefined) { - return false; - } - - var removed = true; - if (typeof(cur_val) === "string") { - if (cur_val == "All") { - // Unexpected. Throw error? - removed = false; - } - else { - // Remove condition. - delete this.attributes.filters[key]; - } - } - else { - // Filter contains an array of conditions. - var condition_index = _.indexOf(cur_val, condition); - if (condition_index !== -1) { - cur_val.splice(condition_index, 1); - } - else { - removed = false; - } - } - - return removed; - }, - - /** - * Returns URL data for obtaining a new grid. - */ - get_url_data: function() { - var url_data = { - async: this.attributes.async, - sort: this.attributes.sort_key, - page: this.attributes.cur_page, - show_item_checkboxes: this.attributes.show_item_checkboxes, - advanced_search: this.attributes.advanced_search - }; - - // Add operation, item_ids only if they have values. - if (this.attributes.operation) { - url_data.operation = this.attributes.operation; - } - if (this.attributes.item_ids) { - url_data.id = this.attributes.item_ids; - } - - // Add filter arguments to data, placing "f-" in front of all arguments. - var self = this; - _.each(_.pairs(self.attributes.filters), function(k) { - url_data['f-' + k[0]] = k[1]; - }); - - return url_data; - }, - - // Return URL for obtaining a new grid - get_url: function (args) { - return this.get('url_base') + "?" + $.param(this.get_url_data()) + '&' + $.param(args); - } - -}); - -// grid view -var GridView = Backbone.View.extend({ - - // model - grid: null, - - // Initialize - initialize: function(grid_config) - { - // initialize controls - this.init_grid(grid_config); - this.init_grid_controls(); - - // Initialize text filters to select text on click and use normal font when user is typing. - $('input[type=text]').each(function() { - $(this).click(function() { $(this).select(); } ) - .keyup(function () { $(this).css("font-style", "normal"); }); - }); - }, - - // refresh frames - handle_refresh: function (refresh_frames) { - if (refresh_frames) { - if ($.inArray('history', refresh_frames) > -1) { - if( top.Galaxy && top.Galaxy.currHistoryPanel ){ - top.Galaxy.currHistoryPanel.loadCurrentHistory(); - } - } - } - }, - - // Initialize - init_grid: function(grid_config) - { - // link grid model - this.grid = new Grid(grid_config); - - // get options - var options = this.grid.attributes; - - // handle refresh requests - this.handle_refresh(options.refresh_frames); - - // strip protocol and domain - var url = this.grid.get('url_base'); - url = url.replace(/^.*\/\/[^\/]+/, ''); - this.grid.set('url_base', url); - - // update div contents - $('#grid-table-body').html(this.template_body(options)); - $('#grid-table-footer').html(this.template_footer(options)); - - // update message - if (options.message) { - $('#grid-message').html(this.template_message(options)); - if (options.use_hide_message) { - setTimeout( function() { $('#grid-message').html(''); }, 5000); - } - } - - // configure elements - this.init_grid_elements(); - - // attach global event handler - init_refresh_on_change(); - }, - - // Initialize grid controls - init_grid_controls: function() { - // Initialize submit image elements. - $('.submit-image').each( function() { - // On mousedown, add class to simulate click. - $(this).mousedown( function() { - $(this).addClass('gray-background'); - }); - - // On mouseup, add class to simulate click. - $(this).mouseup( function() { - $(this).removeClass('gray-background'); - }); - }); - - // link - var self = this; - - // Initialize sort links. - $('.sort-link').each( function() { - $(this).click( function() { - self.set_sort_condition( $(this).attr('sort_key') ); - return false; - }); - }); - - // Initialize categorical filters. - $('.categorical-filter > a').each( function() { - $(this).click( function() { - self.set_categorical_filter( $(this).attr('filter_key'), $(this).attr('filter_val') ); - return false; - }); - }); - - // Initialize text filters. - $('.text-filter-form').each( function() { - $(this).submit( function() { - var column_key = $(this).attr('column_key'); - var text_input_obj = $('#input-' + column_key + '-filter'); - var text_input = text_input_obj.val(); - text_input_obj.val(''); - self.add_filter_condition(column_key, text_input); - return false; - }); - }); - - // Initialize autocomplete for text inputs in search UI. - var t = $("#input-tags-filter"); - if (t.length) { - t.autocomplete(this.grid.history_tag_autocomplete_url, - { selectFirst: false, autoFill: false, highlight: false, mustMatch: false }); - } - - var t2 = $("#input-name-filter"); - if (t2.length) { - t2.autocomplete(this.grid.history_name_autocomplete_url, - { selectFirst: false, autoFill: false, highlight: false, mustMatch: false }); - } - - // Initialize standard, advanced search toggles. - $('.advanced-search-toggle').each( function() { - $(this).click( function() { - $('#standard-search').slideToggle('fast'); - $('#advanced-search').slideToggle('fast'); - return false; - }); - }); - }, - - // Initialize grid elements. - init_grid_elements : function() { - // Initialize grid selection checkboxes. - $(".grid").each( function() { - var checkboxes = $(this).find("input.grid-row-select-checkbox"); - var check_count = $(this).find("span.grid-selected-count"); - var update_checked = function() { - check_count.text( $(checkboxes).filter(":checked").length ); - }; - - $(checkboxes).each( function() { - $(this).change(update_checked); - }); - update_checked(); - }); - - // Initialize ratings. - if ($('.community_rating_star').length !== 0) - $('.community_rating_star').rating({}); - - // get options - var options = this.grid.attributes; - var self = this; - - // - // add page click events - // - $('.page-link > a').each( function() { - $(this).click( function() { - self.set_page( $(this).attr('page_num') ); - return false; - }); - }); - - // - // add inbound/outbound events - // - $(".use-inbound").each( function() { - $(this).click( function(e) { - self.execute({ - href : $(this).attr('href'), - inbound : true - }); - return false; - - }); - }); - - $(".use-outbound").each( function() { - $(this).click( function(e) { - self.execute({ - href : $(this).attr('href') - }); - return false; - }); - }); - - // empty grid? - var items_length = options.items.length; - if (items_length == 0) { - return; - } - - // - // add operation popup menus - // - for (var i in options.items) - { - // get items - var item = options.items[i]; - - // get identifiers - var button = $('#grid-' + i + '-popup'); - button.off(); - var popup = new PopupMenu(button); - - // load details - for (var j in options['operations']) - { - // get operation details - var operation = options['operations'][j]; - var operation_id = operation['label']; - var operation_settings = item['operation_config'][operation_id]; - var encode_id = item['encode_id']; - - // check - if (operation_settings['allowed'] && operation['allow_popup']) - { - // popup configuration - var popupConfig = - { - html : operation['label'], - href : operation_settings['url_args'], - target : operation_settings['target'], - confirmation_text : operation['confirm'], - inbound : operation['inbound'] - }; - - // add popup function - popupConfig.func = function(e) - { - e.preventDefault(); - var label = $(e.target).html(); - var options = this.findItemByHtml(label); - self.execute(options); - }; - - // add item - popup.addItem(popupConfig); - } - } - } - }, - - // Add a condition to the grid filter; this adds the condition and refreshes the grid. - add_filter_condition: function (name, value) { - // Do nothing is value is empty. - if (value === "") { - return false; - } - - // Add condition to grid. - this.grid.add_filter(name, value, true); - - // Add button that displays filter and provides a button to delete it. - var t = $("<span>" + value + "<a href='javascript:void(0);'><span class='delete-search-icon' /></span></a>"); - t.addClass('text-filter-val'); - var self = this; - t.click(function() { - // Remove filter condition. - self.grid.remove_filter(name, value); - - // Remove visible element. - $(this).remove(); - - self.go_page_one(); - self.execute(); - }); - - var container = $('#' + name + "-filtering-criteria"); - container.append(t); - - this.go_page_one(); - this.execute(); - }, - - // Set sort condition for grid. - set_sort_condition: function (col_key) { - // Set new sort condition. New sort is col_key if sorting new column; if reversing sort on - // currently sorted column, sort is reversed. - var cur_sort = this.grid.get('sort_key'); - var new_sort = col_key; - if (cur_sort.indexOf(col_key) !== -1) { - // Reverse sort. - if (cur_sort.substring(0,1) !== '-') { - new_sort = '-' + col_key; - } else { - // Sort reversed by using just col_key. - } - } - - // Remove sort arrows elements. - $('.sort-arrow').remove(); - - // Add sort arrow element to new sort column. - var sort_arrow = (new_sort.substring(0,1) == '-') ? "↑" : "↓"; - var t = $("<span>" + sort_arrow + "</span>").addClass('sort-arrow'); - var th = $("#" + col_key + '-header'); - th.append(t); - - // Update grid. - this.grid.set('sort_key', new_sort); - this.go_page_one(); - this.execute(); - }, - - // Set new value for categorical filter. - set_categorical_filter: function (name, new_value) { - // Update filter hyperlinks to reflect new filter value. - var category_filter = this.grid.get('categorical_filters')[name], - cur_value = this.grid.get('filters')[name]; - var self = this; - $("." + name + "-filter").each( function() { - var text = $.trim( $(this).text() ); - var filter = category_filter[text]; - var filter_value = filter[name]; - if (filter_value == new_value) { - // Remove filter link since grid will be using this filter. It is assumed that - // this element has a single child, a hyperlink/anchor with text. - $(this).empty(); - $(this).addClass("current-filter"); - $(this).append(text); - } else if (filter_value == cur_value) { - // Add hyperlink for this filter since grid will no longer be using this filter. It is assumed that - // this element has a single child, a hyperlink/anchor. - $(this).empty(); - var t = $("<a href='#'>" + text + "</a>"); - t.click(function() { - self.set_categorical_filter( name, filter_value ); - }); - $(this).removeClass("current-filter"); - $(this).append(t); - } - }); - - // Update grid. - this.grid.add_filter(name, new_value); - this.go_page_one(); - this.execute(); - }, - - // Set page to view. - set_page: function (new_page) { - // Update page hyperlink to reflect new page. - var self = this; - $(".page-link").each( function() { - var id = $(this).attr('id'), - page_num = parseInt( id.split("-")[2], 10 ), // Id has form 'page-link-<page_num> - cur_page = self.grid.get('cur_page'), - text; - if (page_num === new_page) { - // Remove link to page since grid will be on this page. It is assumed that - // this element has a single child, a hyperlink/anchor with text. - text = $(this).children().text(); - $(this).empty(); - $(this).addClass("inactive-link"); - $(this).text(text); - } - else if (page_num === cur_page) { - // Add hyperlink to this page since grid will no longer be on this page. It is assumed that - // this element has a single child, a hyperlink/anchor. - text = $(this).text(); - $(this).empty(); - $(this).removeClass("inactive-link"); - var t = $("<a href='#'>" + text + "</a>"); - t.click(function() { - self.set_page(page_num); - }); - $(this).append(t); - } - }); - - if (new_page === "all") { - this.grid.set('cur_page', new_page); - } else { - this.grid.set('cur_page', parseInt(new_page, 10)); - } - this.execute(); - }, - - // confirmation/submission of operation request - submit_operation: function (selected_button, confirmation_text) - { - // verify in any item is selected - var number_of_checked_ids = $('input[name="id"]:checked').length; - if (!number_of_checked_ids > 0) - return false; - - // collect ids - var operation_name = $(selected_button).val(); - var item_ids = []; - $('input[name=id]:checked').each(function() { - item_ids.push( $(this).val() ); - }); - this.execute({ - operation: operation_name, - id: item_ids, - confirmation_text: confirmation_text - }); - - // return - return true; - }, - - // execute operations and hyperlink requests - execute: function (options) { - // get url - var id = null; - var href = null; - var operation = null; - var confirmation_text = null; - var inbound = null; - - // check for options - if (options) - { - // get options - href = options.href; - operation = options.operation; - id = options.id; - confirmation_text = options.confirmation_text; - inbound = options.inbound; - - // check if input contains the operation tag - if (href !== undefined && href.indexOf('operation=') != -1) { - // Get operation, id in hyperlink's href. - var href_parts = href.split("?"); - if (href_parts.length > 1) { - var href_parms_str = href_parts[1]; - var href_parms = href_parms_str.split("&"); - for (var index = 0; index < href_parms.length; index++) { - if (href_parms[index].indexOf('operation') != -1) { - // Found operation parm; get operation value. - operation = href_parms[index].split('=')[1]; - operation = operation.replace (/\+/g, ' '); - } else if (href_parms[index].indexOf('id') != -1) { - // Found id parm; get id value. - id = href_parms[index].split('=')[1]; - } - } - } - } - } - - // check for operation details - if (operation && id) { - // show confirmation box - if (confirmation_text && confirmation_text != '' && confirmation_text != 'None' && confirmation_text != 'null') - if(!confirm(confirmation_text)) - return false; - - // use small characters for operation?! - operation = operation.toLowerCase(); - - // Update grid. - this.grid.set({ - operation: operation, - item_ids: id - }); - - // Do operation. If operation cannot be performed asynchronously, redirect to location. - if (this.grid.can_async_op(operation)) { - this.update_grid(); - } else { - this.go_to(inbound, ''); - } - - // done - return false; - } - - // check for href details - if (href) - { - this.go_to(inbound, href); - return false; - } - - // refresh grid - if (this.grid.get('async')) { - this.update_grid(); - } else { - this.go_to(inbound, ''); - } - - // done - return false; - }, - - // go to url - go_to: function (inbound, href) { - // get aysnc status - var async = this.grid.get('async'); - this.grid.set('async', false); - - // get slide status - advanced_search = $('#advanced-search').is(":visible"); - this.grid.set('advanced_search', advanced_search); - - // get default url - if(!href) - href = this.grid.get('url_base') + "?" + $.param(this.grid.get_url_data()); - - // clear grid of transient request attributes. - this.grid.set({ - operation: undefined, - item_ids: undefined, - async: async - }); - - if (inbound) { - // this currently assumes that there is only a single grid shown at a time - var $div = $('.grid-header').closest('.inbound'); - if ($div.length !== 0) { - $div.load(href); - return; - } - } - - window.location = href; - }, - - // Update grid. - update_grid: function () { - // If there's an operation, do POST; otherwise, do GET. - var method = (this.grid.get('operation') ? "POST" : "GET" ); - $('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions. - var self = this; - $.ajax({ - type: method, - url: self.grid.get('url_base'), - data: self.grid.get_url_data(), - error: function(response) { alert( 'Grid refresh failed' );}, - success: function(response_text) { - // Initialize new grid config - self.init_grid($.parseJSON(response_text)); - - // Hide loading overlay. - $('.loading-elt-overlay').hide(); - }, - complete: function() { - // Clear grid of transient request attributes. - self.grid.set({ - operation: undefined, - item_ids: undefined - }); - } - }); - }, - - check_all_items: function () { - var chk_all = document.getElementById('check_all'), - checks = document.getElementsByTagName('input'), - total = 0, - i; - if ( chk_all.checked === true ) { - for ( i=0; i < checks.length; i++ ) { - if ( checks[i].name.indexOf( 'id' ) !== -1) { - checks[i].checked = true; - total++; - } - } - } - else { - for ( i=0; i < checks.length; i++ ) { - if ( checks[i].name.indexOf( 'id' ) !== -1) { - checks[i].checked = false; - } - - } - } - this.init_grid_elements(); - }, - - // Go back to page one; this is useful when a filter is applied. - go_page_one: function () { - // Need to go back to page 1 if not showing all. - var cur_page = this.grid.get('cur_page'); - if (cur_page !== null && cur_page !== undefined && cur_page !== 'all') { - this.grid.set('cur_page', 1); - } - }, - - // template - template_body: function(options) { - // initialize - var tmpl = ''; - var num_rows_rendered = 0; - var items_length = options.items.length; - - // empty grid? - if (items_length == 0) { - // No results. - tmpl += '<tr><td colspan="100"><em>No Items</em></td></tr>'; - num_rows_rendered = 1; - } - - // create rows - for (var i in options.items) { - - // encode ids - var item = options.items[i]; - var encoded_id = item.encode_id; - var popupmenu_id = 'grid-' + i + '-popup'; - - // Tag current - tmpl += '<tr '; - if (options.current_item_id == item.id) { - tmpl += 'class="current"'; - } - tmpl += '>'; - - // Item selection column - if (options.show_item_checkboxes) { - tmpl += '<td style="width: 1.5em;">' + - '<input type="checkbox" name="id" value="' + encoded_id + '" id="' + encoded_id + '" class="grid-row-select-checkbox" />' + - '</td>'; - } - - // Data columns - for (j in options.columns) { - var column = options.columns[j]; - if (column.visible) { - // Nowrap - var nowrap = ''; - if (column.nowrap) { - nowrap = 'style="white-space:nowrap;"'; - } - - // get column settings - var column_settings = item.column_config[column.label]; - - // load attributes - var link = column_settings.link; - var value = column_settings.value; - var inbound = column_settings.inbound; - - // unescape value - if (jQuery.type( value ) === 'string') { - value = value.replace(/\/\//g, '/'); - } - - // Attach popup menu? - var id = ""; - var cls = ""; - if (column.attach_popup) { - id = 'grid-' + i + '-popup'; - cls = "menubutton" - if (link != '') { - cls += " split"; - } - cls += " popup"; - } - - // Check for row wrapping - tmpl += '<td ' + nowrap + '>'; - - // Link - if (link) { - if (options.operations.length != 0) { - tmpl += '<div id="' + id + '" class="' + cls + '" style="float: left;">'; - } - - var label_class = ""; - if (inbound) { - label_class = "use-inbound" - } else { - label_class = "use-outbound" - } - tmpl += '<a class="label ' + label_class + '" href="' + link + '" onclick="return false;">' + value + '</a>'; - if (options.operations.length != 0) { - tmpl += '</div>'; - } - } else { - tmpl += '<div id="' + id + '" class="' + cls + '"><label id="' + column.label_id_prefix + encoded_id + '" for="' + encoded_id + '">' + value + '</label></div>'; - } - tmpl += '</td>'; - } - } - tmpl += '</tr>'; - num_rows_rendered++; - } - return tmpl; - }, - - // template - template_footer: function(options) { - - // create template string - var tmpl = ''; - - // paging - if (options.use_paging && options.num_pages > 1) { - // get configuration - var num_page_links = options.num_page_links; - var cur_page_num = options.cur_page_num; - var num_pages = options.num_pages; - - // First pass on min page. - var page_link_range = num_page_links / 2; - var min_page = cur_page_num - page_link_range - var min_offset = 0; - if (min_page == 0) { - // Min page is too low. - min_page = 1; - min_offset = page_link_range - ( cur_page_num - min_page ); - } - - // Set max page. - var max_range = page_link_range + min_offset; - var max_page = cur_page_num + max_range; - if (max_page <= num_pages) { - // Max page is fine. - max_offset = 0; - } else { - // Max page is too high. - max_page = num_pages; - // +1 to account for the +1 in the loop below. - max_offset = max_range - ( max_page + 1 - cur_page_num ); - } - - // Second and final pass on min page to add any unused - // offset from max to min. - if (max_offset != 0) { - min_page -= max_offset - if (min_page < 1) { - min_page = 1 - } - } - - // template header - tmpl += '<tr id="page-links-row">'; - if (options.show_item_checkboxes) { - tmpl += '<td></td>'; - } - tmpl += '<td colspan="100">' + - '<span id="page-link-container">' + - 'Page:'; - - if (min_page > 1) { - tmpl += '<span class="page-link" id="page-link-1"><a href="' + this.grid.get_url({page : page_index}) + '" page_num="1" onclick="return false;">1</a></span> ...'; - } - - // create page urls - for (var page_index = min_page; page_index < max_page + 1; page_index++) { - - if (page_index == options.cur_page_num) { - tmpl += '<span class="page-link inactive-link" id="page-link-' + page_index + '">' + page_index + '</span>'; - } else { - tmpl += '<span class="page-link" id="page-link-' + page_index + '"><a href="' + this.grid.get_url({page : page_index}) + '" onclick="return false;" page_num="' + page_index + '">' + page_index + '</a></span>'; - } - } - - // show last page - if (max_page < num_pages) { - tmpl += '...' + - '<span class="page-link" id="page-link-' + num_pages + '"><a href="' + this.grid.get_url({page : num_pages}) + '" onclick="return false;" page_num="' + num_pages + '">' + num_pages + '</a></span>'; - } - tmpl += '</span>'; - - // Show all link - tmpl += '<span class="page-link" id="show-all-link-span"> | <a href="' + this.grid.get_url({page : 'all'}) + '" onclick="return false;" page_num="all">Show All</a></span>' + - '</td>' + - '</tr>'; - } - - // Grid operations for multiple items. - if (options.show_item_checkboxes) { - // start template - tmpl += '<tr>' + - '<input type="hidden" id="operation" name="operation" value="">' + - '<td></td>' + - '<td colspan="100">' + - 'For <span class="grid-selected-count"></span> selected ' + options.get_class_plural + ': '; - - // configure buttons for operations - for (i in options.operations) { - var operation = options.operations[i]; - if (operation.allow_multiple) { - tmpl += '<input type="button" value="' + operation.label + '" class="action-button" onclick="gridView.submit_operation(this, \'' + operation.confirm + '\')"> '; - } - } - - // finalize template - tmpl += '</td>' + - '</tr>'; - } - - // count global operations - var found_global = false; - for (i in options.operations) { - if (options.operations[i].global_operation) { - found_global = true; - break; - } - } - - // add global operations - if (found_global) { - tmpl += '<tr>' + - '<td colspan="100">'; - for (i in options.operations) { - var operation = options.operations[i]; - if (operation.global_operation) { - tmpl += '<a class="action-button" href="' + operation.global_operation + '">' + operation.label + '</a>'; - } - } - tmpl += '</td>' + - '</tr>'; - } - - // add legend - if (options.legend) { - tmpl += '<tr>' + - '<td colspan="100">' + options.legend + '</td>' + - '</tr>'; - } - - // return - return tmpl; - }, - - // template - template_message: function(options) { - return '<p>' + - '<div class="' + options.status + 'message transient-message">' + options.message + '</div>' + - '<div style="clear: both"></div>' + - '</p>'; - } -}); - -return { - Grid : Grid, - GridView : GridView -}; - -}); \ No newline at end of file diff -r be7ece9454471d655668f3997c29b90c2f6c312d -r b20d93e643068f3154752582db3d17e16c499633 static/scripts/mvc/grid/grid-model.js --- /dev/null +++ b/static/scripts/mvc/grid/grid-model.js @@ -0,0 +1,134 @@ +// dependencies +define([], function() { + +// grid model +return Backbone.Model.extend({ + defaults: { + url_base: '', + async: false, + async_ops: [], + categorical_filters: [], + filters: {}, + sort_key: null, + show_item_checkboxes: false, + advanced_search: false, + cur_page: 1, + num_pages: 1, + operation: undefined, + item_ids: undefined + }, + + /** + * Return true if operation can be done asynchronously. + */ + can_async_op: function(op) { + return _.indexOf(this.attributes.async_ops, op) !== -1; + }, + + /** + * Add filtering criterion. + */ + add_filter: function(key, value, append) { + // Update URL arg with new condition. + if (append) { + // Update or append value. + var cur_val = this.attributes.filters[key], + new_val; + if (cur_val === null || cur_val === undefined) { + new_val = value; + } + else if (typeof(cur_val) == "string") { + if (cur_val == "All") { + new_val = value; + } else { + // Replace string with array. + var values = []; + values[0] = cur_val; + values[1] = value; + new_val = values; + } + } + else { + // Current value is an array. + new_val = cur_val; + new_val.push(value); + } + this.attributes.filters[key] = new_val; + } + else { + // Replace value. + this.attributes.filters[key] = value; + } + }, + + /** + * Remove filtering criterion. + */ + remove_filter: function(key, condition) { + var cur_val = this.attributes.filters[key]; + if (cur_val === null || cur_val === undefined) { + return false; + } + + var removed = true; + if (typeof(cur_val) === "string") { + if (cur_val == "All") { + // Unexpected. Throw error? + removed = false; + } + else { + // Remove condition. + delete this.attributes.filters[key]; + } + } + else { + // Filter contains an array of conditions. + var condition_index = _.indexOf(cur_val, condition); + if (condition_index !== -1) { + cur_val.splice(condition_index, 1); + } + else { + removed = false; + } + } + + return removed; + }, + + /** + * Returns URL data for obtaining a new grid. + */ + get_url_data: function() { + var url_data = { + async: this.attributes.async, + sort: this.attributes.sort_key, + page: this.attributes.cur_page, + show_item_checkboxes: this.attributes.show_item_checkboxes, + advanced_search: this.attributes.advanced_search + }; + + // Add operation, item_ids only if they have values. + if (this.attributes.operation) { + url_data.operation = this.attributes.operation; + } + if (this.attributes.item_ids) { + url_data.id = this.attributes.item_ids; + } + + // Add filter arguments to data, placing "f-" in front of all arguments. + var self = this; + _.each(_.pairs(self.attributes.filters), function(k) { + url_data['f-' + k[0]] = k[1]; + }); + + return url_data; + }, + + // Return URL for obtaining a new grid + get_url: function (args) { + return this.get('url_base') + "?" + $.param(this.get_url_data()) + '&' + $.param(args); + } + +}); + +}); \ No newline at end of file diff -r be7ece9454471d655668f3997c29b90c2f6c312d -r b20d93e643068f3154752582db3d17e16c499633 static/scripts/mvc/grid/grid-template.js --- /dev/null +++ b/static/scripts/mvc/grid/grid-template.js @@ -0,0 +1,617 @@ +// dependencies +define([], function() { + +// grid view templates +return { + // template + grid: function(options) { + var tmpl = ''; + if (options.embedded) { + tmpl = this.grid_header(options) + this.grid_table(options); + } else { + tmpl = '<div class="loading-elt-overlay"></div>' + + '<table>' + + '<tr>' + + '<td width="75%">' + + this.grid_header(options) + + '</td>' + + '<td></td>' + + '<td></td>' + + '</tr>' + + '<tr>' + + '<td width="100%" id="grid-message" valign="top"></td>' + + '<td></td>' + + '<td></td>' + + '</tr>' + + '</table>' + + this.grid_table(options); + } + + // add info text + if (options.info_text) { + tmpl += '<br><div class="toolParamHelp" style="clear: both;">' + options.info_text + '</div>'; + } + + // return + return tmpl; + }, + + // template + grid_table: function(options) { + return '<form method="post" onsubmit="return false;">' + + '<table id="grid-table" class="grid">' + + '<thead id="grid-table-header"></thead>' + + '<tbody id="grid-table-body"></tbody>' + + '<tfoot id="grid-table-footer"></tfoot>' + + '</table>' + + '</form>'; + }, + + // template + grid_header: function(options) { + var tmpl = '<div class="grid-header">'; + if (!options.embedded) { + tmpl += '<h2>' + options.title + '</h2>'; + } + if (options.global_actions) { + tmpl += '<ul class="manage-table-actions">'; + var show_popup = (options.global_actions.length >= 3); + if (show_popup) { + tmpl += '<li><a class="action-button" id="popup-global-actions" class="menubutton">Actions</a></li>' + + '<div popupmenu="popup-global-actions">'; + } + for (i in options.global_actions) { + var action = options.global_actions[i]; + var label_cls = ''; + if (action.inbound) { + label_cls = 'use-inbound' + } else { + label_cls = 'use-outbound' + } + tmpl += '<li>' + + '<a class="action-button ' + label_cls + '" href="' + action.url_args + '" onclick="return false;">' + action.label + '</a>' + + '</li>'; + } + if (show_popup) { + tmpl += '</div>'; + } + tmpl += '</ul>'; + } + if (options.insert) { + tmpl += options.insert; + } + + // add grid filters + tmpl += this.grid_filters(options); + tmpl += '</div>' + + // return template + return tmpl; + }, + + // template + header: function(options) { + + // start + var tmpl = '<tr>'; + + // add checkbox + if (options.show_item_checkboxes) { + tmpl += '<th>'; + if (options.items.length > 0) { + tmpl += '<input type="checkbox" id="check_all" name=select_all_checkbox value="true">' + + '<input type="hidden" name=select_all_checkbox value="true">'; + } + tmpl += '</th>'; + } + + // create header elements + for (var i in options.columns) { + var column = options.columns[i]; + if (column.visible) { + tmpl += '<th id="' + column.key + '-header">'; + if (column.href) { + tmpl += '<a href="' + column.href + '" class="sort-link" sort_key="' + column.key + '">' + column.label + '</a>'; + } else { + tmpl += column.label; + } + tmpl += '<span class="sort-arrow">' + column.extra + '</span>' + + '</th>'; + } + } + + // finalize + tmpl += '</tr>'; + + // return template + return tmpl; + }, + + // template + body: function(options) { + // initialize + var tmpl = ''; + var num_rows_rendered = 0; + var items_length = options.items.length; + + // empty grid? + if (items_length == 0) { + // No results. + tmpl += '<tr><td colspan="100"><em>No Items</em></td></tr>'; + num_rows_rendered = 1; + } + + // create rows + for (var i in options.items) { + + // encode ids + var item = options.items[i]; + var encoded_id = item.encode_id; + var popupmenu_id = 'grid-' + i + '-popup'; + + // Tag current + tmpl += '<tr '; + if (options.current_item_id == item.id) { + tmpl += 'class="current"'; + } + tmpl += '>'; + + // Item selection column + if (options.show_item_checkboxes) { + tmpl += '<td style="width: 1.5em;">' + + '<input type="checkbox" name="id" value="' + encoded_id + '" id="' + encoded_id + '" class="grid-row-select-checkbox" />' + + '</td>'; + } + + // Data columns + for (j in options.columns) { + var column = options.columns[j]; + if (column.visible) { + // Nowrap + var nowrap = ''; + if (column.nowrap) { + nowrap = 'style="white-space:nowrap;"'; + } + + // get column settings + var column_settings = item.column_config[column.label]; + + // load attributes + var link = column_settings.link; + var value = column_settings.value; + var inbound = column_settings.inbound; + + // unescape value + if (jQuery.type( value ) === 'string') { + value = value.replace(/\/\//g, '/'); + } + + // Attach popup menu? + var id = ''; + var cls = ''; + if (column.attach_popup) { + id = 'grid-' + i + '-popup'; + cls = 'menubutton'; + if (link != '') { + cls += ' split'; + } + cls += ' popup'; + } + + // Check for row wrapping + tmpl += '<td ' + nowrap + '>'; + + // Link + if (link) { + if (options.operations.length != 0) { + tmpl += '<div id="' + id + '" class="' + cls + '" style="float: left;">'; + } + + var label_class = ''; + if (inbound) { + label_class = 'use-inbound'; + } else { + label_class = 'use-outbound'; + } + tmpl += '<a class="label ' + label_class + '" href="' + link + '" onclick="return false;">' + value + '</a>'; + if (options.operations.length != 0) { + tmpl += '</div>'; + } + } else { + tmpl += '<div id="' + id + '" class="' + cls + '"><label id="' + column.label_id_prefix + encoded_id + '" for="' + encoded_id + '">' + value + '</label></div>'; + } + tmpl += '</td>'; + } + } + tmpl += '</tr>'; + num_rows_rendered++; + } + return tmpl; + }, + + // template + footer: function(options) { + + // create template string + var tmpl = ''; + + // paging + if (options.use_paging && options.num_pages > 1) { + // get configuration + var num_page_links = options.num_page_links; + var cur_page_num = options.cur_page_num; + var num_pages = options.num_pages; + + // First pass on min page. + var page_link_range = num_page_links / 2; + var min_page = cur_page_num - page_link_range + var min_offset = 0; + if (min_page == 0) { + // Min page is too low. + min_page = 1; + min_offset = page_link_range - ( cur_page_num - min_page ); + } + + // Set max page. + var max_range = page_link_range + min_offset; + var max_page = cur_page_num + max_range; + if (max_page <= num_pages) { + // Max page is fine. + max_offset = 0; + } else { + // Max page is too high. + max_page = num_pages; + // +1 to account for the +1 in the loop below. + max_offset = max_range - ( max_page + 1 - cur_page_num ); + } + + // Second and final pass on min page to add any unused + // offset from max to min. + if (max_offset != 0) { + min_page -= max_offset + if (min_page < 1) { + min_page = 1 + } + } + + // template header + tmpl += '<tr id="page-links-row">'; + if (options.show_item_checkboxes) { + tmpl += '<td></td>'; + } + tmpl += '<td colspan="100">' + + '<span id="page-link-container">' + + 'Page:'; + + if (min_page > 1) { + tmpl += '<span class="page-link" id="page-link-1"><a href="' + this.grid.get_url({page : page_index}) + '" page_num="1" onclick="return false;">1</a></span> ...'; + } + + // create page urls + for (var page_index = min_page; page_index < max_page + 1; page_index++) { + + if (page_index == options.cur_page_num) { + tmpl += '<span class="page-link inactive-link" id="page-link-' + page_index + '">' + page_index + '</span>'; + } else { + tmpl += '<span class="page-link" id="page-link-' + page_index + '"><a href="' + this.grid.get_url({page : page_index}) + '" onclick="return false;" page_num="' + page_index + '">' + page_index + '</a></span>'; + } + } + + // show last page + if (max_page < num_pages) { + tmpl += '...' + + '<span class="page-link" id="page-link-' + num_pages + '"><a href="' + this.grid.get_url({page : num_pages}) + '" onclick="return false;" page_num="' + num_pages + '">' + num_pages + '</a></span>'; + } + tmpl += '</span>'; + + // Show all link + tmpl += '<span class="page-link" id="show-all-link-span"> | <a href="' + this.grid.get_url({page : 'all'}) + '" onclick="return false;" page_num="all">Show All</a></span>' + + '</td>' + + '</tr>'; + } + + // Grid operations for multiple items. + if (options.show_item_checkboxes) { + // start template + tmpl += '<tr>' + + '<input type="hidden" id="operation" name="operation" value="">' + + '<td></td>' + + '<td colspan="100">' + + 'For <span class="grid-selected-count"></span> selected ' + options.get_class_plural + ': '; + + // configure buttons for operations + for (i in options.operations) { + var operation = options.operations[i]; + if (operation.allow_multiple) { + tmpl += '<input type="button" value="' + operation.label + '" class="operation-button action-button"> '; + } + } + + // finalize template + tmpl += '</td>' + + '</tr>'; + } + + // count global operations + var found_global = false; + for (i in options.operations) { + if (options.operations[i].global_operation) { + found_global = true; + break; + } + } + + // add global operations + if (found_global) { + tmpl += '<tr>' + + '<td colspan="100">'; + for (i in options.operations) { + var operation = options.operations[i]; + if (operation.global_operation) { + tmpl += '<a class="action-button" href="' + operation.global_operation + '">' + operation.label + '</a>'; + } + } + tmpl += '</td>' + + '</tr>'; + } + + // add legend + if (options.legend) { + tmpl += '<tr>' + + '<td colspan="100">' + options.legend + '</td>' + + '</tr>'; + } + + // return + return tmpl; + }, + + // template + message: function(options) { + return '<p>' + + '<div class="' + options.status + 'message transient-message">' + options.message + '</div>' + + '<div style="clear: both"></div>' + + '</p>'; + }, + + // template + grid_filters: function (options) { + + // get filters + var default_filter_dict = options.default_filter_dict; + var filters = options.filters; + + // show advanced search if flag set or if there are filters for advanced search fields + var advanced_search_display = 'none'; + if (options.advanced_search) { + advanced_search_display = 'block'; + } + + // identify columns with advanced filtering + var show_advanced_search_link = false; + for (var i in options.columns) { + var column = options.columns[i]; + if (column.filterable == 'advanced') { + var column_key = column.key; + var f_key = filters[column_key]; + var d_key = default_filter_dict[column_key]; + if (f_key && d_key && f_key != d_key) { + advanced_search_display = 'block'; + } + show_advanced_search_link = true; + } + } + + // hide standard search if advanced is shown + var standard_search_display = 'block'; + if (advanced_search_display == 'block') { + standard_search_display = 'none'; + } + + // + // standard search + // + var tmpl = '<div id="standard-search" style="display: ' + standard_search_display + ';">' + + '<table>' + + '<tr>' + + '<td style="padding: 0;">' + + '<table>'; + + // add standard filters + for (var i in options.columns) { + var column = options.columns[i]; + if (column.filterable == 'standard') { + tmpl += this.grid_column_filter(options, column); + } + } + + // finalize standard search + tmpl += '</table>' + + '</td>' + + '</tr>' + + '<tr>' + + '<td>'; + + // show advanced search link in standard display + if (show_advanced_search_link) { + tmpl += '<a href="" class="advanced-search-toggle">Advanced Search</a>'; + } + + // finalize standard search display + tmpl += '</td>' + + '</tr>' + + '</table>' + + '</div>'; + + // + // advanced search + // + tmpl += '<div id="advanced-search" style="display: ' + advanced_search_display + '; margin-top: 5px; border: 1px solid #ccc;">' + + '<table>' + + '<tr>' + + '<td style="text-align: left" colspan="100">' + + '<a href="" class="advanced-search-toggle">Close Advanced Search</a>' + + '</td>' + + '</tr>'; + + // add advanced filters + for (var i in options.columns) { + var column = options.columns[i]; + if (column.filterable == 'advanced') { + tmpl += this.grid_column_filter(options, column); + } + } + + // finalize advanced search template + tmpl += '</table>' + + '</div>'; + + // return template + return tmpl; + }, + + // template + grid_column_filter: function(options, column) { + + // collect parameters + var default_filter_dict = options.default_filter_dict; + var filters = options.filters; + var column_label = column.label; + var column_key = column.key; + if (column.filterable == 'advanced') { + column_label = column_label.toLowerCase(); + } + + // start + var tmpl = '<tr>'; + + if (column.filterable == 'advanced') { + tmpl += '<td align="left" style="padding-left: 10px">' + column_label + ':</td>'; + } + tmpl += '<td style="padding-bottom: 1px;">'; + if (column.is_text) { + tmpl += '<form class="text-filter-form" column_key="' + column_key + '" action="' + options.url + '" method="get" >'; + // Carry forward filtering criteria with hidden inputs. + for (i in options.columns) { + var temp_column = options.columns[i]; + var filter_value = filters[temp_column.key]; + if (filter_value) { + if (filter_value != 'All') { + if (temp_column.is_text) { + filter_value = JSON.stringify( filter_value ) + } + tmpl += '<input type="hidden" id="' + temp_column.key + '" name="f-' + temp_column.key + '" value="' + filter_value + '"/>'; + } + } + } + // Print current filtering criteria and links to delete. + tmpl += '<span id="' + column_key + '-filtering-criteria">'; + + // add filters + var column_filter = filters[column_key]; + if (column_filter) { + // identify type + var type = jQuery.type(column_filter); + + // single filter value + if (type == 'string') { + if (column_filter != 'All') { + // append template + tmpl += this.filter_element(column_key, column_filter); + } + } + + // multiple filter values + if (type == 'array') { + for (var i in column_filter ) { + // get filter + var filter = column_filter[i]; + + // copy filters and remove entry + var params = column_filter; + params = params.slice(i); + + // append template + tmpl += this.filter_element(column_key, filter); + } + } + } + + // close span + tmpl += '</span>'; + + // Set value, size of search input field. Minimum size is 20 characters. + var value = ''; + if (column.filterable == 'standard') { + value = column.label.toLowerCase(); + var size = value.length; + if (size < 20) { + size = 20; + } + // +4 to account for search icon/button. + size = size + 4; + } + + // print input field for column + tmpl += '<span class="search-box">' + + '<input class="search-box-input" id="input-' + column_key + '-filter" name="f-' + column_key + '" type="text" placeholder="' + value + '" size="' + size + '"/>' + + //'<button type="submit" style="background: transparent; border: none; padding: 4px; margin: 0px;">' + + // '<i class="fa fa-plus-circle" style="font-size: 1.2em;"></i>' + + //'</button>' + + '</span>' + + '</form>'; + } else { + // filter criteria + tmpl += '<span id="' + column_key + '-filtering-criteria">'; + + // add category filters + var seperator = false; + for (cf_label in options.categorical_filters[column_key]) { + // get category filter + var cf = options.categorical_filters[column_key][cf_label]; + + // each filter will have only a single argument, so get that single argument + var cf_key = ''; + var cf_arg = ''; + for (key in cf) { + cf_key = key; + cf_arg = cf[key]; + } + + // add seperator + if (seperator) { + tmpl += ' | '; + } + seperator = true; + + // add category + var filter = filters[column_key]; + if (filter && cf[column_key] && filter == cf_arg) { + tmpl += '<span class="categorical-filter ' + column_key + '-filter current-filter">' + cf_label + '</span>'; + } else { + tmpl += '<span class="categorical-filter ' + column_key + '-filter">' + + '<a href="javascript:void(0);" filter_key="' + cf_key + '" filter_val="' + cf_arg + '">' + cf_label + '</a>' + + '</span>'; + } + } + tmpl += '</span>'; + } + tmpl += '</td>' + + '</tr>'; + + // return template + return tmpl; + }, + + // template for filter items + filter_element: function(filter_key, filter_value) { + return '<span class="text-filter-val">' + filter_value + + '<a href="javascript:void(0);" filter_key="' + filter_key + '" filter_val="' + filter_value + '">' + + '<i class="fa fa-times" style="padding-left: 5px; padding-bottom: 6px;"/>' + + '</a>' + + '</span>'; + + } +}; + +}); \ No newline at end of file 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.
participants (1)
-
commits-noreply@bitbucket.org