diff --git a/web/pgadmin/browser/register_browser_preferences.py b/web/pgadmin/browser/register_browser_preferences.py index 009f1c1..bb5da06 100644 --- a/web/pgadmin/browser/register_browser_preferences.py +++ b/web/pgadmin/browser/register_browser_preferences.py @@ -387,3 +387,18 @@ def register_browser_preferences(self): category_label=gettext('Keyboard shortcuts'), fields=fields ) + + self.preference.register( + 'keyboard_shortcuts', + 'add_grid_row', + gettext('Add grid row'), + 'keyboardshortcut', + { + 'alt': False, + 'shift': True, + 'control': True, + 'key': {'key_code': 65, 'char': 'a'} + }, + category_label=gettext('Keyboard shortcuts'), + fields=fields + ) diff --git a/web/pgadmin/browser/static/js/keyboard.js b/web/pgadmin/browser/static/js/keyboard.js index 9ad59b6..b50d025 100644 --- a/web/pgadmin/browser/static/js/keyboard.js +++ b/web/pgadmin/browser/static/js/keyboard.js @@ -41,6 +41,7 @@ _.extend(pgBrowser.keyboardNavigation, { 'direct_debugging': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'direct_debugging').value), 'drop_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_multiple').value), 'drop_cascade_multiple_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'grid_menu_drop_cascade_multiple').value), + 'add_grid_row': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'add_grid_row').value), }; this.shortcutMethods = { @@ -61,6 +62,7 @@ _.extend(pgBrowser.keyboardNavigation, { 'bindDirectDebugging': {'shortcuts': this.keyboardShortcut.direct_debugging}, // Sub menu - Direct Debugging 'bindDropMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_multiple_objects}, // Grid Menu Drop Multiple 'bindDropCascadeMultipleObjects': {'shortcuts': this.keyboardShortcut.drop_cascade_multiple_objects}, // Grid Menu Drop Cascade Multiple + 'bindAddGridRow': {'shortcuts': this.keyboardShortcut.add_grid_row}, // Subnode Grid Add Row }; this.bindShortcuts(); } @@ -330,6 +332,12 @@ _.extend(pgBrowser.keyboardNavigation, { $('button.delete_multiple_cascade').click(); } }, + bindAddGridRow: function() { + let subNode = $(document.activeElement).closest('.object.subnode'); + if($(subNode).length) { + $(subNode).find('.add').click(); + } + }, isPropertyPanelVisible: function() { let isPanelVisible = false; _.each(pgAdmin.Browser.docker.findPanels(), (panel) => { diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index b97fc38..156430d 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -10,8 +10,10 @@ define([ 'sources/gettext', 'underscore', 'underscore.string', 'jquery', 'backbone', 'backform', 'backgrid', 'codemirror', 'sources/sqleditor_utils', + 'sources/keyboard_shortcuts', 'spectrum', 'pgadmin.backgrid', 'select2', 'bootstrap.toggle', -], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror, SqlEditorUtils) { +], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror, + SqlEditorUtils, keyboardShortcuts) { var pgAdmin = (window.pgAdmin = window.pgAdmin || {}), pgBrowser = pgAdmin.Browser; @@ -1269,6 +1271,13 @@ define([ var $dialog = gridBody.append(subNodeGrid); + let preferences = pgBrowser.get_preferences_for_module('browser'); + let addBtn = $dialog.find('.add'); + // Add title to the buttons + $(addBtn) + .attr('title', + keyboardShortcuts.shortcut_title(gettext('Add new row'),preferences.add_grid_row)); + // Add button callback if (!(data.disabled || data.canAdd == false)) { $dialog.find('button.add').first().on('click',(e) => { @@ -1554,6 +1563,14 @@ define([ var $dialog = gridBody.append(subNodeGrid); + let preferences = pgBrowser.get_preferences_for_module('browser'); + let addBtn = $dialog.find('.add'); + // Add title to the buttons + $(addBtn) + .attr('title', + keyboardShortcuts.shortcut_title(gettext('Add new row'),preferences.add_grid_row)); + + // Add button callback $dialog.find('button.add').on('click',(e) => { e.preventDefault(); diff --git a/web/pgadmin/static/js/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid.pgadmin.js index c804609..86cc35c 100644 --- a/web/pgadmin/static/js/backgrid.pgadmin.js +++ b/web/pgadmin/static/js/backgrid.pgadmin.js @@ -9,15 +9,18 @@ define([ 'sources/gettext', 'underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify', - 'moment', 'bignumber', 'bootstrap.datetimepicker', 'backgrid.filter', - 'bootstrap.toggle', + 'moment', 'bignumber', 'sources/utils', 'sources/keyboard_shortcuts', + 'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle', ], function( - gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber + gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber, + commonUtils, keyboardShortcuts ) { /* * Add mechanism in backgrid to render different types of cells in * same column; */ + let pgAdmin = (window.pgAdmin = window.pgAdmin || {}), + pgBrowser = pgAdmin.Browser; // Add new property cellFunction in Backgrid.Column. _.extend(Backgrid.Column.prototype.defaults, { @@ -37,6 +40,18 @@ define([ }, }); + // bind shortcut in cell edit mode + _.extend(Backgrid.InputCellEditor.prototype.events, { + 'keydown': function(e) { + let preferences = pgBrowser.get_preferences_for_module('browser'); + if(keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,e)) { + pgBrowser.keyboardNavigation.bindAddGridRow(); + } else { + Backgrid.InputCellEditor.prototype.saveOrCancel.apply(this, arguments); + } + }, + }); + /* Overriding backgrid sort method. * As we are getting numeric, integer values as string * from server side, but on client side javascript truncates @@ -189,7 +204,7 @@ define([ var ObjectCellEditor = Backgrid.Extension.ObjectCellEditor = Backgrid.CellEditor.extend({ modalTemplate: _.template([ - '
', + '
', '
', '
', ].join('\n')), @@ -235,6 +250,18 @@ define([ tabPanelClassName: function() { return 'sub-node-form col-sm-12'; }, + events: { + 'keydown': function (event) { + let preferences = pgBrowser.get_preferences_for_module('browser'); + if(keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,event)) { + pgBrowser.keyboardNavigation.bindAddGridRow(); + } else if(keyboardShortcuts.validateShortcutKeys(preferences.save_grid_row,event)) { + pgBrowser.keyboardNavigation.bindSaveGridRow(); + } else if(keyboardShortcuts.validateShortcutKeys(preferences.refresh_grid,event)) { + pgBrowser.keyboardNavigation.bindRefreshGrid(); + } + }, + }, }); this.objectView.render(); @@ -315,12 +342,18 @@ define([ editorOptions['el'] = $(this.el); editorOptions['columns_length'] = this.column.collection.length; - editorOptions['el'].attr('tabindex', 1); + editorOptions['el'].attr('tabindex', 0); this.listenTo(this.model, 'backgrid:edit', function(model, column, cell, editor) { if (column.get('name') == this.column.get('name')) editor.extendWithOptions(editorOptions); }); + // Listen for Tab key, open subnode dialog on space key + this.$el.on('keydown', function(e) { + if (e.keyCode == 32) { + $(this).click(); + } + }); }, enterEditMode: function() { // Notify that we are about to enter in edit mode for current cell. @@ -342,6 +375,10 @@ define([ this.$el.html( '' ); + let body = $(this.$el).parents()[1], + container = $(body).find('.tab-content:first > .tab-pane.active:first'); + commonUtils.findAndSetFocus(container); + pgBrowser.keyboardNavigation.getDialogTabNavigator($(body).find('.subnode-dialog')); this.model.trigger( 'pg-sub-node:opened', this.model, this ); @@ -362,14 +399,16 @@ define([ return this; }, exitEditMode: function() { - var index = $(this.currentEditor.objectView.el) - .find('.nav-tabs > .active > a[data-toggle="tab"]').first() - .data('tabIndex'); - Backgrid.Cell.prototype.exitEditMode.apply(this, arguments); - this.model.trigger( - 'pg-sub-node:closed', this, index - ); - this.grabFocus = true; + if(!_.isUndefined(this.currentEditor) || !_.isEmpty(this.currentEditor)) { + var index = $(this.currentEditor.objectView.el) + .find('.nav-tabs > .active > a[data-toggle="tab"]').first() + .data('tabIndex'); + Backgrid.Cell.prototype.exitEditMode.apply(this, arguments); + this.model.trigger( + 'pg-sub-node:closed', this, index + ); + this.grabFocus = true; + } }, events: { 'click': function(e) { @@ -382,6 +421,17 @@ define([ } e.preventDefault(); }, + 'keydown': function(e) { + var model = this.model; + var column = this.column; + var command = new Backgrid.Command(e); + + if (command.moveLeft()) { + setTimeout(function() { + model.trigger('backgrid:edited', model, column, command); + }, 20); + } + }, }, }); @@ -413,7 +463,16 @@ define([ delete_title, delete_msg, function() { + let tbody = that.el.closest('tbody'); that.model.collection.remove(that.model); + let row = $(tbody).find('tr'); + if(row.length > 0) { + // set focus to first tr + row.first().children()[0].focus(); + } else { + // set focus to add button + $(tbody).closest('.subnode').find('.add').focus(); + } }, function() { return true; @@ -427,12 +486,54 @@ define([ ); } }, + exitEditMode: function() { + this.$el.removeClass('editor'); + }, initialize: function() { Backgrid.Cell.prototype.initialize.apply(this, arguments); }, render: function() { + var self = this; this.$el.empty(); + $(this.$el).attr('tabindex', 0); this.$el.html(''); + // Listen for Tab/Shift-Tab key + this.$el.on('keydown', function(e) { + // with keyboard navigation on space key, mark row for deletion + if (e.keyCode == 32) { + self.$el.click(); + } + var gotoCell; + if (e.keyCode == 9 || e.keyCode == 16) { + // go to Next Cell & if Shift is also pressed go to Previous Cell + gotoCell = e.shiftKey ? self.$el.prev() : self.$el.next(); + } + + if (gotoCell) { + let command = new Backgrid.Command({ + key: 'Tab', + keyCode: 9, + which: 9, + shiftKey: e.shiftKey, + }); + setTimeout(function() { + // When we have Editable Cell + if (gotoCell.hasClass('editable')) { + e.preventDefault(); + e.stopPropagation(); + self.model.trigger('backgrid:edited', self.model, + self.column, command); + } + else { + // When we have Non-Editable Cell + self.model.trigger('backgrid:edited', self.model, + self.column, command); + } + }, 20); + } + }); + + this.delegateEvents(); return this; }, @@ -488,6 +589,7 @@ define([ 'change input': 'onChange', 'keyup': 'toggleSwitch', 'blur input': 'exitEditMode', + 'keydown': 'onKeyDown', }, toggleSwitch: function(e) { @@ -497,6 +599,13 @@ define([ } }, + onKeyDown: function(e) { + let preferences = pgBrowser.get_preferences_for_module('browser'); + if(keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,e)) { + pgBrowser.keyboardNavigation.bindAddGridRow(); + } + }, + onChange: function() { var model = this.model, column = this.column, @@ -553,7 +662,11 @@ define([ }); setTimeout(function() { // When we have Editable Cell - if (gotoCell.hasClass('editable')) { + if (gotoCell.hasClass('editable') && gotoCell.hasClass('edit-cell')) { + e.preventDefault(); + e.stopPropagation(); + gotoCell.trigger('focus'); + } else if (gotoCell.hasClass('editable')) { e.preventDefault(); e.stopPropagation(); self.model.trigger('backgrid:edited', self.model, @@ -608,8 +721,7 @@ define([ }, saveOrCancel: function (e) { - var model = this.model; - var column = this.column; + var self = this; var command = new Backgrid.Command(e); var blurred = e.type === 'blur'; @@ -617,10 +729,32 @@ define([ if (command.moveUp() || command.moveDown() || command.moveLeft() || command.moveRight() || command.save() || blurred) { - this.exitEditMode(); - e.preventDefault(); - e.stopPropagation(); - model.trigger('backgrid:edited', model, column, command); + let gotoCell; + // go to Next Cell & if Shift is also pressed go to Previous Cell + gotoCell = e.shiftKey ? self.$el.prev() : self.$el.next(); + + if (gotoCell) { + let command = new Backgrid.Command({ + key: 'Tab', + keyCode: 9, + which: 9, + shiftKey: e.shiftKey, + }); + setTimeout(function() { + // When we have Editable Cell + if (gotoCell.hasClass('editable')) { + e.preventDefault(); + e.stopPropagation(); + self.model.trigger('backgrid:edited', self.model, + self.column, command); + } + else { + // When we have Non-Editable Cell + self.model.trigger('backgrid:edited', self.model, + self.column, command); + } + }, 20); + } } }, events: { diff --git a/web/pgadmin/static/js/dialog_tab_navigator.js b/web/pgadmin/static/js/dialog_tab_navigator.js index 4472172..37bff6b 100644 --- a/web/pgadmin/static/js/dialog_tab_navigator.js +++ b/web/pgadmin/static/js/dialog_tab_navigator.js @@ -46,13 +46,13 @@ class dialogTabNavigator { if(childTabData) { var res = this.navigate(shortcut, childTabData.childTab, - childTabData.childTabPane); + childTabData.childTabPane, event); if (!res) { - this.navigate(shortcut, this.tabs, currentTabPane); + this.navigate(shortcut, this.tabs, currentTabPane, event); } } else { - this.navigate(shortcut, this.tabs, currentTabPane); + this.navigate(shortcut, this.tabs, currentTabPane, event); } } @@ -73,16 +73,16 @@ class dialogTabNavigator { return null; } - navigate(shortcut, tabs, tab_pane) { + navigate(shortcut, tabs, tab_pane, event) { if(shortcut == this.dialogTabBackward) { - return this.navigateBackward(tabs, tab_pane); + return this.navigateBackward(tabs, tab_pane, event); }else if (shortcut == this.dialogTabForward) { - return this.navigateForward(tabs, tab_pane); + return this.navigateForward(tabs, tab_pane, event); } return false; } - navigateBackward(tabs, tab_pane) { + navigateBackward(tabs, tab_pane, event) { var self = this, nextTabPane, innerTabContainer, @@ -105,6 +105,7 @@ class dialogTabNavigator { self.tabSwitching = false; }, 200); + event.stopPropagation(); return true; } @@ -112,7 +113,7 @@ class dialogTabNavigator { return false; } - navigateForward(tabs, tab_pane) { + navigateForward(tabs, tab_pane, event) { var self = this, nextTabPane, innerTabContainer, @@ -135,6 +136,8 @@ class dialogTabNavigator { self.tabSwitching = false; }, 200); + event.stopPropagation(); + return true; } this.tabSwitching = false; diff --git a/web/pgadmin/static/scss/_backgrid.overrides.scss b/web/pgadmin/static/scss/_backgrid.overrides.scss index b0b7475..41266eb 100644 --- a/web/pgadmin/static/scss/_backgrid.overrides.scss +++ b/web/pgadmin/static/scss/_backgrid.overrides.scss @@ -288,6 +288,10 @@ table.backgrid { background-color: $color-bg-theme !important; } + & td.edit-cell.editor:focus { + outline: $input-focus-border-color auto 5px !important; + } + tr.editor-row { background-color: $color-gray-light !important; & > td { diff --git a/web/pgadmin/static/scss/_pgadmin.style.scss b/web/pgadmin/static/scss/_pgadmin.style.scss index f5a8877..8f1e248 100644 --- a/web/pgadmin/static/scss/_pgadmin.style.scss +++ b/web/pgadmin/static/scss/_pgadmin.style.scss @@ -729,10 +729,17 @@ table tr th { padding: 0; } & button:focus { - outline: none; + outline: $input-focus-border-color auto 5px !important; } } +table tr td { + td.edit-cell:focus, + td.delete-cell:focus, + td.string-cell:focus { + outline: $input-focus-border-color auto 5px !important; + } +} .privilege_label{ font-size: 10px!important; diff --git a/web/pgadmin/static/vendor/backgrid/backgrid.js b/web/pgadmin/static/vendor/backgrid/backgrid.js index 963ddca..1b3173b 100644 --- a/web/pgadmin/static/vendor/backgrid/backgrid.js +++ b/web/pgadmin/static/vendor/backgrid/backgrid.js @@ -8,32 +8,35 @@ ////////////////////////////////////////////////////////////// /*! - backgrid - http://github.com/wyuenho/backgrid + backgrid 0.3.8 + http://github.com/cloudflare/backgrid - Copyright (c) 2014 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2017 Cloudflare, Inc. and contributors Licensed under the MIT license. */ -(function (factory) { +(function (root, factory) { - // CommonJS - if (typeof exports == "object") { - module.exports = factory(module.exports, - require("underscore"), - require("backbone")); - } - // Browser - else factory(this, this._, this.Backbone); -}(function (root, _, Backbone) { + if (typeof define === "function" && define.amd) { + // AMD (+ global for extensions) + define(["underscore", "backbone"], function (_, Backbone) { + return (root.Backgrid = factory(_, Backbone)); + }); + } else if (typeof exports === "object") { + // CommonJS + module.exports = factory(require("underscore"), require("backbone")); + } else { + // Browser + root.Backgrid = factory(root._, root.Backbone); + }}(this, function (_, Backbone) { "use strict"; /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -72,7 +75,7 @@ function lpad(str, length, padstr) { var $ = Backbone.$; -var Backgrid = root.Backgrid = { +var Backgrid = { Extension: {}, @@ -180,9 +183,9 @@ _.extend(Command.prototype, { /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -285,7 +288,7 @@ _.extend(NumberFormatter.prototype, { fromRaw: function (number, model) { if (_.isNull(number) || _.isUndefined(number)) return ''; - number = number.toFixed(~~this.decimals); + number = parseFloat(number).toFixed(~~this.decimals); var parts = number.split('.'); var integerPart = parts[0]; @@ -625,9 +628,9 @@ _.extend(SelectFormatter.prototype, { /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -825,7 +828,8 @@ var Cell = Backgrid.Cell = Backbone.View.extend({ /** @property */ events: { - "click": "enterEditMode" + "click": "enterEditMode", + "focus": "onFocus" }, /** @@ -873,9 +877,16 @@ var Cell = Backgrid.Cell = Backbone.View.extend({ } }); - if (Backgrid.callByNeed(column.editable(), column, model)) $el.addClass("editable"); - if (Backgrid.callByNeed(column.sortable(), column, model)) $el.addClass("sortable"); - if (Backgrid.callByNeed(column.renderable(), column, model)) $el.addClass("renderable"); + this.updateStateClassesMaybe(); + }, + + updateStateClassesMaybe: function () { + var model = this.model; + var column = this.column; + var $el = this.$el; + $el.toggleClass("editable", Backgrid.callByNeed(column.editable(), column, model)); + $el.toggleClass("sortable", Backgrid.callByNeed(column.sortable(), column, model)); + $el.toggleClass("renderable", Backgrid.callByNeed(column.renderable(), column, model)); }, /** @@ -883,9 +894,18 @@ var Cell = Backgrid.Cell = Backbone.View.extend({ model's raw value for this cell's column. */ render: function () { - this.$el.empty(); + var $el = this.$el; + $el.empty(); var model = this.model; - this.$el.text(this.formatter.fromRaw(model.get(this.column.get("name")), model)); + var columnName = this.column.get("name"); + $el.text(this.formatter.fromRaw(model.get(columnName), model)); + $el.addClass(columnName); + if(this.$el.hasClass('string-cell')) { + if(Backgrid.callByNeed(this.column.editable(), this.column, this.model)) { + $el.attr('tabindex', 0); + } + } + this.updateStateClassesMaybe(); this.delegateEvents(); return this; }, @@ -935,6 +955,12 @@ var Cell = Backgrid.Cell = Backbone.View.extend({ } }, + onFocus: function (e) { + if(e.keyCode == 9 && $(this).hasClass('string-cell') && $(this).hasClass('editable')) { + $(this).click(); + } + }, + /** Put an `error` CSS class on the table cell. */ @@ -1408,7 +1434,15 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({ }, /** @property {function(Object, ?Object=): string} template */ - template: _.template('', null, {variable: null}), + template: _.template( + '', + null, + { + variable : null, + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }), setOptionValues: function (optionValues) { this.optionValues = optionValues; @@ -1651,9 +1685,9 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({ /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -1706,19 +1740,20 @@ var Column = Backgrid.Column = Backbone.Model.extend({ this column is sortable. If the value is a string, a method will the same name will be looked up from the column instance to determine whether the column should be sortable. The method's signature must be `function - (Backgrid.Column, Backbone.Model): boolean`. + (Backbone.Model): boolean`. The function's context is the column instance. @cfg {boolean|string|function(): boolean} [defaults.editable=true] Whether this column is editable. If the value is a string, a method will the same name will be looked up from the column instance to determine whether the column should be editable. The method's signature must be `function - (Backgrid.Column, Backbone.Model): boolean`. + (Backbone.Model): boolean`. The function's context is the column instance. @cfg {boolean|string|function(): boolean} [defaults.renderable=true] Whether this column is renderable. If the value is a string, a method will the same name will be looked up from the column instance to determine whether the column should be renderable. The method's signature must be - `function (Backrid.Column, Backbone.Model): boolean`. + `function (Backbone.Model): boolean`. The function's context is the column + instance. @cfg {Backgrid.CellFormatter | Object | string} [defaults.formatter] The formatter to use to convert between raw model values and user input. @@ -1824,24 +1859,33 @@ var Column = Backgrid.Column = Backbone.Model.extend({ } /** + If you cannot always determine whether a column should be sortable before + the grid get initialized, you can override this method. + @member Backgrid.Column @protected @method sortable - @return {function(Backgrid.Column, Backbone.Model): boolean | boolean} + @return {function(Backbone.Model): boolean | boolean} */ /** + If you cannot always determine whether a column should be editable before + the grid get initialized, you can override this method. + @member Backgrid.Column @protected @method editable - @return {function(Backgrid.Column, Backbone.Model): boolean | boolean} + @return {function(Backbone.Model): boolean | boolean} */ /** + If you cannot always determine whether a column should be renderable before + the grid get initialized, you can override this method. + @member Backgrid.Column @protected @method renderable - @return {function(Backgrid.Column, Backbone.Model): boolean | boolean} + @return {function(Backbone.Model): boolean | boolean} */ }); @@ -1871,9 +1915,9 @@ var Columns = Backgrid.Columns = Backbone.Collection.extend({ /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -2020,7 +2064,9 @@ var EmptyRow = Backgrid.EmptyRow = Backbone.View.extend({ var td = document.createElement("td"); td.setAttribute("colspan", this.columns.length); - td.appendChild(document.createTextNode(_.result(this, "emptyText"))); + var span = document.createElement("span"); + span.innerHTML = _.result(this, "emptyText"); + td.appendChild(span); this.el.className = "empty"; this.el.appendChild(td); @@ -2031,9 +2077,9 @@ var EmptyRow = Backgrid.EmptyRow = Backbone.View.extend({ /* backgrid - http://github.com/wyuenho/backgrid + http://github.com/cloudflare/backgrid - Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors + Copyright (c) 2013-present Cloudflare, Inc. and contributors Licensed under the MIT license. */ @@ -2052,7 +2098,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({ /** @property */ events: { - "click a": "onClick" + "click button": "onClick" }, /** @@ -2087,12 +2133,12 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({ if (Backgrid.callByNeed(column.sortable(), column, collection)) $el.addClass("sortable"); if (Backgrid.callByNeed(column.renderable(), column, collection)) $el.addClass("renderable"); - this.listenTo(collection.fullCollection || collection, "sort", this.removeCellDirection); + this.listenTo(collection.fullCollection || collection, "backgrid:sorted", this.removeCellDirection); }, /** - Event handler for the collection's `sort` event. Removes all the CSS - direction classes. + Event handler for the collection's `backgrid:sorted` event. Removes + all the CSS direction classes. */ removeCellDirection: function () { this.$el.removeClass("ascending").removeClass("descending"); @@ -2151,7 +2197,7 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({ var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection); var label; if(sortable){ - label = $("").text(column.get("label")).append(""); + label = $("