Move plugins out, fix to checkbox

This commit is contained in:
Sam Georges 2014-06-21 12:34:02 +10:00
parent 7ea793170f
commit 0833cfcbba
8 changed files with 1233 additions and 1122 deletions

View File

@ -0,0 +1,172 @@
(function (Handsontable) {
function HandsontableAutoColumnSize() {
var plugin = this
, sampleCount = 5; //number of samples to take of each value length
this.beforeInit = function () {
var instance = this;
instance.autoColumnWidths = [];
if (instance.getSettings().autoColumnSize !== false) {
if (!instance.autoColumnSizeTmp) {
instance.autoColumnSizeTmp = {
table: null,
tableStyle: null,
theadTh: null,
tbody: null,
container: null,
containerStyle: null,
determineBeforeNextRender: true
};
}
instance.addHook('beforeRender', htAutoColumnSize.determineIfChanged);
instance.addHook('afterGetColWidth', htAutoColumnSize.getColWidth);
instance.addHook('afterDestroy', htAutoColumnSize.afterDestroy);
instance.determineColumnWidth = plugin.determineColumnWidth;
} else {
instance.removeHook('beforeRender', htAutoColumnSize.determineIfChanged);
instance.removeHook('afterGetColWidth', htAutoColumnSize.getColWidth);
instance.removeHook('afterDestroy', htAutoColumnSize.afterDestroy);
delete instance.determineColumnWidth;
plugin.afterDestroy.call(instance);
}
};
this.determineIfChanged = function (force) {
if (force) {
htAutoColumnSize.determineColumnsWidth.apply(this, arguments);
}
};
this.determineColumnWidth = function (col) {
var instance = this
, tmp = instance.autoColumnSizeTmp;
if (!tmp.container) {
createTmpContainer.call(tmp, instance);
}
tmp.container.className = instance.rootElement[0].className + ' htAutoColumnSize';
tmp.table.className = instance.$table[0].className;
var rows = instance.countRows();
var samples = {};
var maxLen = 0;
for (var r = 0; r < rows; r++) {
var value = Handsontable.helper.stringify(instance.getDataAtCell(r, col));
var len = value.length;
if (len > maxLen) {
maxLen = len;
}
if (!samples[len]) {
samples[len] = {
needed: sampleCount,
strings: []
};
}
if (samples[len].needed) {
samples[len].strings.push({value: value, row: r});
samples[len].needed--;
}
}
var settings = instance.getSettings();
if (settings.colHeaders) {
instance.view.appendColHeader(col, tmp.theadTh); //TH innerHTML
}
instance.view.wt.wtDom.empty(tmp.tbody);
var cellProperties = instance.getCellMeta(0, col);
var renderer = Handsontable.helper.getCellMethod('renderer', cellProperties.renderer);
for (var i in samples) {
if (samples.hasOwnProperty(i)) {
for (var j = 0, jlen = samples[i].strings.length; j < jlen; j++) {
var tr = document.createElement('tr');
var td = document.createElement('td');
renderer(instance, td, samples[i].strings[j].row, col, instance.colToProp(col), samples[i].strings[j].value, cellProperties);
r++;
tr.appendChild(td);
tmp.tbody.appendChild(tr);
}
}
}
var parent = instance.rootElement[0].parentNode;
parent.appendChild(tmp.container);
var width = instance.view.wt.wtDom.outerWidth(tmp.table);
parent.removeChild(tmp.container);
var maxWidth = instance.view.wt.wtViewport.getViewportWidth() - 2; //2 is some overhead for cell border
if (width > maxWidth) {
width = maxWidth;
}
return width;
};
this.determineColumnsWidth = function () {
var instance = this;
var settings = this.getSettings();
if (settings.autoColumnSize || !settings.colWidths) {
var cols = this.countCols();
for (var c = 0; c < cols; c++) {
if (!instance._getColWidthFromSettings(c)) {
this.autoColumnWidths[c] = plugin.determineColumnWidth.call(instance, c);
}
}
}
};
this.getColWidth = function (col, response) {
if (this.autoColumnWidths[col] && this.autoColumnWidths[col] > response.width) {
response.width = this.autoColumnWidths[col];
}
};
this.afterDestroy = function () {
var instance = this;
if (instance.autoColumnSizeTmp && instance.autoColumnSizeTmp.container && instance.autoColumnSizeTmp.container.parentNode) {
instance.autoColumnSizeTmp.container.parentNode.removeChild(instance.autoColumnSizeTmp.container);
}
};
function createTmpContainer(instance) {
var d = document
, tmp = this;
tmp.table = d.createElement('table');
tmp.theadTh = d.createElement('th');
tmp.table.appendChild(d.createElement('thead')).appendChild(d.createElement('tr')).appendChild(tmp.theadTh);
tmp.tableStyle = tmp.table.style;
tmp.tableStyle.tableLayout = 'auto';
tmp.tableStyle.width = 'auto';
tmp.tbody = d.createElement('tbody');
tmp.table.appendChild(tmp.tbody);
tmp.container = d.createElement('div');
tmp.container.className = instance.rootElement[0].className + ' hidden';
tmp.containerStyle = tmp.container.style;
tmp.container.appendChild(tmp.table);
}
}
var htAutoColumnSize = new HandsontableAutoColumnSize();
Handsontable.PluginHooks.add('beforeInit', htAutoColumnSize.beforeInit);
Handsontable.PluginHooks.add('afterUpdateSettings', htAutoColumnSize.beforeInit);
})(Handsontable);

