diff --git a/index.html b/index.html index d208d6c..e937bd9 100644 --- a/index.html +++ b/index.html @@ -507,12 +507,7 @@ wrapper: document.querySelector('section'), addSerialNoColumn: true, enableClusterize: true, - data, - editing: { - getInput() { - return $('').get(0) - } - } + data }); performance.mark("ReGrid-end"); diff --git a/lib/ReGrid.js b/lib/ReGrid.js index 00b29e4..8d940ba 100644 --- a/lib/ReGrid.js +++ b/lib/ReGrid.js @@ -111,7 +111,7 @@ var _createClass = function () { function defineProperties(target, props) { for var _utils = __webpack_require__(2); -__webpack_require__(5); +__webpack_require__(3); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -136,7 +136,7 @@ var ReGrid = function () { this.addSerialNoColumn = (0, _utils.getDefault)(addSerialNoColumn, false); this.enableClusterize = (0, _utils.getDefault)(enableClusterize, false); this.enableLogs = (0, _utils.getDefault)(enableLogs, true); - this.editing = (0, _utils.getDefault)(editing, {}); + this.editing = (0, _utils.getDefault)(editing, null); if (data) { this.refresh(data); @@ -266,12 +266,9 @@ var ReGrid = function () { }, { key: 'updateCell', value: function updateCell(rowIndex, colIndex, value) { - var row = this.getRow(rowIndex); - var cell = row.find(function (cell) { - return cell.col_index === colIndex; - }); + var cell = this.getCell(rowIndex, colIndex); - cell.data = value; + cell.content = value; this.refreshCell(cell); } }, { @@ -283,8 +280,8 @@ var ReGrid = function () { }, { key: 'refreshCell', value: function refreshCell(cell) { - var selector = '.data-table-col[data-row-index="' + cell.row_index + '"][data-col-index="' + cell.col_index + '"]'; - var $cell = this.body.find(selector); + var selector = '.data-table-col[data-row-index="' + cell.rowIndex + '"][data-col-index="' + cell.colIndex + '"]'; + var $cell = this.bodyScrollable.find(selector); var $newCell = $((0, _utils.getColumnHTML)(cell)); $cell.replaceWith($newCell); @@ -402,22 +399,32 @@ var ReGrid = function () { var self = this; this.$editingCell = null; - // if (!self.events.onCellEdit) return; - this.bodyScrollable.on('dblclick', '.data-table-col', function () { self.activateEditing($(this)); }); $(document.body).on('keypress', function (e) { // enter keypress on focused cell - if (e.which === 13 && _this2.$focusedCell) { - self.activateEditing(_this2.$focusedCell); + if (e.which === 13 && _this2.$focusedCell && !_this2.$editingCell) { + _this2.log('editingCell'); + _this2.activateEditing(_this2.$focusedCell); + e.stopImmediatePropagation(); + } + }); + + $(document.body).on('keypress', function (e) { + // enter keypress on editing cell + if (e.which === 13 && _this2.$editingCell) { + _this2.log('submitCell'); + _this2.submitEditing(_this2.$editingCell); + e.stopImmediatePropagation(); } }); $(document.body).on('click', function (e) { if ($(e.target).is('.edit-cell, .edit-cell *')) return; self.bodyScrollable.find('.edit-cell').hide(); + _this2.$editingCell = null; }); } }, { @@ -441,34 +448,67 @@ var ReGrid = function () { this.$editingCell = $cell; var $editCell = $cell.find('.edit-cell').empty(); var cell = this.getCell(rowIndex, colIndex); + var editing = this.getEditingObject(colIndex, rowIndex, cell.content, $editCell); - var render = this.renderEditingInput(colIndex, cell.content, $editCell); - - if (render) { + if (editing) { + this.currentCellEditing = editing; + // initialize editing input with cell value + editing.initValue(cell.content); $editCell.show(); } - - // showing the popup is the responsibility of event handler - // self.events.onCellEdit( - // $cell.get(0), - // $editPopup, - // rowIndex, - // colIndex - // ); } }, { - key: 'renderEditingInput', - value: function renderEditingInput(colIndex, value, parent) { - if (this.editing.renderInput) { - return this.editing.renderInput(colIndex, value, parent); + key: 'getEditingObject', + value: function getEditingObject(colIndex, rowIndex, value, parent) { + if (this.editing) { + return this.editing(colIndex, rowIndex, value, parent); } - // render fallback + + // editing fallback var $input = $(''); parent.append($input); - $input.val(value); - $input.select(); - return true; + + return { + initValue: function initValue(value) { + return $input.val(value); + }, + getValue: function getValue() { + return $input.val(); + }, + setValue: function setValue(value) { + return $input.val(value); + } + }; + } + }, { + key: 'submitEditing', + value: function submitEditing($cell) { + var _this3 = this; + + var _getCellAttr3 = this.getCellAttr($cell), + rowIndex = _getCellAttr3.rowIndex, + colIndex = _getCellAttr3.colIndex; + + if ($cell) { + var editing = this.currentCellEditing; + + if (editing) { + var value = editing.getValue(); + var done = editing.setValue(value); + + if (done && done.then) { + // wait for promise then update internal state + done.then(function () { + return _this3.updateCell(rowIndex, colIndex, value); + }); + } else { + this.updateCell(rowIndex, colIndex, value); + } + } + } + + this.currentCellEditing = null; } }, { key: 'bindResizeColumn', @@ -619,7 +659,7 @@ var ReGrid = function () { }, { key: 'setColumnWidths', value: function setColumnWidths() { - var _this3 = this; + var _this4 = this; var availableWidth = this.wrapper.width(); var headerWidth = this.header.width(); @@ -632,15 +672,15 @@ var ReGrid = function () { var deltaWidth = (availableWidth - headerWidth) / this.data.columns.length; this.data.columns.map(function (col) { - var width = _this3.getColumnHeaderElement(col.colIndex).width(); + var width = _this4.getColumnHeaderElement(col.colIndex).width(); var finalWidth = width + deltaWidth - 16; - if (_this3.addSerialNoColumn && col.colIndex === 0) { + if (_this4.addSerialNoColumn && col.colIndex === 0) { return; } - _this3.setColumnHeaderWidth(col.colIndex, finalWidth); - _this3.setColumnWidth(col.colIndex, finalWidth); + _this4.setColumnHeaderWidth(col.colIndex, finalWidth); + _this4.setColumnWidth(col.colIndex, finalWidth); }); this.setBodyWidth(); } @@ -923,15 +963,13 @@ exports.default = { module.exports = exports['default']; /***/ }), -/* 3 */, -/* 4 */, -/* 5 */ +/* 3 */ /***/ (function(module, exports, __webpack_require__) { // style-loader: Adds some css to the DOM by adding a ')\n .prependTo(this.wrapper);\n }\n\n getColumn(colIndex) {\n colIndex = +colIndex;\n return this.data.columns.find(col => col.colIndex === colIndex);\n }\n\n getRow(rowIndex) {\n rowIndex = +rowIndex;\n return this.data.rows.find(row => row[0].rowIndex === rowIndex);\n }\n\n getCell(rowIndex, colIndex) {\n rowIndex = +rowIndex;\n colIndex = +colIndex;\n return this.data.rows.find(row => row[0].rowIndex === rowIndex)[colIndex];\n }\n\n getColumnHeaderElement(colIndex) {\n colIndex = +colIndex;\n if (colIndex < 0) return null;\n return this.wrapper.find(\n `.data-table-col[data-is-header][data-col-index=\"${colIndex}\"]`\n );\n }\n\n getColumnMinWidth(colIndex) {\n colIndex = +colIndex;\n return this.minWidthMap && this.minWidthMap[colIndex];\n }\n\n getCellAttr($cell) {\n return $cell.data();\n }\n\n log() {\n if (this.enableLogs) {\n console.log.apply(console, arguments);\n }\n }\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./src/regrid.js","function camelCaseToDash(str) {\n return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);\n}\n\nfunction makeDataAttributeString(props) {\n const keys = Object.keys(props);\n\n return keys\n .map((key) => {\n const _key = camelCaseToDash(key);\n const val = props[key];\n\n if (val === undefined) return '';\n return `data-${_key}=\"${val}\" `;\n })\n .join('')\n .trim();\n}\n\nfunction getEditCellHTML() {\n return `\n
\n `;\n}\n\nfunction getColumnHTML(column) {\n const { rowIndex, colIndex, isHeader } = column;\n const dataAttr = makeDataAttributeString({\n rowIndex,\n colIndex,\n isHeader\n });\n\n const editCellHTML = isHeader ? '' : getEditCellHTML();\n\n return `\n \n
\n ${column.format ? column.format(column.content) : column.content}\n \n
\n ${editCellHTML}\n \n `;\n}\n\nfunction getRowHTML(columns, props) {\n const dataAttr = makeDataAttributeString(props);\n\n return `\n \n ${columns.map(getColumnHTML).join('')}\n \n `;\n}\n\nfunction getHeaderHTML(columns) {\n const $header = `\n \n ${getRowHTML(columns, { isHeader: 1, rowIndex: -1 })}\n \n `;\n\n // columns.map(col => {\n // if (!col.width) return;\n // const $cellContent = $header.find(\n // `.data-table-col[data-col-index=\"${col.colIndex}\"] .content`\n // );\n\n // $cellContent.width(col.width);\n // });\n\n return $header;\n}\n\nfunction getBodyHTML(rows) {\n return `\n \n ${rows.map(row => getRowHTML(row, { rowIndex: row[0].rowIndex })).join('')}\n \n `;\n}\n\nfunction prepareColumn(col, i) {\n if (typeof col === 'string') {\n col = {\n content: col\n };\n }\n return Object.assign(col, {\n colIndex: i\n });\n}\n\nfunction prepareColumns(columns, props = {}) {\n const _columns = columns.map(prepareColumn);\n\n return _columns.map(col => Object.assign(col, props));\n}\n\nfunction prepareRowHeader(columns) {\n return prepareColumns(columns, {\n rowIndex: -1,\n isHeader: 1,\n format: (content) => `${content}`\n });\n}\n\nfunction prepareRow(row, i) {\n return prepareColumns(row, {\n rowIndex: i\n });\n}\n\nfunction prepareRows(rows) {\n return rows.map(prepareRow);\n}\n\nfunction getDefault(a, b) {\n return a !== undefined ? a : b;\n}\n\nfunction escapeRegExp(str) {\n // https://stackoverflow.com/a/6969486\n return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, '\\\\$&');\n}\n\nfunction getCSSString(styleMap) {\n let style = '';\n\n for (const prop in styleMap) {\n if (styleMap.hasOwnProperty(prop)) {\n style += `${prop}: ${styleMap[prop]}; `;\n }\n }\n\n return style.trim();\n}\n\nfunction getCSSRuleBlock(rule, styleMap) {\n return `${rule} { ${getCSSString(styleMap)} }`;\n}\n\nfunction namespaceSelector(selector) {\n return '.data-table ' + selector;\n}\n\nfunction buildCSSRule(rule, styleMap, cssRulesString = '') {\n // build css rules efficiently,\n // append new rule if doesnt exist,\n // update existing ones\n\n const rulePatternStr = `${escapeRegExp(rule)} {([^}]*)}`;\n const rulePattern = new RegExp(rulePatternStr, 'g');\n\n if (cssRulesString && cssRulesString.match(rulePattern)) {\n for (const property in styleMap) {\n const value = styleMap[property];\n const propPattern = new RegExp(`${escapeRegExp(property)}:([^;]*);`);\n\n cssRulesString = cssRulesString.replace(rulePattern, function (match, propertyStr) {\n if (propertyStr.match(propPattern)) {\n // property exists, replace value with new value\n propertyStr = propertyStr.replace(propPattern, (match, valueStr) => {\n return `${property}: ${value};`;\n });\n }\n propertyStr = propertyStr.trim();\n\n const replacer =\n `${rule} { ${propertyStr} }`;\n\n return replacer;\n });\n }\n\n return cssRulesString;\n }\n // no match, append new rule block\n return `${cssRulesString}${getCSSRuleBlock(rule, styleMap)}`;\n}\n\nexport default {\n getHeaderHTML,\n getBodyHTML,\n getRowHTML,\n getColumnHTML,\n getEditCellHTML,\n prepareRowHeader,\n prepareRows,\n namespaceSelector,\n getCSSString,\n buildCSSRule,\n makeDataAttributeString,\n getDefault,\n escapeRegExp\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/utils.js","// style-loader: Adds some css to the DOM by adding a ')\n .prependTo(this.wrapper);\n }\n\n getColumn(colIndex) {\n colIndex = +colIndex;\n return this.data.columns.find(col => col.colIndex === colIndex);\n }\n\n getRow(rowIndex) {\n rowIndex = +rowIndex;\n return this.data.rows.find(row => row[0].rowIndex === rowIndex);\n }\n\n getCell(rowIndex, colIndex) {\n rowIndex = +rowIndex;\n colIndex = +colIndex;\n return this.data.rows.find(row => row[0].rowIndex === rowIndex)[colIndex];\n }\n\n getColumnHeaderElement(colIndex) {\n colIndex = +colIndex;\n if (colIndex < 0) return null;\n return this.wrapper.find(\n `.data-table-col[data-is-header][data-col-index=\"${colIndex}\"]`\n );\n }\n\n getColumnMinWidth(colIndex) {\n colIndex = +colIndex;\n return this.minWidthMap && this.minWidthMap[colIndex];\n }\n\n getCellAttr($cell) {\n return $cell.data();\n }\n\n log() {\n if (this.enableLogs) {\n console.log.apply(console, arguments);\n }\n }\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./src/regrid.js","function camelCaseToDash(str) {\n return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);\n}\n\nfunction makeDataAttributeString(props) {\n const keys = Object.keys(props);\n\n return keys\n .map((key) => {\n const _key = camelCaseToDash(key);\n const val = props[key];\n\n if (val === undefined) return '';\n return `data-${_key}=\"${val}\" `;\n })\n .join('')\n .trim();\n}\n\nfunction getEditCellHTML() {\n return `\n
\n `;\n}\n\nfunction getColumnHTML(column) {\n const { rowIndex, colIndex, isHeader } = column;\n const dataAttr = makeDataAttributeString({\n rowIndex,\n colIndex,\n isHeader\n });\n\n const editCellHTML = isHeader ? '' : getEditCellHTML();\n\n return `\n \n
\n ${column.format ? column.format(column.content) : column.content}\n \n
\n ${editCellHTML}\n \n `;\n}\n\nfunction getRowHTML(columns, props) {\n const dataAttr = makeDataAttributeString(props);\n\n return `\n \n ${columns.map(getColumnHTML).join('')}\n \n `;\n}\n\nfunction getHeaderHTML(columns) {\n const $header = `\n \n ${getRowHTML(columns, { isHeader: 1, rowIndex: -1 })}\n \n `;\n\n // columns.map(col => {\n // if (!col.width) return;\n // const $cellContent = $header.find(\n // `.data-table-col[data-col-index=\"${col.colIndex}\"] .content`\n // );\n\n // $cellContent.width(col.width);\n // });\n\n return $header;\n}\n\nfunction getBodyHTML(rows) {\n return `\n \n ${rows.map(row => getRowHTML(row, { rowIndex: row[0].rowIndex })).join('')}\n \n `;\n}\n\nfunction prepareColumn(col, i) {\n if (typeof col === 'string') {\n col = {\n content: col\n };\n }\n return Object.assign(col, {\n colIndex: i\n });\n}\n\nfunction prepareColumns(columns, props = {}) {\n const _columns = columns.map(prepareColumn);\n\n return _columns.map(col => Object.assign(col, props));\n}\n\nfunction prepareRowHeader(columns) {\n return prepareColumns(columns, {\n rowIndex: -1,\n isHeader: 1,\n format: (content) => `${content}`\n });\n}\n\nfunction prepareRow(row, i) {\n return prepareColumns(row, {\n rowIndex: i\n });\n}\n\nfunction prepareRows(rows) {\n return rows.map(prepareRow);\n}\n\nfunction getDefault(a, b) {\n return a !== undefined ? a : b;\n}\n\nfunction escapeRegExp(str) {\n // https://stackoverflow.com/a/6969486\n return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, '\\\\$&');\n}\n\nfunction getCSSString(styleMap) {\n let style = '';\n\n for (const prop in styleMap) {\n if (styleMap.hasOwnProperty(prop)) {\n style += `${prop}: ${styleMap[prop]}; `;\n }\n }\n\n return style.trim();\n}\n\nfunction getCSSRuleBlock(rule, styleMap) {\n return `${rule} { ${getCSSString(styleMap)} }`;\n}\n\nfunction namespaceSelector(selector) {\n return '.data-table ' + selector;\n}\n\nfunction buildCSSRule(rule, styleMap, cssRulesString = '') {\n // build css rules efficiently,\n // append new rule if doesnt exist,\n // update existing ones\n\n const rulePatternStr = `${escapeRegExp(rule)} {([^}]*)}`;\n const rulePattern = new RegExp(rulePatternStr, 'g');\n\n if (cssRulesString && cssRulesString.match(rulePattern)) {\n for (const property in styleMap) {\n const value = styleMap[property];\n const propPattern = new RegExp(`${escapeRegExp(property)}:([^;]*);`);\n\n cssRulesString = cssRulesString.replace(rulePattern, function (match, propertyStr) {\n if (propertyStr.match(propPattern)) {\n // property exists, replace value with new value\n propertyStr = propertyStr.replace(propPattern, (match, valueStr) => {\n return `${property}: ${value};`;\n });\n }\n propertyStr = propertyStr.trim();\n\n const replacer =\n `${rule} { ${propertyStr} }`;\n\n return replacer;\n });\n }\n\n return cssRulesString;\n }\n // no match, append new rule block\n return `${cssRulesString}${getCSSRuleBlock(rule, styleMap)}`;\n}\n\nexport default {\n getHeaderHTML,\n getBodyHTML,\n getRowHTML,\n getColumnHTML,\n getEditCellHTML,\n prepareRowHeader,\n prepareRows,\n namespaceSelector,\n getCSSString,\n buildCSSRule,\n makeDataAttributeString,\n getDefault,\n escapeRegExp\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/utils.js","// style-loader: Adds some css to the DOM by adding a