diff --git a/tailbone/static/css/grids.css b/tailbone/static/css/grids.css index 04cb867f..104e6e7a 100644 --- a/tailbone/static/css/grids.css +++ b/tailbone/static/css/grids.css @@ -240,6 +240,23 @@ text-align: center; } +.grid tr:not(.header).selected.odd { + background-color: #507aaa; +} + +.grid tr:not(.header).selected.even { + background-color: #628db6; +} + +.grid tr:not(.header).selected.hovering { + background-color: #3e5b76; + color: white; +} + +.grid tr:not(.header).selected a { + color: #cccccc; +} + /****************************** * main actions diff --git a/tailbone/static/js/jquery.ui.tailbone.js b/tailbone/static/js/jquery.ui.tailbone.js index 7f9b3dd6..e8c14294 100644 --- a/tailbone/static/js/jquery.ui.tailbone.js +++ b/tailbone/static/js/jquery.ui.tailbone.js @@ -1,8 +1,107 @@ -// -*- coding: utf-8 -*- + /********************************************************************** * jQuery UI plugins for Tailbone **********************************************************************/ +/********************************************************************** + * gridcore plugin + **********************************************************************/ + +(function($) { + + $.widget('tailbone.gridcore', { + + _create: function() { + + var that = this; + + // Add hover highlight effect to grid rows during mouse-over. + // this.element.on('mouseenter', 'tbody tr:not(.header)', function() { + this.element.on('mouseenter', 'tr:not(.header)', function() { + $(this).addClass('hovering'); + }); + // this.element.on('mouseleave', 'tbody tr:not(.header)', function() { + this.element.on('mouseleave', 'tr:not(.header)', function() { + $(this).removeClass('hovering'); + }); + + // do some extra stuff for grids with checkboxes + + // (un-)check all rows when clicking check-all box in header + if (this.element.find('tr.header td.checkbox :checkbox').length) { + this.element.on('click', 'tr.header td.checkbox :checkbox', function() { + var checked = $(this).prop('checked'); + var rows = that.element.find('tr:not(.header)'); + rows.find('td.checkbox :checkbox').prop('checked', checked); + if (checked) { + rows.addClass('selected'); + } else { + rows.removeClass('selected'); + } + that.element.trigger('gridchecked', that.count_selected()); + }); + } + + // when row with checkbox is clicked, toggle selected status, + // unless clicking checkbox (since that already toggles it) or a + // link (since that does something completely different) + this.element.on('click', 'tr:not(.header)', function(event) { + var el = $(event.target); + if (!el.is('a') && !el.is(':checkbox')) { + $(this).find('td.checkbox :checkbox').click(); + } + }); + + this.element.on('change', 'tr:not(.header) td.checkbox :checkbox', function() { + if (this.checked) { + $(this).parents('tr:first').addClass('selected'); + } else { + $(this).parents('tr:first').removeClass('selected'); + } + that.element.trigger('gridchecked', that.count_selected()); + }); + + // Show 'more' actions when user hovers over 'more' link. + this.element.on('mouseenter', '.actions a.more', function() { + that.element.find('.actions div.more').hide(); + $(this).siblings('div.more') + .show() + .position({my: 'left-5 top-4', at: 'left top', of: $(this)}); + }); + this.element.on('mouseleave', '.actions div.more', function() { + $(this).hide(); + }); + + // Add speed bump for "Delete Row" action, if grid is so configured. + if (this.element.data('delete-speedbump')) { + this.element.on('click', 'tr:not(.header) .actions a.delete', function() { + return confirm("Are you sure you wish to delete this object?"); + }); + } + }, + + count_selected: function() { + return this.element.find('tr:not(.header) td.checkbox input:checked').length; + }, + + // TODO: deprecate / remove this? + count_checked: function() { + return this.count_selected(); + }, + + selected_uuids: function() { + var uuids = []; + this.element.find('tr:not(.header) td.checkbox input:checked').each(function() { + uuids.push($(this).parents('tr:first').data('uuid')); + }); + return uuids; + } + + }); + +})( jQuery ); + + /********************************************************************** * gridwrapper plugin **********************************************************************/ @@ -25,6 +124,9 @@ this.save_defaults = this.filters.find('#save-defaults'); this.grid = this.element.find('.grid'); + // add standard grid behavior + this.grid.gridcore(); + // Enhance filters etc. this.filters.find('.filter').gridfilter(); this.apply_filters.button('option', 'icons', {primary: 'ui-icon-search'}); @@ -147,56 +249,6 @@ that.refresh(this.search.substring(1)); // remove leading '?' return false; }); - - // Add hover highlight effect to grid rows during mouse-over. - this.element.on('mouseenter', 'tbody tr:not(.header)', function() { - $(this).addClass('hovering'); - }); - this.element.on('mouseleave', 'tbody tr:not(.header)', function() { - $(this).removeClass('hovering'); - }); - - // do some extra stuff for grids with checkboxes - - // (un-)check all rows when clicking check-all box in header - if (this.grid.find('tr.header td.checkbox input').length) { - this.element.on('click', 'tr.header td.checkbox input', function() { - var checked = $(this).prop('checked'); - that.grid.find('tr:not(.header) td.checkbox input').prop('checked', checked); - }); - - } - - // Select current row when clicked, unless clicking checkbox - // (since that already does select the row) or a link (since - // that does something completely different). - this.element.on('click', '.grid tr:not(.header) td.checkbox input', function(event) { - event.stopPropagation(); - }); - this.element.on('click', '.grid tr:not(.header) a', function(event) { - event.stopPropagation(); - }); - this.element.on('click', '.grid tr:not(.header)', function() { - $(this).find('td.checkbox input').click(); - }); - - // Show 'more' actions when user hovers over 'more' link. - this.element.on('mouseenter', '.actions a.more', function() { - that.grid.find('.actions div.more').hide(); - $(this).siblings('div.more') - .show() - .position({my: 'left-5 top-4', at: 'left top', of: $(this)}); - }); - this.element.on('mouseleave', '.actions div.more', function() { - $(this).hide(); - }); - - // Add speed bump for "Delete Row" action, if grid is so configured. - if (this.grid.data('delete-speedbump')) { - this.element.on('click', 'tbody td.actions a.delete', function() { - return confirm("Are you sure you wish to delete this object?"); - }); - } }, // Refreshes the visible data within the grid, according to the given settings. @@ -206,6 +258,7 @@ $.get(this.grid.data('url'), settings, function(data) { that.grid.replaceWith(data); that.grid = that.element.find('.grid'); + that.grid.gridcore(); that.element.unmask(); }); } diff --git a/tailbone/templates/base.mako b/tailbone/templates/base.mako index 15d5974d..6a5ed524 100644 --- a/tailbone/templates/base.mako +++ b/tailbone/templates/base.mako @@ -155,7 +155,8 @@ var noop_url = '${request.route_url('noop')}'; ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js') + '?ver={}'.format(tailbone.__version__))} - ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.feedback.js'))} + ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.feedback.js') + '?ver={}'.format(tailbone.__version__))} + ${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js') + '?ver={}'.format(tailbone.__version__))} <%def name="extra_javascript()"> diff --git a/tailbone/templates/batch/edit.mako b/tailbone/templates/batch/edit.mako index c0183535..f79ec2dd 100644 --- a/tailbone/templates/batch/edit.mako +++ b/tailbone/templates/batch/edit.mako @@ -3,7 +3,6 @@ <%def name="extra_javascript()"> ${parent.extra_javascript()} - ${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js'))} ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.batch.js'))}