View File

@ -0,0 +1,187 @@
/**
* Column move plugin
*/
function HandsontableManualColumnMove() {
var instance
, pressed
, startCol
, endCol
, startX
, startOffset;
var ghost = document.createElement('DIV')
, ghostStyle = ghost.style;
ghost.className = 'ghost';
ghostStyle.position = 'absolute';
ghostStyle.top = '25px';
ghostStyle.left = 0;
ghostStyle.width = '10px';
ghostStyle.height = '10px';
ghostStyle.backgroundColor = '#CCC';
ghostStyle.opacity = 0.7;
var saveManualColumnPositions = function () {
var instance = this;
instance.PluginHooks.run('persistentStateSave', 'manualColumnPositions', instance.manualColumnPositions);
};
var loadManualColumnPositions = function () {
var instance = this;
var storedState = {};
instance.PluginHooks.run('persistentStateLoad', 'manualColumnPositions', storedState);
return storedState.value;
};
var bindMoveColEvents = function () {
var instance = this;
instance.rootElement.on('mousemove.manualColumnMove', function (e) {
if (pressed) {
ghostStyle.left = startOffset + e.pageX - startX + 6 + 'px';
if (ghostStyle.display === 'none') {
ghostStyle.display = 'block';
}
}
});
instance.rootElement.on('mouseup.manualColumnMove', function () {
if (pressed) {
if (startCol < endCol) {
endCol--;
}
if (instance.getSettings().rowHeaders) {
startCol--;
endCol--;
}
instance.manualColumnPositions.splice(endCol, 0, instance.manualColumnPositions.splice(startCol, 1)[0]);
$('.manualColumnMover.active').removeClass('active');
pressed = false;
instance.forceFullRender = true;
instance.view.render(); //updates all
ghostStyle.display = 'none';
saveManualColumnPositions.call(instance);
instance.PluginHooks.run('afterColumnMove', startCol, endCol);
}
});
instance.rootElement.on('mousedown.manualColumnMove', '.manualColumnMover', function (e) {
var mover = e.currentTarget;
var TH = instance.view.wt.wtDom.closest(mover, 'TH');
startCol = instance.view.wt.wtDom.index(TH) + instance.colOffset();
endCol = startCol;
pressed = true;
startX = e.pageX;
var TABLE = instance.$table[0];
TABLE.parentNode.appendChild(ghost);
ghostStyle.width = instance.view.wt.wtDom.outerWidth(TH) + 'px';
ghostStyle.height = instance.view.wt.wtDom.outerHeight(TABLE) + 'px';
startOffset = parseInt(instance.view.wt.wtDom.offset(TH).left - instance.view.wt.wtDom.offset(TABLE).left, 10);
ghostStyle.left = startOffset + 6 + 'px';
});
instance.rootElement.on('mouseenter.manualColumnMove', 'td, th', function () {
if (pressed) {
var active = instance.view.THEAD.querySelector('.manualColumnMover.active');
if (active) {
instance.view.wt.wtDom.removeClass(active, 'active');
}
endCol = instance.view.wt.wtDom.index(this) + instance.colOffset();
var THs = instance.view.THEAD.querySelectorAll('th');
var mover = THs[endCol].querySelector('.manualColumnMover');
instance.view.wt.wtDom.addClass(mover, 'active');
}
});
instance.addHook('afterDestroy', unbindMoveColEvents);
};
var unbindMoveColEvents = function(){
var instance = this;
instance.rootElement.off('mouseup.manualColumnMove');
instance.rootElement.off('mousemove.manualColumnMove');
instance.rootElement.off('mousedown.manualColumnMove');
instance.rootElement.off('mouseenter.manualColumnMove');
}
this.beforeInit = function () {
this.manualColumnPositions = [];
};
this.init = function (source) {
var instance = this;
var manualColMoveEnabled = !!(this.getSettings().manualColumnMove);
if (manualColMoveEnabled) {
var initialManualColumnPositions = this.getSettings().manualColumnMove;
var loadedManualColumnPositions = loadManualColumnPositions.call(instance);
if (typeof loadedManualColumnPositions != 'undefined') {
this.manualColumnPositions = loadedManualColumnPositions;
} else if (initialManualColumnPositions instanceof Array) {
this.manualColumnPositions = initialManualColumnPositions;
} else {
this.manualColumnPositions = [];
}
instance.forceFullRender = true;
if (source == 'afterInit') {
bindMoveColEvents.call(this);
if (this.manualColumnPositions.length > 0) {
this.forceFullRender = true;
this.render();
}
}
} else {
unbindMoveColEvents.call(this);
this.manualColumnPositions = [];
}
};
this.modifyCol = function (col) {
//TODO test performance: http://jsperf.com/object-wrapper-vs-primitive/2
if (this.getSettings().manualColumnMove) {
if (typeof this.manualColumnPositions[col] === 'undefined') {
this.manualColumnPositions[col] = col;
}
return this.manualColumnPositions[col];
}
return col;
};
this.getColHeader = function (col, TH) {
if (this.getSettings().manualColumnMove) {
var DIV = document.createElement('DIV');
DIV.className = 'manualColumnMover';
TH.firstChild.appendChild(DIV);
}
};
}
var htManualColumnMove = new HandsontableManualColumnMove();
Handsontable.PluginHooks.add('beforeInit', htManualColumnMove.beforeInit);
Handsontable.PluginHooks.add('afterInit', function () {
htManualColumnMove.init.call(this, 'afterInit')
});
Handsontable.PluginHooks.add('afterUpdateSettings', function () {
htManualColumnMove.init.call(this, 'afterUpdateSettings')
});
Handsontable.PluginHooks.add('afterGetColHeader', htManualColumnMove.getColHeader);
Handsontable.PluginHooks.add('modifyCol', htManualColumnMove.modifyCol);

