diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnautosize.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnautosize.js new file mode 100644 index 000000000..b6de77da1 --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnautosize.js @@ -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); diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnmove.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnmove.js new file mode 100644 index 000000000..1e2a438a1 --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnmove.js @@ -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); + + diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnresize.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnresize.js new file mode 100644 index 000000000..ad0ed84ee --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnresize.js @@ -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); diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnsorting.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnsorting.js new file mode 100644 index 000000000..bd8d5ea0a --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/columnsorting.js @@ -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); diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.css b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.css index 0a54d9d67..57e803d94 100644 --- a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.css +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.css @@ -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; +} \ No newline at end of file diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js index 2adae0d2a..d4c418fd9 100644 --- a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/jquery.handsontable.js @@ -3697,7 +3697,7 @@ Handsontable.CheckboxRenderer = function (instance, TD, row, col, prop, value, c })); var INPUT = $input.get(0), - CHECKBOX = $checkbox.get(0); //this is faster than createElement + CHECKBOX = $checkbox.get(0); if (value === cellProperties.checkedTemplate || value === Handsontable.helper.stringify(cellProperties.checkedTemplate)) { INPUT.checked = true; @@ -3717,11 +3717,11 @@ Handsontable.CheckboxRenderer = function (instance, TD, row, col, prop, value, c }); } else { - $input.on('mousedown', function (event) { + $checkbox.on('mousedown', function (event) { event.stopPropagation(); //otherwise can confuse cell mousedown handler }); - $input.on('mouseup', function (event) { + $checkbox.on('mouseup', function (event) { event.stopPropagation(); //otherwise can confuse cell dblclick handler }); @@ -5069,1129 +5069,51 @@ Handsontable.PluginHookClass = (function () { Handsontable.PluginHooks = new Handsontable.PluginHookClass(); -(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); - -/** - * 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); - /** * This plugin adds support for legacy features, deprecated APIs, etc. */ -/** - * Support for old autocomplete syntax - * For old syntax, see: https://github.com/warpech/jquery-handsontable/blob/8c9e701d090ea4620fe08b6a1a048672fadf6c7e/README.md#defining-autocomplete - */ -Handsontable.PluginHooks.add('beforeGetCellMeta', function (row, col, cellProperties) { - var settings = this.getSettings(), data = this.getData(), i, ilen, a; - - //isWritable - deprecated since 0.8.0 - cellProperties.isWritable = !cellProperties.readOnly; - - //autocomplete - deprecated since 0.7.1 (see CHANGELOG.md) - if (settings.autoComplete) { - for (i = 0, ilen = settings.autoComplete.length; i < ilen; i++) { - if (settings.autoComplete[i].match(row, col, data)) { - if (typeof cellProperties.type === 'undefined') { - cellProperties.type = Handsontable.AutocompleteCell; - } - else { - if (typeof cellProperties.type.renderer === 'undefined') { - cellProperties.type.renderer = Handsontable.AutocompleteCell.renderer; - } - if (typeof cellProperties.type.editor === 'undefined') { - cellProperties.type.editor = Handsontable.AutocompleteCell.editor; - } - } - for (a in settings.autoComplete[i]) { - if (settings.autoComplete[i].hasOwnProperty(a) && a !== 'match' && typeof cellProperties[i] === 'undefined') { - if (a === 'source') { - cellProperties[a] = settings.autoComplete[i][a](row, col); - } - else { - cellProperties[a] = settings.autoComplete[i][a]; - } - } - } - break; - } - } - } -}); - -/** - * 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); - -/** - * 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); - - -/** - * 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); +//@todo +// /** +// * Support for old autocomplete syntax +// * For old syntax, see: https://github.com/warpech/jquery-handsontable/blob/8c9e701d090ea4620fe08b6a1a048672fadf6c7e/README.md#defining-autocomplete +// */ +// Handsontable.PluginHooks.add('beforeGetCellMeta', function (row, col, cellProperties) { +// var settings = this.getSettings(), data = this.getData(), i, ilen, a; + +// //isWritable - deprecated since 0.8.0 +// cellProperties.isWritable = !cellProperties.readOnly; + +// //autocomplete - deprecated since 0.7.1 (see CHANGELOG.md) +// if (settings.autoComplete) { +// for (i = 0, ilen = settings.autoComplete.length; i < ilen; i++) { +// if (settings.autoComplete[i].match(row, col, data)) { +// if (typeof cellProperties.type === 'undefined') { +// cellProperties.type = Handsontable.AutocompleteCell; +// } +// else { +// if (typeof cellProperties.type.renderer === 'undefined') { +// cellProperties.type.renderer = Handsontable.AutocompleteCell.renderer; +// } +// if (typeof cellProperties.type.editor === 'undefined') { +// cellProperties.type.editor = Handsontable.AutocompleteCell.editor; +// } +// } +// for (a in settings.autoComplete[i]) { +// if (settings.autoComplete[i].hasOwnProperty(a) && a !== 'match' && typeof cellProperties[i] === 'undefined') { +// if (a === 'source') { +// cellProperties[a] = settings.autoComplete[i][a](row, col); +// } +// else { +// cellProperties[a] = settings.autoComplete[i][a]; +// } +// } +// } +// break; +// } +// } +// } +// }); (function HandsontableObserveChanges() { diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/removebutton.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/removebutton.js new file mode 100644 index 000000000..e5d4ea8c4 --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/removebutton.js @@ -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); \ No newline at end of file diff --git a/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/rowmove.js b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/rowmove.js new file mode 100644 index 000000000..5ab31ad59 --- /dev/null +++ b/modules/backend/formwidgets/datagrid/assets/vendor/handsontable/rowmove.js @@ -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);