The Table navigation functionality was factored out to the Navigation class. Minor table performance fixes.

This commit is contained in:
alekseybobkov 2014-11-17 22:27:54 -08:00
parent 917958bc4c
commit 2bd40037d1
5 changed files with 206 additions and 137 deletions

View File

@ -63,6 +63,7 @@ class Table extends WidgetBase
{
$this->addCss('css/table.css', 'core');
$this->addJs('js/table.js', 'core');
$this->addJs('js/table.helper.navigation.js', 'core');
$this->addJs('js/table.datasource.base.js', 'core');
$this->addJs('js/table.datasource.client.js', 'core');
$this->addJs('js/table.processor.base.js', 'core');

View File

@ -0,0 +1,181 @@
/*
* Navigation helper for the table widget.
* Implements the keyboard navigation within the current page
* and pagination.
*/
+function ($) { "use strict";
// NAMESPACE CHECK
// ============================
if ($.oc.table === undefined)
throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");
if ($.oc.table.helper === undefined)
$.oc.table.helper = {}
// NAVIGATION CLASS DEFINITION
// ============================
var Navigation = function(tableObj) {
// Reference to the table object
this.tableObj = tableObj
// Event handlers
this.keydownHandler = this.onKeydown.bind(this)
this.init()
};
Navigation.prototype.init = function() {
this.registerHandlers()
}
Navigation.prototype.dispose = function() {
// Unregister event handlers
this.unregisterHandlers()
// Remove the reference to the table object
this.tableObj = null
}
Navigation.prototype.registerHandlers = function() {
this.tableObj.el.addEventListener('keydown', this.keydownHandler)
}
Navigation.prototype.unregisterHandlers = function() {
this.tableObj.el.removeEventListener('keydown', this.keydownHandler);
this.keydownHandler = null
}
// KEYBOARD NAVIGATION
// ============================
Navigation.prototype.navigateDown = function(ev) {
if (!this.tableObj.activeCell)
return
if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'down'))
return
var row = this.tableObj.activeCell.parentNode,
newRow = !ev.shiftKey ?
row.nextElementSibling :
row.parentNode.children[row.parentNode.children.length - 1]
if (!newRow)
return
var cell = newRow.children[this.tableObj.activeCell.cellIndex]
if (cell)
this.tableObj.focusCell(cell)
}
Navigation.prototype.navigateUp = function(ev) {
if (!this.tableObj.activeCell)
return
if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'up'))
return
var row = this.tableObj.activeCell.parentNode,
newRow = !ev.shiftKey ?
row.previousElementSibling :
row.parentNode.children[0]
if (!newRow)
return
var cell = newRow.children[this.tableObj.activeCell.cellIndex]
if (cell)
this.tableObj.focusCell(cell)
}
Navigation.prototype.navigateLeft = function(ev) {
if (!this.tableObj.activeCell)
return
if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'left'))
return
var row = this.tableObj.activeCell.parentNode,
newIndex = !ev.shiftKey ?
this.tableObj.activeCell.cellIndex-1 :
0
var cell = row.children[newIndex]
if (cell)
this.tableObj.focusCell(cell)
}
Navigation.prototype.navigateRight = function(ev) {
if (!this.tableObj.activeCell)
return
if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'right'))
return
var row = this.tableObj.activeCell.parentNode,
newIndex = !ev.shiftKey ?
this.tableObj.activeCell.cellIndex+1 :
row.children.length-1
var cell = row.children[newIndex]
if (cell)
this.tableObj.focusCell(cell)
}
Navigation.prototype.navigateNext = function(ev) {
if (!this.tableObj.activeCell)
return
if (this.tableObj.activeCellProcessor && !this.tableObj.activeCellProcessor.keyNavigationAllowed(ev, 'tab'))
return
var row = this.tableObj.activeCell.parentNode,
cellCount = row.children.length,
cellIndex = this.tableObj.activeCell.cellIndex
if (!ev.shiftKey) {
if (cellIndex < cellCount-1)
this.tableObj.focusCell(row.children[cellIndex+1])
else {
if (row.nextElementSibling)
this.tableObj.focusCell(row.nextElementSibling.children[0])
}
} else {
if (cellIndex > 0)
this.tableObj.focusCell(row.children[cellIndex-1])
else {
if (row.previousElementSibling)
this.tableObj.focusCell(row.previousElementSibling.children[cellCount-1])
}
}
this.tableObj.stopEvent(ev)
}
// EVENT HANDLERS
// ============================
Navigation.prototype.onKeydown = function(ev) {
// Handle keyboard navigation events.
if (ev.keyCode == 40)
return this.navigateDown(ev)
else if (ev.keyCode == 38)
return this.navigateUp(ev)
else if (ev.keyCode == 37)
return this.navigateLeft(ev)
if (ev.keyCode == 39)
return this.navigateRight(ev)
if (ev.keyCode == 9)
return this.navigateNext(ev)
}
$.oc.table.helper.navigation = Navigation;
}(window.jQuery);

View File