View File

@ -0,0 +1,198 @@
/**
* Column resize plugin
*/
function HandsontableManualColumnResize() {
var pressed
, currentTH
, currentCol
, currentWidth
, instance
, newSize
, startX
, startWidth
, startOffset
, resizer = document.createElement('DIV')
, handle = document.createElement('DIV')
, line = document.createElement('DIV')
, lineStyle = line.style;
resizer.className = 'manualColumnResizer';
handle.className = 'manualColumnResizerHandle';
resizer.appendChild(handle);
line.className = 'manualColumnResizerLine';
resizer.appendChild(line);
var $document = $(document);
$document.mousemove(function (e) {
if (pressed) {
currentWidth = startWidth + (e.pageX - startX);
newSize = setManualSize(currentCol, currentWidth); //save col width
resizer.style.left = startOffset + currentWidth + 'px';
}
});
$document.mouseup(function () {
if (pressed) {
instance.view.wt.wtDom.removeClass(resizer, 'active');
pressed = false;
if(newSize != startWidth){
instance.forceFullRender = true;
instance.view.render(); //updates all
saveManualColumnWidths.call(instance);
instance.PluginHooks.run('afterColumnResize', currentCol, newSize);
}
refreshResizerPosition.call(instance, currentTH);
}
});
var saveManualColumnWidths = function () {
var instance = this;
instance.PluginHooks.run('persistentStateSave', 'manualColumnWidths', instance.manualColumnWidths);
};
var loadManualColumnWidths = function () {
var instance = this;
var storedState = {};
instance.PluginHooks.run('persistentStateLoad', 'manualColumnWidths', storedState);
return storedState.value;
};
function refreshResizerPosition(TH) {
instance = this;
currentTH = TH;
var col = this.view.wt.wtTable.getCoords(TH)[1]; //getCoords returns array [row, col]
if (col >= 0) { //if not row header
currentCol = col;
var rootOffset = this.view.wt.wtDom.offset(this.rootElement[0]).left;
var thOffset = this.view.wt.wtDom.offset(TH).left;
startOffset = (thOffset - rootOffset) - 6;
var thStyle = this.view.wt.wtDom.getComputedStyle(TH);
resizer.style.left = startOffset + parseInt(this.view.wt.wtDom.outerWidth(TH), 10) + 'px';
this.rootElement[0].appendChild(resizer);
}
}
function getColumnWidth(TH) {
var instance = this;
var thOffset = instance.view.wt.wtDom.offset(TH).left - instance.view.wt.wtDom.offset(TH).left;
var rootOffset = instance.view.wt.wtDom.offset(instance.rootElement[0]).left;
var col = instance.view.wt.wtTable.getCoords(TH)[1]; //getCoords returns array [row, col]
var thWidth = instance.getColWidth(col);
var maxWidth = instance.view.maximumVisibleElementWidth(thOffset - rootOffset);
return Math.min(thWidth, maxWidth);
}
function refreshLinePosition() {
var instance = this;
var thBorderWidth = 2 * parseInt(this.view.wt.wtDom.getComputedStyle(currentTH).borderWidth, 10);
startWidth = parseInt(this.view.wt.wtDom.outerWidth(currentTH), 10);
instance.view.wt.wtDom.addClass(resizer, 'active');
lineStyle.height = instance.view.wt.wtDom.outerHeight(instance.$table[0]) + 'px';
pressed = instance;
}
var bindManualColumnWidthEvents = function () {
var instance = this;
var dblclick = 0;
var autoresizeTimeout = null;
this.rootElement.on('mouseenter.handsontable', 'th', function (e) {
if (!pressed) {
refreshResizerPosition.call(instance, e.currentTarget);
}
});
this.rootElement.on('mousedown.handsontable', '.manualColumnResizer', function () {
if (autoresizeTimeout == null) {
autoresizeTimeout = setTimeout(function () {
if (dblclick >= 2) {
newSize = instance.determineColumnWidth.call(instance, currentCol);
setManualSize(currentCol, newSize);
instance.forceFullRender = true;
instance.view.render(); //updates all
instance.PluginHooks.run('afterColumnResize', currentCol, newSize);
}
dblclick = 0;
autoresizeTimeout = null;
}, 500);
}
dblclick++;
});
this.rootElement.on('mousedown.handsontable', '.manualColumnResizer', function (e) {
startX = e.pageX;
refreshLinePosition.call(instance);
newSize = startWidth;
});
};
this.beforeInit = function () {
this.manualColumnWidths = [];
};
this.init = function (source) {
var instance = this;
var manualColumnWidthEnabled = !!(this.getSettings().manualColumnResize);
if (manualColumnWidthEnabled) {
var initialColumnWidths = this.getSettings().manualColumnResize;
var loadedManualColumnWidths = loadManualColumnWidths.call(instance);
if (typeof loadedManualColumnWidths != 'undefined') {
this.manualColumnWidths = loadedManualColumnWidths;
} else if (initialColumnWidths instanceof Array) {
this.manualColumnWidths = initialColumnWidths;
} else {
this.manualColumnWidths = [];
}
if (source == 'afterInit') {
bindManualColumnWidthEvents.call(this);
instance.forceFullRender = true;
instance.render();
}
}
};
var setManualSize = function (col, width) {
width = Math.max(width, 20);
/**
* We need to run col through modifyCol hook, in case the order of displayed columns is different than the order
* in data source. For instance, this order can be modified by manualColumnMove plugin.
*/
col = instance.PluginHooks.execute('modifyCol', col);
instance.manualColumnWidths[col] = width;
return width;
};
this.getColWidth = function (col, response) {
if (this.getSettings().manualColumnResize && this.manualColumnWidths[col]) {
response.width = this.manualColumnWidths[col];
}
};
}
var htManualColumnResize = new HandsontableManualColumnResize();
Handsontable.PluginHooks.add('beforeInit', htManualColumnResize.beforeInit);
Handsontable.PluginHooks.add('afterInit', function () {
htManualColumnResize.init.call(this, 'afterInit')
});
Handsontable.PluginHooks.add('afterUpdateSettings', function () {
htManualColumnResize.init.call(this, 'afterUpdateSettings')
});
Handsontable.PluginHooks.add('afterGetColWidth', htManualColumnResize.getColWidth);

