UNPKG

editable-grid

Version:
311 lines (260 loc) 10.4 kB
var $ = require('jquery'), _ = require('underscore'), sorter = require('stand-in-order'); var SORT_MAPPINGS = { text: 'string', cost: 'float', percent: 'float', select: 'string' }; var setValue = function (path, obj, value) { var split = path.split('.'); if (split.length === 1) { obj[split[0]] = value; return; } var name = split[0]; if (!_.has(obj, name)) { obj[name] = {}; } split.shift(); setValue(split.join('.'), obj[name], value); }; var delpthFirstSearch = function (rowId, collection, options) { for (var i = 0; i < collection.length; i++) { var obj = collection[i]; if (obj[options.id] === rowId) { return obj; } else if ('children' in obj && _.isArray(obj.children) && obj.children.length) { var foundObj = delpthFirstSearch(rowId, obj.children, options); if (foundObj != null) { return foundObj; } } } }; module.exports = function (options) { var grid = this; var utils = { _valueChanged: function (rowId, colId, value) { var column = _.findWhere(options.columns, {id: colId}); var id = {}; id[options.id] = isNaN(rowId) ? rowId : Number(rowId); var obj = _.findWhere(options.data, id); var parsedValue = column.parser(colId, value); setValue(colId, obj, parsedValue); grid.ears.trigger('editable-value-updated', { rowId: rowId, colId: colId, value: parsedValue }); this._updateInput(rowId, colId, parsedValue); }, _updateInput: function (rowId, colId, value) { var column = _.findWhere(options.columns, {id: colId}); var input = options.el.find('.editable-body-table tr[data-row-id="' + rowId + '"] ' + 'td[data-col-id="' + colId + '"] input'); input.val(column.formatter(colId, value)); }, _newRowChanged: function (colId) { var newObj = this._getNewRowData(); grid.ears.trigger('editable-new-row-value-changed', newObj, colId); }, _getNewRowData: function () { var tr = options.el.find('.editable-footer-table tr.new-row'); var newObj = {}; _.each(options.columns, function (column) { var el; if (column.type === 'select') { el = tr.find('td[data-col-id="' + column.id + '"] select'); } else { el = tr.find('td[data-col-id="' + column.id + '"] input'); } var parsedValue = null; if (el.is('input') && el.attr('type') === 'checkbox') { parsedValue = el.prop('checked'); } else { parsedValue = column.parser(column.id, el.val()); } newObj[column.id] = parsedValue; }, this); return newObj; }, _newRowClicked: function () { var newObj = {}; newObj[options.id] = _.uniqueId('-'); _.extend(newObj, this._getNewRowData()); grid.dataOrder.push(newObj); options.data.push(newObj); grid.ears.trigger('editable-new-row', newObj); grid.render(); // focus to the first input or select var controls = options.el.find('.editable-footer-table tr.new-row select,input'); controls.eq(0).focus(); }, _rowClicked: function (rowId, colId) { var id = {}; id[options.id] = rowId; var obj = delpthFirstSearch(rowId, options.data, options); grid.ears.trigger('editable-row-clicked', {obj: obj, rowId: rowId, colId: colId}); }, _isColumnSorted: function (id) { var sortConfig = _.findWhere(options.sortConfig, {id: id}); if (sortConfig == null) { return null; } return sortConfig.asc ? 'asc' : 'desc'; }, _columnClicked: function (id) { var column = _.findWhere(options.columns, {id: id}); if (!column.sortable) { return null; } var sort = utils._isColumnSorted(id); if (sort == null) { utils._sort(id, 'asc'); } else if (sort === 'asc') { utils._sort(id, 'desc'); } else if (sort === 'desc') { utils._sort(id, null); } }, _getSortType: function (type) { if (_.has(SORT_MAPPINGS, type)) { return SORT_MAPPINGS[type]; } return type; }, _sort: function (id, order) { grid.ears.trigger('editable-before-sort', {id: id, order: order}); var sortConfig = _.findWhere(options.sortConfig, {id: id}); if (order == null) { options.sortConfig.splice(_.indexOf(options.sortConfig, sortConfig), 1); } if (sortConfig == null) { options.sortConfig = []; options.sortConfig.push({ id: id, asc: true }); } else { sortConfig.asc = order === 'asc' ? true : false; } var sorterConfig = []; _.each(options.sortConfig, function (config) { var column = _.findWhere(options.columns, {id: config.id}); sorterConfig.push({ name: config.id, type: utils._getSortType(column.sortType || column.type), ascending: config.asc, compare: column.sortCompare }); }); if (sorterConfig.length) { sorter(options.data, sorterConfig); } else { // reset order options.data = _.clone(grid.dataOrder); } grid.render(); grid.ears.trigger('editable-after-sort', {id: id, order: order}); }, _validateRow: function (row/*tr*/) { var valid = true; var inputs = row.find('input'), rowId = row.attr('data-row-id'); _.each(inputs, function (input) { var $input = $(input), colId = $input.closest('td').attr('data-col-id'); if (!this._validate(rowId, colId, $input)) { valid = false; } }, this); return valid; }, _validate: function (rowId, colId, input) { // no validation required for check boxes if (input.attr('type') === 'checkbox') { return true; } var column = _.findWhere(options.columns, {id: colId}); var cell = input.closest('td'); cell.removeClass('has-error'); cell.find('.validation-error').remove(); var nullable = column.nullable, value = input.val(); nullable = nullable != null ? JSON.parse(nullable) : false; var message = column.validate(column.id, value); if (nullable && value.length === 0) { message = ''; } if (message.length) { // not valid cell.addClass('has-error'); if (nullable) { cell.append('<span class="validation-error help-block small">' + message + '</div>'); } else { cell.append('<span class="validation-error help-block small">Required. ' + message + '</div>'); } } return !message.length; }, _createDeleteRows: function () { var tds = options.el.find('td[data-col-id="' + options.columns[0].id + '"]'); tds.addClass('delete-column'); tds.prepend( '<div class="row-delete">' + '<button type="button" class="close" aria-hidden="true">&times;</button>' + '</div>'); }, _removeDeleteRows: function () { var tds = options.el.find('td[data-col-id="' + options.columns[0].id + '"]'); tds.removeClass('delete-column'); tds.find('.row-delete').remove(); }, _deleteRow: function (rowId) { grid.ears.trigger('editable-can-delete', rowId).done(function () { // can delete for (var i = 0; i < options.data.length; i++) { if (options.data[i].id === rowId) { options.data.splice(i, 1); break; } } grid.bodyTable.find('tr[data-row-id="' + rowId + '"]').remove(); }); }, _treeNodeExpand: function (rowId) { grid.ears.trigger('editable-before-tree-node-expand', rowId); // grab the row object var obj = delpthFirstSearch(rowId, options.data, options); // if no children property exist, then go get them var dfd = $.Deferred(); if (!('children' in obj)) { dfd = options.childData(rowId, obj).done(function (children) { children = _.isArray(children) ? children : []; obj.children = children; }); } else { dfd.resolve(); } dfd.done(function () { if (!('_treeState' in grid)) { grid._treeState = {}; } grid._treeState[rowId] = 'expand'; grid.render(); grid.ears.trigger('editable-after-tree-node-expand', rowId); }); }, _treeNodeCollapse: function (rowId) { grid.ears.trigger('editable-before-tree-node-collapse', rowId); grid._treeState[rowId] = 'collapse'; grid.render(); grid.ears.trigger('editable-after-tree-node-collapse', rowId); } }; return utils; };