@ -52,14 +52,16 @@
// Event handlers
this.clickHandler = this.onClick.bind(this)
this.keydownHandler = this.onKeydown.bind(this)
// Navigation helper
this.navigation = null
//
// Initialization
//
this.init()
};
}
// INTERNAL METHODS
// ============================
@ -71,6 +73,9 @@
// Create cell processors
this.initCellProcessors()
// Initialize helpers
this.navigation = new $.oc.table.helper.navigation(this)
// Create header and data tables
this.buildTables()
@ -109,12 +114,12 @@
Table.prototype.registerHandlers = function() {
this.el.addEventListener('click', this.clickHandler)
this.el.addEventListener('keydown', this.keydownHandler)
}
Table.prototype.unregisterHandlers = function() {
this.el.removeEventListener('click', this.clickHandler);
this.el.removeEventListener('keydown', this.keydownHandler);
this.clickHandler = null
}
Table.prototype.initCellProcessors = function() {
@ -293,114 +298,6 @@
cellElement.parentNode.setAttribute('data-dirty', 1)
}
Table.prototype.navigateDown = function(ev) {
if (!this.activeCell)
return
if (this.activeCellProcessor && !this.activeCellProcessor.keyNavigationAllowed(ev, 'down'))
return
var row = this.activeCell.parentNode,
newRow = !ev.shiftKey ?
row.nextElementSibling :
row.parentNode.children[row.parentNode.children.length - 1]
if (!newRow)
return
var cell = newRow.children[this.activeCell.cellIndex]
if (cell)
this.focusCell(cell)
}
Table.prototype.navigateUp = function(ev) {
if (!this.activeCell)
return
if (this.activeCellProcessor && !this.activeCellProcessor.keyNavigationAllowed(ev, 'up'))
return
var row = this.activeCell.parentNode,
newRow = !ev.shiftKey ?
row.previousElementSibling :
row.parentNode.children[0]
if (!newRow)
return
var cell = newRow.children[this.activeCell.cellIndex]
if (cell)
this.focusCell(cell)
}
Table.prototype.navigateLeft = function(ev) {
if (!this.activeCell)
return
if (this.activeCellProcessor && !this.activeCellProcessor.keyNavigationAllowed(ev, 'left'))
return
var row = this.activeCell.parentNode,
newIndex = !ev.shiftKey ?
this.activeCell.cellIndex-1 :
0
var cell = row.children[newIndex]
if (cell)
this.focusCell(cell)
}
Table.prototype.navigateRight = function(ev) {
if (!this.activeCell)
return
if (this.activeCellProcessor && !this.activeCellProcessor.keyNavigationAllowed(ev, 'right'))
return
var row = this.activeCell.parentNode,
newIndex = !ev.shiftKey ?
this.activeCell.cellIndex+1 :
row.children.length-1
var cell = row.children[newIndex]
if (cell)
this.focusCell(cell)
}
Table.prototype.navigateNext = function(ev) {
if (!this.activeCell)
return
if (this.activeCellProcessor && !this.activeCellProcessor.keyNavigationAllowed(ev, 'tab'))
return
var row = this.activeCell.parentNode,
cellCount = row.children.length,
cellIndex = this.activeCell.cellIndex
if (!ev.shiftKey) {
if (cellIndex < cellCount-1)
this.focusCell(row.children[cellIndex+1])
else {
if (row.nextElementSibling)
this.focusCell(row.nextElementSibling.children[0])
}
} else {
if (cellIndex > 0)
this.focusCell(row.children[cellIndex-1])
else {
if (row.previousElementSibling)
this.focusCell(row.previousElementSibling.children[cellCount-1])
}
}
this.stopEvent(ev)
}
// EVENT HANDLERS
// ============================
@ -416,24 +313,6 @@
this.focusCell(target)
}
Table.prototype.onKeydown = function(ev) {
// Handle keyboard navigation events.
// Cell processor editors should stop the keydown event
// bubbling if they handle the up/down/left/right
// keys by themselves.
if (ev.keyCode == 40)
return this.navigateDown(ev)
else if (ev.keyCode == 38)
return this.navigateUp(ev)
else if (ev.keyCode == 37)
return this.navigateLeft(ev)
if (ev.keyCode == 39)
return this.navigateRight(ev)
if (ev.keyCode == 9)
return this.navigateNext(ev)
}
// PUBLIC METHODS
// ============================
@ -451,6 +330,10 @@
// Dispose cell processors
this.disposeCellProcessors()
// Dispose helpers and remove references
this.navigation.dispose()
this.navigation = null
// Delete the reference to the control HTML element.
// The script doesn't remove any DOM elements themselves.
// If it's needed it should be done by the outer script,

View File

@ -157,15 +157,19 @@
if (document.selection) {
var range = input.createTextRange()
range.collapse(true)
range.moveStart("character", position)
range.moveEnd("character", 0)
range.select()
setTimeout(function(){
range.collapse(true)
range.moveStart("character", position)
range.moveEnd("character", 0)
range.select()
}, 0)
}
if (input.selectionStart !== undefined) {
input.selectionStart = position
input.selectionEnd = position
setTimeout(function(){
input.selectionStart = position
input.selectionEnd = position
}, 0)
}
return 0

View File

@ -302,4 +302,4 @@
?>
<div data-control="table" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>"></div>
<div data-control="table" data-columns="<?= e(json_encode($columns)) ?>" data-data="<?= e(json_encode($data)) ?>" data-records-per-page="10"></div>