View File

@ -0,0 +1,325 @@
/**
* This plugin sorts the view by a column (but does not sort the data source!)
* @constructor
*/
function HandsontableColumnSorting() {
var plugin = this;
this.init = function (source) {
var instance = this;
var sortingSettings = instance.getSettings().columnSorting;
var sortingColumn, sortingOrder;
instance.sortingEnabled = !!(sortingSettings);
if (instance.sortingEnabled) {
instance.sortIndex = [];
var loadedSortingState = loadSortingState.call(instance);
if (typeof loadedSortingState != 'undefined') {
sortingColumn = loadedSortingState.sortColumn;
sortingOrder = loadedSortingState.sortOrder;
} else {
sortingColumn = sortingSettings.column;
sortingOrder = sortingSettings.sortOrder;
}
plugin.sortByColumn.call(instance, sortingColumn, sortingOrder);
instance.sort = function(){
var args = Array.prototype.slice.call(arguments);
return plugin.sortByColumn.apply(instance, args)
}
if (typeof instance.getSettings().observeChanges == 'undefined'){
enableObserveChangesPlugin.call(instance);
}
if (source == 'afterInit') {
bindColumnSortingAfterClick.call(instance);
instance.addHook('afterCreateRow', plugin.afterCreateRow);
instance.addHook('afterRemoveRow', plugin.afterRemoveRow);
}
} else {
delete instance.sort;
}
};
this.setSortingColumn = function (col, order) {
var instance = this;
if (typeof col == 'undefined') {
delete instance.sortColumn;
delete instance.sortOrder;
return;
} else if (instance.sortColumn === col && typeof order == 'undefined') {
instance.sortOrder = !instance.sortOrder;
} else {
instance.sortOrder = typeof order != 'undefined' ? order : true;
}
instance.sortColumn = col;
};
this.sortByColumn = function (col, order) {
var instance = this;
plugin.setSortingColumn.call(instance, col, order);
instance.PluginHooks.run('beforeColumnSort', instance.sortColumn, instance.sortOrder);
plugin.sort.call(instance);
instance.render();
saveSortingState.call(instance);
instance.PluginHooks.run('afterColumnSort', instance.sortColumn, instance.sortOrder);
};
var saveSortingState = function () {
var instance = this;
var sortingState = {};
if (typeof instance.sortColumn != 'undefined') {
sortingState.sortColumn = instance.sortColumn;
}
if (typeof instance.sortOrder != 'undefined') {
sortingState.sortOrder = instance.sortOrder;
}
if (sortingState.hasOwnProperty('sortColumn') || sortingState.hasOwnProperty('sortOrder')) {
instance.PluginHooks.run('persistentStateSave', 'columnSorting', sortingState);
}
};
var loadSortingState = function () {
var instance = this;
var storedState = {};
instance.PluginHooks.run('persistentStateLoad', 'columnSorting', storedState);
return storedState.value;
};
var bindColumnSortingAfterClick = function () {
var instance = this;
instance.rootElement.on('click.handsontable', '.columnSorting', function (e) {
if (instance.view.wt.wtDom.hasClass(e.target, 'columnSorting')) {
var col = getColumn(e.target);
plugin.sortByColumn.call(instance, col);
}
});
function countRowHeaders() {
var THs = instance.view.TBODY.querySelector('tr').querySelectorAll('th');
return THs.length;
}
function getColumn(target) {
var TH = instance.view.wt.wtDom.closest(target, 'TH');
return instance.view.wt.wtDom.index(TH) - countRowHeaders();
}
};
function enableObserveChangesPlugin () {
var instance = this;
instance.registerTimeout('enableObserveChanges', function(){
instance.updateSettings({
observeChanges: true
});
}, 0);
}
function defaultSort(sortOrder) {
return function (a, b) {
if (a[1] === b[1]) {
return 0;
}
if (a[1] === null) {
return 1;
}
if (b[1] === null) {
return -1;
}
if (a[1] < b[1]) return sortOrder ? -1 : 1;
if (a[1] > b[1]) return sortOrder ? 1 : -1;
return 0;
}
}
function dateSort(sortOrder) {
return function (a, b) {
if (a[1] === b[1]) {
return 0;
}
if (a[1] === null) {
return 1;
}
if (b[1] === null) {
return -1;
}
var aDate = new Date(a[1]);
var bDate = new Date(b[1]);
if (aDate < bDate) return sortOrder ? -1 : 1;
if (aDate > bDate) return sortOrder ? 1 : -1;
return 0;
}
}
this.sort = function () {
var instance = this;
if (typeof instance.sortOrder == 'undefined') {
return;
}
instance.sortingEnabled = false; //this is required by translateRow plugin hook
instance.sortIndex.length = 0;
var colOffset = this.colOffset();
for (var i = 0, ilen = this.countRows() - instance.getSettings()['minSpareRows']; i < ilen; i++) {
this.sortIndex.push([i, instance.getDataAtCell(i, this.sortColumn + colOffset)]);
}
var colMeta = instance.getCellMeta(0, instance.sortColumn);
var sortFunction;
switch (colMeta.type) {
case 'date':
sortFunction = dateSort;
break;
default:
sortFunction = defaultSort;
}
this.sortIndex.sort(sortFunction(instance.sortOrder));
//Append spareRows
for(var i = this.sortIndex.length; i < instance.countRows(); i++){
this.sortIndex.push([i, instance.getDataAtCell(i, this.sortColumn + colOffset)]);
}
instance.sortingEnabled = true; //this is required by translateRow plugin hook
};
this.translateRow = function (row) {
var instance = this;
if (instance.sortingEnabled && instance.sortIndex && instance.sortIndex.length) {
return instance.sortIndex[row][0];
}
return row;
};
this.onBeforeGetSet = function (getVars) {
var instance = this;
getVars.row = plugin.translateRow.call(instance, getVars.row);
};
this.untranslateRow = function (row) {
if (sortingEnabled && this.sortIndex && this.sortIndex.length) {
for (var i = 0; i < this.sortIndex.length; i++) {
if (this.sortIndex[i][0] == row) {
return i;
}
}
}
};
this.getColHeader = function (col, TH) {
if (this.getSettings().columnSorting) {
this.view.wt.wtDom.addClass(TH.querySelector('.colHeader'), 'columnSorting');
}
};
function isSorted(instance){
return typeof instance.sortColumn != 'undefined';
}
this.afterCreateRow = function(index, amount){
var instance = this;
if(!isSorted(instance)){
return;
}
instance.sortIndex.splice(index, 0, [index, instance.getData()[index][this.sortColumn + instance.colOffset()]]);
for(var i = 0; i < instance.sortIndex.length; i++){
if(i == index) continue;
if (instance.sortIndex[i][0] >= index){
instance.sortIndex[i][0] += 1;
}
}
saveSortingState.call(instance);
};
this.afterRemoveRow = function(index, amount){
var instance = this;
if(!isSorted(instance)){
return;
}
instance.sortIndex.splice(index, amount);
for(var i = 0; i < instance.sortIndex.length; i++){
if (instance.sortIndex[i][0] > index){
instance.sortIndex[i][0] -= amount;
}
}
saveSortingState.call(instance);
};
this.afterChangeSort = function (changes/*, source*/) {
var instance = this;
var sortColumnChanged = false;
var selection = {};
if (!changes) {
return;
}
for (var i = 0; i < changes.length; i++) {
if (changes[i][1] == instance.sortColumn) {
sortColumnChanged = true;
selection.row = plugin.translateRow.call(instance, changes[i][0]);
selection.col = changes[i][1];
break;
}
}
if (sortColumnChanged) {
setTimeout(function () {
plugin.sort.call(instance);
instance.render();
instance.selectCell(plugin.untranslateRow.call(instance, selection.row), selection.col);
}, 0);
}
};
}
var htSortColumn = new HandsontableColumnSorting();
Handsontable.PluginHooks.add('afterInit', function () {
htSortColumn.init.call(this, 'afterInit')
});
Handsontable.PluginHooks.add('afterUpdateSettings', function () {
htSortColumn.init.call(this, 'afterUpdateSettings')
});
Handsontable.PluginHooks.add('beforeGet', htSortColumn.onBeforeGetSet);
Handsontable.PluginHooks.add('beforeSet', htSortColumn.onBeforeGetSet);
Handsontable.PluginHooks.add('afterGetColHeader', htSortColumn.getColHeader);

View File

@ -312,3 +312,32 @@
width: 1px;
height: 1px;
}
/**
* Handsontable RemoveRow extension. See `demo/buttons.html` for example usage
*/
.handsontable.htRemoveRow th.htRemoveRow {
text-align: center;
}
.handsontable.htRemoveRow th.htRemoveRow .btn {
background-color: #BBB;
border-radius: 9px;
padding: 0 6px 0 6px;
color: #FFF;
cursor: pointer;
font-size: 11px;
font-weight: bold;
display: none;
margin: 0 auto;
width: 10px;
}
.handsontable.htRemoveRow th.htRemoveRow .btn:hover {
background-color: #777;
}

View File

@ -0,0 +1,82 @@
(function (Handsontable, $) {
"use strict";
/**
* Handsontable RemoveRow extension. See `demo/buttons.html` for example usage
* See `.../test/jasmine/spec/extensions/removeRowSpec.js` for tests
*/
function init() {
var instance = this;
var pluginEnabled = !!(instance.getSettings().removeRowPlugin);
if (pluginEnabled) {
bindMouseEvents();
instance.rootElement.addClass('htRemoveRow');
} else {
unbindMouseEvents();
instance.rootElement.removeClass('htRemoveRow');
}
function bindMouseEvents() {
instance.rootElement.on('mouseover.removeRow', 'tbody th, tbody td', function () {
getButton(this).show();
});
instance.rootElement.on('mouseout.removeRow', 'tbody th, tbody td', function () {
getButton(this).hide();
});
}
function unbindMouseEvents() {
instance.rootElement.off('mouseover.removeRow');
instance.rootElement.off('mouseout.removeRow');
}
function getButton(td) {
return $(td).parent('tr').find('th.htRemoveRow').eq(0).find('.btn');
}
}
Handsontable.PluginHooks.add('beforeInitWalkontable', function (walkontableConfig) {
var instance = this;
/**
* rowHeaders is a function, so to alter the actual value we need to alter the result returned by this function
*/
var baseRowHeaders = walkontableConfig.rowHeaders;
walkontableConfig.rowHeaders = function () {
var pluginEnabled = Boolean(instance.getSettings().removeRowPlugin);
var newRowHeader = function (row, elem) {
var child
, div;
while (child = elem.lastChild) {
elem.removeChild(child);
}
elem.className = 'htNoFrame htRemoveRow';
if (row > -1) {
div = document.createElement('div');
div.className = 'btn';
div.appendChild(document.createTextNode('x'));
elem.appendChild(div);
$(div).on('mouseup', function () {
instance.alter("remove_row", row);
});
}
};
return pluginEnabled ? Array.prototype.concat.call([], newRowHeader, baseRowHeaders()) : baseRowHeaders();
};
});
Handsontable.PluginHooks.add('beforeInit', function () {
init.call(this)
});
Handsontable.PluginHooks.add('afterUpdateSettings', function () {
init.call(this)
});
})(Handsontable, jQuery);

View File

@ -0,0 +1,196 @@
/**
* Row move plugin
*/
function HandsontableManualRowMove() {
var pressed,
startRow,
endRow,
startY,
startOffest;
var ghost = document.createElement('DIV'),
ghostStyle = ghost.style;
ghost.className = 'ghost';
ghostStyle.position = 'absolute';
ghostStyle.top = '25px';
ghostStyle.left = '50px';
ghostStyle.width = '10px';
ghostStyle.height = '10px';
ghostStyle.backgroundColor = '#CCC';
ghostStyle.opacity = 0.7;
var saveManualRowPostions = function () {
var instance = this;
instance.PluginHooks.run('persistentStateSave', 'manualRowPostions', instance.manualRowPositions);
};
var loadManualRowPositions = function () {
var instance = this,
storedState = {};
instance.PluginHooks.run('persistentStateLoad', 'manualRowPositions', storedState);
return storedState.value;
};
var bindMoveRowEvents = function () {
var instance = this;
instance.rootElement.on('mousemove.manualRowMove', function (e) {
if (pressed) {
ghostStyle.top = startOffest + e.pageY - startY + 'px';
if (ghostStyle.display === 'none') {
ghostStyle.display = 'block';
}
}
});
instance.rootElement.on('mouseup.manualRowMove', function () {
if (pressed) {
if (startRow < endRow) {
endRow--;
}
if (instance.getSettings().colHeaders) {
startRow--;
endRow--;
}
instance.manualRowPositions.splice(endRow, 0, instance.manualRowPositions.splice(startRow, 1)[0]);
$('.manualRowMover.active').removeClass('active');
pressed = false;
instance.forceFullRender = true;
instance.view.render();
ghostStyle.display = 'none';
saveManualRowPostions.call(instance);
instance.PluginHooks.run('afterRowMove', startRow, endRow);
}
});
instance.rootElement.on('mousedown.manualRowMove', '.manualRowMover', function (e) {
var mover = e.currentTarget,
TH = instance.view.wt.wtDom.closest(mover, 'TH'),
TR = TH.parentNode;
startRow = parseInt(instance.view.wt.wtDom.index(TR), 10) + 1 + instance.rowOffset();
endRow = startRow;
pressed = true;
startY = e.pageY;
var TABLE = instance.$table[0];
TABLE.parentNode.appendChild(ghost);
ghostStyle.width = instance.view.wt.wtDom.outerWidth(TABLE) + 'px';
ghostStyle.height = instance.view.wt.wtDom.outerHeight(TH) + 'px';
startOffest = parseInt(instance.view.wt.wtDom.offset(TH).top - instance.view.wt.wtDom.offset(TABLE).top, 10);
ghostStyle.top = startOffest + 'px';
});
instance.rootElement.on('mouseenter.manualRowMove', 'table tbody th, table tbody td', function (e) {
if (pressed) {
var active = instance.view.TBODY.querySelector('.manualRowMover.active');
if (active) {
instance.view.wt.wtDom.removeClass(active, 'active');
}
var currentTarget = e.currentTarget,
TR = currentTarget.parentNode,
rowOffset = instance.rowOffset();
endRow = parseInt(instance.view.wt.wtDom.index(TR), 10) + 1 + rowOffset;
var THs = instance.view.TBODY.querySelectorAll('th'),
totalVisibleRows = instance.countVisibleRows(),
currentPosition = (endRow > totalVisibleRows ? endRow - rowOffset : endRow);
var mover = THs[currentPosition].querySelector('.manualRowMover');
instance.view.wt.wtDom.addClass(mover, 'active');
}
});
instance.addHook('afterDestroy', unbindMoveRowEvents);
};
var unbindMoveRowEvents = function () {
var instance = this;
instance.rootElement.off('mouseup.manualRowMove');
instance.rootElement.off('mousemove.manualRowMove');
instance.rootElement.off('mousedown.manualRowMove');
instance.rootElement.off('mouseenter.manualRowMove');
};
this.beforeInit = function () {
this.manualRowPositions = [];
};
this.init = function (source) {
var instance = this;
var manualRowMoveEnabled = !!(instance.getSettings().manualRowMove);
if (manualRowMoveEnabled) {
var initialManualRowPositions = instance.getSettings().manualRowMove;
var loadedManualRowPostions = loadManualRowPositions.call(instance);
if (typeof loadedManualRowPostions != 'undefined') {
this.manualRowPositions = loadedManualRowPostions;
} else if(initialManualRowPositions instanceof Array) {
this.manualRowPositions = initialManualRowPositions;
} else {
this.manualRowPositions = [];
}
instance.forceFullRender = true;
if (source === 'afterInit') {
bindMoveRowEvents.call(this);
instance.forceFullRender = true;
instance.render();
}
} else {
unbindMoveRowEvents.call(this);
instance.manualRowPositions = [];
}
};
this.modifyRow = function (row) {
var instance = this;
if (instance.getSettings().manualRowMove) {
if (typeof instance.manualRowPositions[row] === 'undefined') {
instance.manualRowPositions[row] = row;
}
return instance.manualRowPositions[row];
}
return row;
};
this.getRowHeader = function (row, TH) {
if (this.getSettings().manualRowMove) {
var DIV = document.createElement('DIV');
DIV.className = 'manualRowMover';
TH.firstChild.appendChild(DIV);
}
};
}
var htManualRowMove = new HandsontableManualRowMove();
Handsontable.PluginHooks.add('beforeInit', htManualRowMove.beforeInit);
Handsontable.PluginHooks.add('afterInit', function () {
htManualRowMove.init.call(this, 'afterInit');
});
Handsontable.PluginHooks.add('afterUpdateSettings', function () {
htManualRowMove.init.call(this, 'afterUpdateSettings');
});
Handsontable.PluginHooks.add('afterGetRowHeader', htManualRowMove.getRowHeader);
Handsontable.PluginHooks.add('modifyRow', htManualRowMove.modifyRow);