/*! StateRestore 1.4.1 * © SpryMedia Ltd - datatables.net/license */ import jQuery from 'jquery'; import DataTable from 'datatables.net'; // Allow reassignment of the $ variable let $ = jQuery; (function () { 'use strict'; var $$2; var dataTable$1; function setJQuery$1(jq) { $$2 = jq; dataTable$1 = jq.fn.dataTable; } var StateRestore = /** @class */ (function () { function StateRestore(settings, opts, identifier, state, isPreDefined, successCallback) { if (state === void 0) { state = undefined; } if (isPreDefined === void 0) { isPreDefined = false; } if (successCallback === void 0) { successCallback = function () { return null; }; } // Check that the required version of DataTables is included if (!dataTable$1 || !dataTable$1.versionCheck || !dataTable$1.versionCheck('1.10.0')) { throw new Error('StateRestore requires DataTables 1.10 or newer'); } // Check that Select is included // eslint-disable-next-line no-extra-parens if (!dataTable$1.Buttons) { throw new Error('StateRestore requires Buttons'); } var table = new dataTable$1.Api(settings); this.classes = $$2.extend(true, {}, StateRestore.classes); // Get options from user this.c = $$2.extend(true, {}, StateRestore.defaults, opts); this.s = { dt: table, identifier: identifier, isPreDefined: isPreDefined, savedState: null, tableId: state && state.stateRestore ? state.stateRestore.tableId : undefined }; this.dom = { background: $$2('<div class="' + this.classes.background + '"/>'), closeButton: $$2('<div class="' + this.classes.closeButton + '">×</div>'), confirmation: $$2('<div class="' + this.classes.confirmation + '"/>'), confirmationButton: $$2('<button class="' + this.classes.confirmationButton + ' ' + this.classes.dtButton + '">'), confirmationTitleRow: $$2('<div class="' + this.classes.confirmationTitleRow + '"></div>'), dtContainer: $$2(this.s.dt.table().container()), duplicateError: $$2('<span class="' + this.classes.modalError + '">' + this.s.dt.i18n('stateRestore.duplicateError', this.c.i18n.duplicateError) + '</span>'), emptyError: $$2('<span class="' + this.classes.modalError + '">' + this.s.dt.i18n('stateRestore.emptyError', this.c.i18n.emptyError) + '</span>'), removeContents: $$2('<div class="' + this.classes.confirmationText + '"><span>' + this.s.dt .i18n('stateRestore.removeConfirm', this.c.i18n.removeConfirm) .replace(/%s/g, StateRestore.entityEncode(this.s.identifier)) + '</span></div>'), removeError: $$2('<span class="' + this.classes.modalError + '">' + this.s.dt.i18n('stateRestore.removeError', this.c.i18n.removeError) + '</span>'), removeTitle: $$2('<h2 class="' + this.classes.confirmationTitle + '">' + this.s.dt.i18n('stateRestore.removeTitle', this.c.i18n.removeTitle) + '</h2>'), renameContents: $$2('<div class="' + this.classes.confirmationText + ' ' + this.classes.renameModal + '">' + '<label class="' + this.classes.confirmationMessage + '">' + this.s.dt .i18n('stateRestore.renameLabel', this.c.i18n.renameLabel) .replace(/%s/g, StateRestore.entityEncode(this.s.identifier)) + '</label>' + '</div>'), renameInput: $$2('<input class="' + this.classes.input + '" type="text"></input>'), renameTitle: $$2('<h2 class="' + this.classes.confirmationTitle + '">' + this.s.dt.i18n('stateRestore.renameTitle', this.c.i18n.renameTitle) + '</h2>') }; // When a StateRestore instance is created the current state of the table should also be saved. this.save(state, successCallback); } /** * Removes a state from storage and then triggers the dtsr-remove event * so that the StateRestoreCollection class can remove it's references as well. * * @param skipModal Flag to indicate if the modal should be skipped or not */ StateRestore.prototype.remove = function (skipModal) { var _a; var _this = this; if (skipModal === void 0) { skipModal = false; } // Check if removal of states is allowed if (!this.c.remove) { return false; } var removeFunction; var ajaxData = { action: 'remove', stateRestore: (_a = {}, _a[this.s.identifier] = this.s.savedState, _a) }; var successCallback = function () { _this.dom.confirmation.trigger('dtsr-remove'); $$2(_this.s.dt.table().node()).trigger('stateRestore-change'); _this.dom.background.click(); _this.dom.confirmation.remove(); $$2(document).unbind('keyup', function (e) { return _this._keyupFunction(e); }); _this.dom.confirmationButton.off('click'); }; // If the remove is not happening over ajax remove it from local storage and then trigger the event if (!this.c.ajax) { removeFunction = function () { try { localStorage.removeItem('DataTables_stateRestore_' + _this.s.identifier + '_' + location.pathname + (_this.s.tableId ? '_' + _this.s.tableId : '')); successCallback(); } catch (e) { _this.dom.confirmation.children('.' + _this.classes.modalError).remove(); _this.dom.confirmation.append(_this.dom.removeError); return 'remove'; } return true; }; } // Ajax property has to be a string, not just true // Also only want to save if the table has been initialised and the states have been loaded in else if (typeof this.c.ajax === 'string' && this.s.dt.settings()[0]._bInitComplete) { removeFunction = function () { $$2.ajax({ data: ajaxData, success: successCallback, type: 'POST', url: _this.c.ajax }); return true; }; } else if (typeof this.c.ajax === 'function') { removeFunction = function () { if (typeof _this.c.ajax === 'function') { _this.c.ajax.call(_this.s.dt, ajaxData, successCallback); } return true; }; } // If the modal is to be skipped then remove straight away if (skipModal) { this.dom.confirmation.appendTo(this.dom.dtContainer); $$2(this.s.dt.table().node()).trigger('dtsr-modal-inserted'); removeFunction(); this.dom.confirmation.remove(); } // Otherwise display the modal else { this._newModal(this.dom.removeTitle, this.s.dt.i18n('stateRestore.removeSubmit', this.c.i18n.removeSubmit), removeFunction, this.dom.removeContents); } return true; }; /** * Compares the state held within this instance with a state that is passed in * * @param state The state that is to be compared against * @returns boolean indicating if the states match */ StateRestore.prototype.compare = function (state) { // Order if (!this.c.saveState.order) { state.order = undefined; } // Search if (!this.c.saveState.search) { state.search = undefined; } // Columns if (this.c.saveState.columns && state.columns) { for (var i = 0, ien = state.columns.length; i < ien; i++) { // Visibility if (typeof this.c.saveState.columns !== 'boolean' && !this.c.saveState.columns.visible) { state.columns[i].visible = undefined; } // Search if (typeof this.c.saveState.columns !== 'boolean' && !this.c.saveState.columns.search) { state.columns[i].search = undefined; } } } else if (!this.c.saveState.columns) { state.columns = undefined; } // Paging if (!this.c.saveState.paging) { state.page = undefined; } // SearchBuilder if (!this.c.saveState.searchBuilder) { state.searchBuilder = undefined; } // SearchPanes if (!this.c.saveState.searchPanes) { state.searchPanes = undefined; } // Select if (!this.c.saveState.select) { state.select = undefined; } // ColReorder if (!this.c.saveState.colReorder) { state.ColReorder = undefined; } // Scroller if (!this.c.saveState.scroller) { state.scroller = undefined; if (dataTable$1.Scroller !== undefined) { state.start = 0; } } // Paging if (!this.c.saveState.paging) { state.start = 0; } // Page Length if (!this.c.saveState.length) { state.length = undefined; } // Need to delete properties that we do not want to compare delete state.time; var copyState = this.s.savedState; delete copyState.time; delete copyState.c; delete copyState.stateRestore; // Perform a deep compare of the two state objects return this._deepCompare(state, copyState); }; /** * Removes all of the dom elements from the document */ StateRestore.prototype.destroy = function () { $$2.each(this.dom, function (name, el) { el.off().remove(); }); }; /** * Loads the state referenced by the identifier from storage * * @param state The identifier of the state that should be loaded * @returns the state that has been loaded */ StateRestore.prototype.load = function () { var _this = this; var loadedState = this.s.savedState; var settings = this.s.dt.settings()[0]; // Always want the states stored here to be loaded in - regardless of when they were created loadedState.time = +new Date(); settings.oLoadedState = $$2.extend(true, {}, loadedState); // Click on a background if there is one to shut the collection $$2('div.dt-button-background').click(); var loaded = function () { var correctPaging = function (e, preSettings) { setTimeout(function () { var currpage = preSettings._iDisplayStart / preSettings._iDisplayLength; var intendedPage = loadedState.start / loadedState.length; // If the paging is incorrect then we have to set it again so that it is correct // This happens when a searchpanes filter is removed // This has to happen in a timeout because searchpanes only deselects after a timeout if (currpage >= 0 && intendedPage >= 0 && currpage !== intendedPage) { _this.s.dt.page(intendedPage).draw(false); } }, 50); }; _this.s.dt.one('preDraw', correctPaging); _this.s.dt.draw(false); }; // Call the internal datatables function to implement the state on the table if (DataTable.versionCheck('2')) { this.s.dt.state(loadedState); loaded(); } else { // Legacy DataTable.ext.oApi._fnImplementState(settings, loadedState, loaded); } return loadedState; }; /** * Shows a modal that allows a state to be renamed * * @param newIdentifier Optional. The new identifier for this state */ StateRestore.prototype.rename = function (newIdentifier, currentIdentifiers) { var _this = this; if (newIdentifier === void 0) { newIdentifier = null; } // Check if renaming of states is allowed if (!this.c.rename) { return; } var renameFunction = function () { var _a; if (newIdentifier === null) { var tempIdentifier = $$2('input.' + _this.classes.input.replace(/ /g, '.')).val(); if (tempIdentifier.length === 0) { _this.dom.confirmation.children('.' + _this.classes.modalError).remove(); _this.dom.confirmation.append(_this.dom.emptyError); return 'empty'; } else if (currentIdentifiers.includes(tempIdentifier)) { _this.dom.confirmation.children('.' + _this.classes.modalError).remove(); _this.dom.confirmation.append(_this.dom.duplicateError); return 'duplicate'; } else { newIdentifier = tempIdentifier; } } var ajaxData = { action: 'rename', stateRestore: (_a = {}, _a[_this.s.identifier] = newIdentifier, _a) }; var successCallback = function () { _this.s.identifier = newIdentifier; _this.save(_this.s.savedState, function () { return null; }, false); _this.dom.removeContents = $$2('<div class="' + _this.classes.confirmationText + '"><span>' + _this.s.dt .i18n('stateRestore.removeConfirm', _this.c.i18n.removeConfirm) .replace(/%s/g, _this.s.identifier) + '</span></div>'); _this.dom.confirmation.trigger('dtsr-rename'); _this.dom.background.click(); _this.dom.confirmation.remove(); $$2(document).unbind('keyup', function (e) { return _this._keyupFunction(e); }); _this.dom.confirmationButton.off('click'); }; if (!_this.c.ajax) { try { localStorage.removeItem('DataTables_stateRestore_' + _this.s.identifier + '_' + location.pathname + (_this.s.tableId ? '_' + _this.s.tableId : '')); successCallback(); } catch (e) { _this.dom.confirmation.children('.' + _this.classes.modalError).remove(); _this.dom.confirmation.append(_this.dom.removeError); return false; } } else if (typeof _this.c.ajax === 'string' && _this.s.dt.settings()[0]._bInitComplete) { $$2.ajax({ data: ajaxData, success: successCallback, type: 'POST', url: _this.c.ajax }); } else if (typeof _this.c.ajax === 'function') { _this.c.ajax.call(_this.s.dt, ajaxData, successCallback); } return true; }; // Check if a new identifier has been provided, if so no need for a modal if (newIdentifier !== null) { if (currentIdentifiers.includes(newIdentifier)) { throw new Error(this.s.dt.i18n('stateRestore.duplicateError', this.c.i18n.duplicateError)); } else if (newIdentifier.length === 0) { throw new Error(this.s.dt.i18n('stateRestore.emptyError', this.c.i18n.emptyError)); } else { this.dom.confirmation.appendTo(this.dom.dtContainer); $$2(this.s.dt.table().node()).trigger('dtsr-modal-inserted'); renameFunction(); this.dom.confirmation.remove(); } } else { this.dom.renameInput.val(this.s.identifier); this.dom.renameContents.append(this.dom.renameInput); this._newModal(this.dom.renameTitle, this.s.dt.i18n('stateRestore.renameButton', this.c.i18n.renameButton), renameFunction, this.dom.renameContents); } }; /** * Saves the tables current state using the identifier that is passed in. * * @param state Optional. If provided this is the state that will be saved rather than using the current state */ StateRestore.prototype.save = function (state, passedSuccessCallback, callAjax) { var _a; var _this = this; if (callAjax === void 0) { callAjax = true; } // Check if saving states is allowed if (!this.c.save) { if (passedSuccessCallback) { passedSuccessCallback.call(this); } return; } // this.s.dt.state.save(); var savedState; // If no state has been provided then create a new one from the current state this.s.dt.state.save(); if (state === undefined) { savedState = this.s.dt.state(); } else if (typeof state !== 'object') { return; } else { savedState = state; } if (savedState.stateRestore) { savedState.stateRestore.isPreDefined = this.s.isPreDefined; savedState.stateRestore.state = this.s.identifier; savedState.stateRestore.tableId = this.s.tableId; } else { savedState.stateRestore = { isPreDefined: this.s.isPreDefined, state: this.s.identifier, tableId: this.s.tableId }; } this.s.savedState = savedState; // Order if (!this.c.saveState.order) { this.s.savedState.order = undefined; } // Search if (!this.c.saveState.search) { this.s.savedState.search = undefined; } // Columns if (this.c.saveState.columns && this.s.savedState.columns) { for (var i = 0, ien = this.s.savedState.columns.length; i < ien; i++) { // Visibility if (typeof this.c.saveState.columns !== 'boolean' && !this.c.saveState.columns.visible) { this.s.savedState.columns[i].visible = undefined; } // Search if (typeof this.c.saveState.columns !== 'boolean' && !this.c.saveState.columns.search) { this.s.savedState.columns[i].search = undefined; } } } else if (!this.c.saveState.columns) { this.s.savedState.columns = undefined; } // SearchBuilder if (!this.c.saveState.searchBuilder) { this.s.savedState.searchBuilder = undefined; } // SearchPanes if (!this.c.saveState.searchPanes) { this.s.savedState.searchPanes = undefined; } // Select if (!this.c.saveState.select) { this.s.savedState.select = undefined; } // ColReorder if (!this.c.saveState.colReorder) { this.s.savedState.ColReorder = undefined; } // Scroller if (!this.c.saveState.scroller) { this.s.savedState.scroller = undefined; if (dataTable$1.Scroller !== undefined) { this.s.savedState.start = 0; } } // Paging if (!this.c.saveState.paging) { this.s.savedState.start = 0; } // Page Length if (!this.c.saveState.length) { this.s.savedState.length = undefined; } this.s.savedState.c = this.c; // Need to remove the parent reference before we save the state // Its not needed to rebuild, but it does cause a circular reference when converting to JSON if (this.s.savedState.c.splitSecondaries.length) { for (var _i = 0, _b = this.s.savedState.c.splitSecondaries; _i < _b.length; _i++) { var secondary = _b[_i]; if (secondary.parent) { secondary.parent = undefined; } } } // If the state is predefined there is no need to save it over ajax or to local storage if (this.s.isPreDefined) { if (passedSuccessCallback) { passedSuccessCallback.call(this); } return; } var ajaxData = { action: 'save', stateRestore: (_a = {}, _a[this.s.identifier] = this.s.savedState, _a) }; var successCallback = function () { if (passedSuccessCallback) { passedSuccessCallback.call(_this); } _this.dom.confirmation.trigger('dtsr-save'); $$2(_this.s.dt.table().node()).trigger('stateRestore-change'); }; if (!this.c.ajax) { localStorage.setItem('DataTables_stateRestore_' + this.s.identifier + '_' + location.pathname + (this.s.tableId ? '_' + this.s.tableId : ''), JSON.stringify(this.s.savedState)); successCallback(); } else if (typeof this.c.ajax === 'string' && callAjax) { if (this.s.dt.settings()[0]._bInitComplete) { $$2.ajax({ data: ajaxData, success: successCallback, type: 'POST', url: this.c.ajax }); } else { this.s.dt.one('init', function () { $$2.ajax({ data: ajaxData, success: successCallback, type: 'POST', url: _this.c.ajax }); }); } } else if (typeof this.c.ajax === 'function' && callAjax) { this.c.ajax.call(this.s.dt, ajaxData, successCallback); } }; /** * Encode HTML entities * * @param d String to encode * @returns Encoded string * @todo When DT1 support is dropped, switch to using `DataTable.util.escapeHtml` */ StateRestore.entityEncode = function (d) { return typeof d === 'string' ? d .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') : d; }; /** * Performs a deep compare of two state objects, returning true if they match * * @param state1 The first object to compare * @param state2 The second object to compare * @returns boolean indicating if the objects match */ StateRestore.prototype._deepCompare = function (state1, state2) { // Put keys and states into arrays as this makes the later code easier to work var states = [state1, state2]; var keys = [Object.keys(state1).sort(), Object.keys(state2).sort()]; var startIdx, i; // If scroller is included then we need to remove the start value // as it can be different but yield the same results if (keys[0].includes('scroller')) { startIdx = keys[0].indexOf('start'); if (startIdx) { keys[0].splice(startIdx, 1); } } if (keys[1].includes('scroller')) { startIdx = keys[1].indexOf('start'); if (startIdx) { keys[1].splice(startIdx, 1); } } // We want to remove any private properties within the states for (i = 0; i < keys[0].length; i++) { if (keys[0][i].indexOf('_') === 0) { keys[0].splice(i, 1); i--; continue; } // If scroller is included then we need to remove the following values // as they can be different but yield the same results if (keys[0][i] === 'baseRowTop' || keys[0][i] === 'baseScrollTop' || keys[0][i] === 'scrollTop' || (!this.c.saveState.paging && keys[0][i] === 'page')) { keys[0].splice(i, 1); i--; continue; } } for (i = 0; i < keys[1].length; i++) { if (keys[1][i].indexOf('_') === 0) { keys[1].splice(i, 1); i--; continue; } if (keys[1][i] === 'baseRowTop' || keys[1][i] === 'baseScrollTop' || keys[1][i] === 'scrollTop' || (!this.c.saveState.paging && keys[0][i] === 'page')) { keys[1].splice(i, 1); i--; continue; } } if (keys[0].length === 0 && keys[1].length > 0 || keys[1].length === 0 && keys[0].length > 0) { return false; } // We are only going to compare the keys that are common between both states for (i = 0; i < keys[0].length; i++) { if (!keys[1].includes(keys[0][i])) { keys[0].splice(i, 1); i--; } } for (i = 0; i < keys[1].length; i++) { if (!keys[0].includes(keys[1][i])) { keys[1].splice(i, 1); i--; } } // Then each key and value has to be checked against each other for (i = 0; i < keys[0].length; i++) { // If the keys dont equal, or their corresponding types are different we can return false if (keys[0][i] !== keys[1][i] || typeof states[0][keys[0][i]] !== typeof states[1][keys[1][i]]) { return false; } // If the type is an object then further deep comparisons are required if (typeof states[0][keys[0][i]] === 'object') { if (!this._deepCompare(states[0][keys[0][i]], states[1][keys[1][i]])) { return false; } } else if (typeof states[0][keys[0][i]] === 'number' && typeof states[1][keys[1][i]] === 'number') { if (Math.round(states[0][keys[0][i]]) !== Math.round(states[1][keys[1][i]])) { return false; } } // Otherwise we can just check the value else if (states[0][keys[0][i]] !== states[1][keys[1][i]]) { return false; } } // If we get all the way to here there are no differences so return true for this object return true; }; StateRestore.prototype._keyupFunction = function (e) { // If enter same action as pressing the button if (e.key === 'Enter') { this.dom.confirmationButton.click(); } // If escape close modal else if (e.key === 'Escape') { $$2('div.' + this.classes.background.replace(/ /g, '.')).click(); } }; /** * Creates a new confirmation modal for the user to approve an action * * @param title The title that is to be displayed at the top of the modal * @param buttonText The text that is to be displayed in the confirmation button of the modal * @param buttonAction The action that should be taken when the confirmation button is pressed * @param modalContents The contents for the main body of the modal */ StateRestore.prototype._newModal = function (title, buttonText, buttonAction, modalContents) { var _this = this; this.dom.background.appendTo(this.dom.dtContainer); this.dom.confirmationTitleRow.empty().append(title); this.dom.confirmationButton.html(buttonText); this.dom.confirmation .empty() .append(this.dom.confirmationTitleRow) .append(modalContents) .append($$2('<div class="' + this.classes.confirmationButtons + '"></div>') .append(this.dom.confirmationButton)) .appendTo(this.dom.dtContainer); $$2(this.s.dt.table().node()).trigger('dtsr-modal-inserted'); var inputs = modalContents.children('input'); // If there is an input focus on that if (inputs.length > 0) { $$2(inputs[0]).focus(); } // Otherwise focus on the confirmation button else { this.dom.confirmationButton.focus(); } var background = $$2('div.' + this.classes.background.replace(/ /g, '.')); if (this.c.modalCloseButton) { this.dom.confirmation.append(this.dom.closeButton); this.dom.closeButton.on('click', function () { return background.click(); }); } // When the button is clicked, call the appropriate action, // remove the background and modal from the screen and unbind the keyup event. this.dom.confirmationButton.on('click', function () { return buttonAction(); }); this.dom.confirmation.on('click', function (e) { e.stopPropagation(); }); // When the button is clicked, remove the background and modal from the screen and unbind the keyup event. background.one('click', function () { _this.dom.background.remove(); _this.dom.confirmation.remove(); $$2(document).unbind('keyup', function (e) { return _this._keyupFunction(e); }); }); $$2(document).on('keyup', function (e) { return _this._keyupFunction(e); }); }; StateRestore.version = '1.4.1'; StateRestore.classes = { background: 'dtsr-background', closeButton: 'dtsr-popover-close', confirmation: 'dtsr-confirmation', confirmationButton: 'dtsr-confirmation-button', confirmationButtons: 'dtsr-confirmation-buttons', confirmationMessage: 'dtsr-confirmation-message dtsr-name-label', confirmationText: 'dtsr-confirmation-text', confirmationTitle: 'dtsr-confirmation-title', confirmationTitleRow: 'dtsr-confirmation-title-row', dtButton: 'dt-button', input: 'dtsr-input', modalError: 'dtsr-modal-error', renameModal: 'dtsr-rename-modal' }; StateRestore.defaults = { _createInSaved: false, ajax: false, create: true, creationModal: false, i18n: { creationModal: { button: 'Create', colReorder: 'Column Order:', columns: { search: 'Column Search:', visible: 'Column Visibility:' }, length: 'Page Length:', name: 'Name:', order: 'Sorting:', paging: 'Paging:', scroller: 'Scroll Position:', search: 'Search:', searchBuilder: 'SearchBuilder:', searchPanes: 'SearchPanes:', select: 'Select:', title: 'Create New State', toggleLabel: 'Includes:' }, duplicateError: 'A state with this name already exists.', emptyError: 'Name cannot be empty.', emptyStates: 'No saved states', removeConfirm: 'Are you sure you want to remove %s?', removeError: 'Failed to remove state.', removeJoiner: ' and ', removeSubmit: 'Remove', removeTitle: 'Remove State', renameButton: 'Rename', renameLabel: 'New Name for %s:', renameTitle: 'Rename State' }, modalCloseButton: true, remove: true, rename: true, save: true, saveState: { colReorder: true, columns: { search: true, visible: true }, length: true, order: true, paging: true, scroller: true, search: true, searchBuilder: true, searchPanes: true, select: true }, splitSecondaries: [ 'updateState', 'renameState', 'removeState' ], toggle: { colReorder: false, columns: { search: false, visible: false }, length: false, order: false, paging: false, scroller: false, search: false, searchBuilder: false, searchPanes: false, select: false } }; return StateRestore; }()); var $$1; var dataTable; function setJQuery(jq) { $$1 = jq; dataTable = jq.fn.dataTable; } var StateRestoreCollection = /** @class */ (function () { function StateRestoreCollection(settings, opts) { var _this = this; // Check that the required version of DataTables is included if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) { throw new Error('StateRestore requires DataTables 1.10 or newer'); } // Check that Select is included // eslint-disable-next-line no-extra-parens if (!dataTable.Buttons) { throw new Error('StateRestore requires Buttons'); } var table = new dataTable.Api(settings); this.classes = $$1.extend(true, {}, StateRestoreCollection.classes); if (table.settings()[0]._stateRestore !== undefined) { return; } // Get options from user this.c = $$1.extend(true, {}, StateRestoreCollection.defaults, opts); this.s = { dt: table, hasColReorder: dataTable.ColReorder !== undefined, hasScroller: dataTable.Scroller !== undefined, hasSearchBuilder: dataTable.SearchBuilder !== undefined, hasSearchPanes: dataTable.SearchPanes !== undefined, hasSelect: dataTable.select !== undefined, states: [] }; this.s.dt.on('xhr', function (e, xhrsettings, json) { // Has staterestore been used before? Is there anything to load? if (json && json.stateRestore) { _this._addPreDefined(json.stateRestore); } }); this.dom = { background: $$1('<div class="' + this.classes.background + '"/>'), checkboxInputRow: $$1('<div class="' + this.classes.formRow + '">' + '<label class="' + this.classes.nameLabel + '">' + this.s.dt.i18n('stateRestore.creationModal.toggleLabel', this.c.i18n.creationModal.toggleLabel) + '</label>' + '<div class="dtsr-input"></div>' + '</div>'), closeButton: $$1('<div class="' + this.classes.closeButton + '">x</div>'), colReorderToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.colReorderToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.colReorder', this.c.i18n.creationModal.colReorder) + '</div>'), columnsSearchToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.columnsSearchToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.columns.search', this.c.i18n.creationModal.columns.search) + '</div>'), columnsVisibleToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.columnsVisibleToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.columns.visible', this.c.i18n.creationModal.columns.visible) + '</div>'), confirmation: $$1('<div class="' + this.classes.confirmation + '"/>'), confirmationTitleRow: $$1('<div class="' + this.classes.confirmationTitleRow + '"></div>'), createButtonRow: $$1('<div class="' + this.classes.formRow + ' ' + this.classes.modalFoot + '">' + '<button class="' + this.classes.creationButton + ' ' + this.classes.dtButton + '">' + this.s.dt.i18n('stateRestore.creationModal.button', this.c.i18n.creationModal.button) + '</button>' + '</div>'), creation: $$1('<div class="' + this.classes.creation + '"/>'), creationForm: $$1('<div class="' + this.classes.creationForm + '"/>'), creationTitle: $$1('<div class="' + this.classes.creationText + '">' + '<h2 class="' + this.classes.creationTitle + '">' + this.s.dt.i18n('stateRestore.creationModal.title', this.c.i18n.creationModal.title) + '</h2>' + '</div>'), dtContainer: $$1(this.s.dt.table().container()), duplicateError: $$1('<span class="' + this.classes.modalError + '">' + this.s.dt.i18n('stateRestore.duplicateError', this.c.i18n.duplicateError) + '</span>'), emptyError: $$1('<span class="' + this.classes.modalError + '">' + this.s.dt.i18n('stateRestore.emptyError', this.c.i18n.emptyError) + '</span>'), lengthToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.lengthToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.length', this.c.i18n.creationModal.length) + '</div>'), nameInputRow: $$1('<div class="' + this.classes.formRow + '">' + '<label class="' + this.classes.nameLabel + '">' + this.s.dt.i18n('stateRestore.creationModal.name', this.c.i18n.creationModal.name) + '</label>' + '<div class="dtsr-input">' + '<input class="' + this.classes.nameInput + '" type="text">' + '</div>' + '</div>'), orderToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.orderToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.order', this.c.i18n.creationModal.order) + '</div>'), pagingToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.pagingToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.paging', this.c.i18n.creationModal.paging) + '</div>'), removeContents: $$1('<div class="' + this.classes.confirmationText + '"><span></span></div>'), removeTitle: $$1('<div class="' + this.classes.creationText + '">' + '<h2 class="' + this.classes.creationTitle + '">' + this.s.dt.i18n('stateRestore.removeTitle', this.c.i18n.removeTitle) + '</h2>' + '</div>'), scrollerToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.scrollerToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.scroller', this.c.i18n.creationModal.scroller) + '</div>'), searchBuilderToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.searchBuilderToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.searchBuilder', this.c.i18n.creationModal.searchBuilder) + '</div>'), searchPanesToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.searchPanesToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.searchPanes', this.c.i18n.creationModal.searchPanes) + '</div>'), searchToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.searchToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.search', this.c.i18n.creationModal.search) + '</div>'), selectToggle: $$1('<div class="' + this.classes.checkLabel + '">' + '<input type="checkbox" class="' + this.classes.selectToggle + ' ' + this.classes.checkBox + '" checked>' + this.s.dt.i18n('stateRestore.creationModal.select', this.c.i18n.creationModal.select) + '</div>') }; table.settings()[0]._stateRestore = this; this._searchForStates(); // Has staterestore been used before? Is there anything to load? this._addPreDefined(this.c.preDefined); var ajaxFunction; var ajaxData = { action: 'load' }; if (typeof this.c.ajax === 'function') { ajaxFunction = function () { if (typeof _this.c.ajax === 'function') { _this.c.ajax.call(_this.s.dt, ajaxData, function (s) { return _this._addPreDefined(s); }); } }; } else if (typeof this.c.ajax === 'string') { ajaxFunction = function () { $$1.ajax({ data: ajaxData, success: function (data) { _this._addPreDefined(data); }, type: 'POST', url: _this.c.ajax }); }; } if (typeof ajaxFunction === 'function') { if (this.s.dt.settings()[0]._bInitComplete) { ajaxFunction(); } else { this.s.dt.one('preInit.dtsr', function () { ajaxFunction(); }); } } this.s.dt.on('destroy.dtsr', function () { _this.destroy(); }); this.s.dt.on('draw.dtsr buttons-action.dtsr', function () { return _this.findActive(); }); return this; } /** * Adds a new StateRestore instance to the collection based on the current properties of the table * * @param identifier The value that is used to identify a state. * @returns The state that has been created */ StateRestoreCollection.prototype.addState = function (identifier, currentIdentifiers, options) { var _this = this; // If creation/saving is not allowed then return if (!this.c.create || !this.c.save) { return; } // Check if the state exists before creating a new ones var state = this.getState(identifier); var createFunction = function (id, toggles) { if (id.length === 0) { return 'empty'; } else if (currentIdentifiers.includes(id)) { return 'duplicate'; } _this.s.dt.state.save(); var that = _this; var successCallback = function () { that.s.states.push(this); that._collectionRebuild(); }; var currState = _this.s.dt.state(); currState.stateRestore = { isPredefined: false, state: id, tableId: _this.s.dt.table().node().id }; if (toggles.saveState) { var opts = _this.c.saveState; // We don't want to extend, but instead AND all properties of the saveState option for (var _i = 0, _a = Object.keys(toggles.saveState); _i < _a.length; _i++) { var key = _a[_i]; if (typeof toggles.saveState[key] === 'object') { for (var _b = 0, _c = Object.keys(toggles.saveState[key]); _b < _c.length; _b++) { var nestedKey = _c[_b]; if (!toggles.saveState[key][nestedKey]) { opts[key][nestedKey] = false; } } } else if (!toggles.saveState[key]) { opts[key] = false; } } _this.c.saveState = opts; } var newState = new StateRestore(_this.s.dt.settings()[0], $$1.extend(true, {}, _this.c, options), id, currState, false, successCallback); $$1(_this.s.dt.table().node()).on('dtsr-modal-inserted', function () { newState.dom.confirmation.one('dtsr-remove', function () { return _this._removeCallback(newState.s.identifier); }); newState.dom.confirmation.one('dtsr-rename', function () { return _this._collectionRebuild(); }); newState.dom.confirmation.one('dtsr-save', function () { return _this._collectionRebuild(); }); }); return true; }; // If there isn't already a state with this identifier if (state === null) { if (this.c.creationModal || options !== undefined && options.creationModal) { this._creationModal(createFunction, identifier, options); } else { var success = createFunction(identifier, {}); if (success === 'empty') { throw new Error(this.s.dt.i18n('stateRestore.emptyError', this.c.i18n.emptyError)); } else if (success === 'duplicate') { throw new Error(this.s.dt.i18n('stateRestore.duplicateError', this.c.i18n.duplicateError)); } } } else { throw new Error(this.s.dt.i18n('stateRestore.duplicateError', this.c.i18n.duplicateError)); } }; /** * Removes all of the states, showing a modal to the user for confirmation * * @param removeFunction The action to be taken when the action is confirmed */ StateRestoreCollection.prototype.removeAll = function (removeFunction) { // There are no states to remove so just return if (this.s.states.length === 0) { return; } var ids = this.s.states.map(function (state) { return state.s.identifier; }); var replacementString = ids[0]; if (ids.length > 1) { replacementString = ids.slice(0, -1).join(', ') + this.s.dt.i18n('stateRestore.removeJoiner', this.c.i18n.removeJoiner) + ids.slice(-1); } $$1(this.dom.removeContents.children('span')).html(this.s.dt .i18n('stateRestore.removeConfirm', this.c.i18n.removeConfirm) .replace(/%s/g, replacementString)); this._newModal(this.dom.removeTitle, this.s.dt.i18n('stateRestore.removeSubmit', this.c.i18n.removeSubmit), removeFunction, this.dom.removeContents); }; /** * Removes all of the dom elements from the document for the collection and the stored states */ StateRestoreCollection.prototype.destroy = function () { for (var _i = 0, _a = this.s.states; _i < _a.length; _i++) { var state = _a[_i]; state.destroy(); } $$1.each(this.dom, function (name, el) { el.off().remove(); }); this.s.states = []; this.s.dt.off('.dtsr'); $$1(this.s.dt.table().node()).off('.dtsr'); }; /** * Identifies active states and updates their button to reflect this. * * @returns An array containing objects with the details of currently active states */ StateRestoreCollection.prototype.findActive = function () { // Make sure that the state is up to date this.s.dt.state.save(); var currState = this.s.dt.state(); var button; // Make all of the buttons inactive so that only any that match will be marked as active var buttons = this.s.dt.buttons().nodes(); for (var _i = 0, buttons_1 = buttons; _i < buttons_1.length; _i++) { button = buttons_1[_i]; if ($$1(button).hasClass('dtsr-state') || $$1(button).children().hasClass('dtsr-state')) { this.s.dt.button(button).active(false); } } var results = []; // Go through all of the states comparing if their state is the same to the current one for (var _a = 0, _b = this.s.states; _a < _b.length; _a++) { var state = _b[_a]; if (state.compare(currState)) { results.push({ data: state.s.savedState, name: state.s.identifier }); // If so, find the corresponding button and mark it as active for (var _c = 0, buttons_2 = buttons; _c < buttons_2.length; _c++) { button = buttons_2[_c]; var btn = this.s.dt.button(button); if (btn.text() === state.s.identifier) { btn.active(true); break; } } } } return results; }; /** * Gets a single state that has the identifier matching that which is passed in * * @param identifier The value that is used to identify a state * @returns The state that has been identified or null if no states have been identified */ StateRestoreCollection.prototype.getState = function (identifier) { for (var _i = 0, _a = this.s.states; _i < _a.length; _i++) { var state = _a[_i]; if (state.s.identifier === identifier) { return state; } } return null; }; /** * Gets an array of all of the states * * @returns Any states that have been identified */ StateRestoreCollection.prototype.getStates = function (ids) { if (ids === undefined) { return this.s.states; } else { var states = []; for (var _i = 0, ids_1 = ids; _i < ids_1.length; _i++) { var id = ids_1[_i]; var found = false; for (var _a = 0, _b = this.s.states; _a < _b.length; _a++) { var state = _b[_a]; if (id === state.s.identifier) { states.push(state); found = true; break; } } if (!found) { states.push(undefined); } } return states; } }; /** * Reloads states that are set via datatables config or over ajax * * @param preDefined Object containing the predefined states that are to be reintroduced */ StateRestoreCollection.prototype._addPreDefined = function (preDefined) { var _this = this; // There is a potential issue here if sorting where the string parts of the name are the same, // only the number differs and there are many states - but this wouldn't be usfeul naming so // more of a priority to sort alphabetically var states = Object.keys(preDefined).sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); var _loop_1 = function (state) { for (var i = 0; i < this_1.s.states.length; i++) { if (this_1.s.states[i].s.identifier === state) { this_1.s.states.splice(i, 1); } } var that = this_1; var successCallback = function () { that.s.states.push(this); that._collectionRebuild(); }; var loadedState = preDefined[state]; var newState = new StateRestore(this_1.s.dt, $$1.extend(true, {}, this_1.c, loadedState.c !== undefined ? { saveState: loadedState.c.saveState } : undefined, true), state, loadedState, true, successCallback); newState.s.savedState = loadedState; $$1(this_1.s.dt.table().node()).on('dtsr-modal-inserted', function () { newState.dom.confirmation.one('dtsr-remove', function () { return _this._removeCallback(newState.s.identifier); }); newState.dom.confirmation.one('dtsr-rename', function () { return _this._collectionRebuild(); }); newState.dom.confirmation.one('dtsr-save', function () { return _this._collectionRebuild(); }); }); }; var this_1 = this; for (var _i = 0, states_1 = states; _i < states_1.length; _i++) { var state = states_1[_i]; _loop_1(state); } }; /** * Rebuilds all of the buttons in the collection of states to make sure that states and text is up to date */ StateRestoreCollection.prototype._collectionRebuild = function () { var button = this.s.dt.button('SaveStateRestore:name'); var stateButtons = []; var i; // Need to get the original configuration object, so we can rebuild it // It might be nested, so need to traverse down the tree if (button[0]) { var idxs = button.index().split('-'); stateButtons = button[0].inst.c.buttons; for (i = 0; i < idxs.length; i++) { if (stateButtons[idxs[i]].buttons) { stateButtons = stateButtons[idxs[i]].buttons; } else { stateButtons = []; break; } } } // remove any states from the previous rebuild - if they are still there they will be added later for (i = 0; i < stateButtons.length; i++) { if (stateButtons[i].extend === 'stateRestore') { stateButtons.splice(i, 1); i--; } } if (this.c._createInSaved) { stateButtons.push('createState'); } var emptyText = '<span class="' + this.classes.emptyStates + '">' + this.s.dt.i18n('stateRestore.emptyStates', this.c.i18n.emptyStates) + '</span>'; // If there are no states display an empty message if (this.s.states.length === 0) { // Don't want the empty text included more than twice if (!stateButtons.includes(emptyText)) { stateButtons.push(emptyText); } } else { // There are states to add so there shouldn't be any empty text left! while (stateButtons.includes(emptyText)) { stateButtons.splice(stateButtons.indexOf(emptyText), 1); } // There is a potential issue here if sorting where the string parts of the name are the same, // only the number differs and there are many states - but this wouldn't be usfeul naming so // more of a priority to sort alphabetically this.s.states = this.s.states.sort(function (a, b) { var aId = a.s.identifier; var bId = b.s.identifier; return aId > bId ? 1 : aId < bId ? -1 : 0; }); // Construct the split property of each button for (var _i = 0, _a = this.s.states; _i < _a.length; _i++) { var state = _a[_i]; var split = this.c.splitSecondaries.slice(); if (split.includes('updateState') && (!this.c.save || !state.c.save)) { split.splice(split.indexOf('updateState'), 1); } if (split.includes('renameState') && (!this.c.save || !state.c.save || !this.c.rename || !state.c.rename)) { split.splice(split.indexOf('renameState'), 1); } if (split.includes('removeState') && (!this.c.remove || !state.c.remove)) { split.splice(split.indexOf('removeState'), 1); } stateButtons.push({ _stateRestore: state, attr: { title: state.s.identifier }, config: { split: split }, extend: 'stateRestore', text: StateRestore.entityEncode(state.s.identifier), popoverTitle: StateRestore.entityEncode(state.s.identifier) }); } } button.collectionRebuild(stateButtons); // Need to disable the removeAllStates button if there are no states and it is present var buttons = this.s.dt.buttons(); for (var _b = 0, buttons_3 = buttons; _b < buttons_3.length; _b++) { var butt = buttons_3[_b]; if ($$1(butt.node).hasClass('dtsr-removeAllStates')) { if (this.s.states.length === 0) { this.s.dt.button(butt.node).disable(); } else { this.s.dt.button(butt.node).enable(); } } } }; /** * Displays a modal that is used to get information from the user to create a new state. * * @param buttonAction The action that should be taken when the button is pressed * @param identifier The default identifier for the next new state */ StateRestoreCollection.prototype._creationModal = function (buttonAction, identifier, options) { var _this = this; this.dom.creation.empty(); this.dom.creationForm.empty(); this.dom.nameInputRow.find('input').val(identifier); this.dom.creationForm.append(this.dom.nameInputRow); var tableConfig = this.s.dt.settings()[0].oInit; var toggle; var togglesToInsert = []; var toggleDefined = options !== undefined && options.toggle !== undefined; // Order toggle - check toggle and saving enabled if (((!toggleDefined || options.toggle.order === undefined) && this.c.toggle.order || toggleDefined && options.toggle.order) && this.c.saveState.order && (tableConfig.ordering === undefined || tableConfig.ordering)) { togglesToInsert.push(this.dom.orderToggle); } // Search toggle - check toggle and saving enabled if (((!toggleDefined || options.toggle.search === undefined) && this.c.toggle.search || toggleDefined && options.toggle.search) && this.c.saveState.search && (tableConfig.searching === undefined || tableConfig.searching)) { togglesToInsert.push(this.dom.searchToggle); } // Paging toggle - check toggle and saving enabled if (((!toggleDefined || options.toggle.paging === undefined) && this.c.toggle.paging || toggleDefined && options.toggle.paging) && this.c.saveState.paging && (tableConfig.paging === undefined || tableConfig.paging)) { togglesToInsert.push(this.dom.pagingToggle); } // Page Length toggle - check toggle and saving enabled if (((!toggleDefined || options.toggle.length === undefined) && this.c.toggle.length || toggleDefined && options.toggle.length) && this.c.saveState.length && (tableConfig.length === undefined || tableConfig.length)) { togglesToInsert.push(this.dom.lengthToggle); } // ColReorder toggle - check toggle and saving enabled if (this.s.hasColReorder && ((!toggleDefined || options.toggle.colReorder === undefined) && this.c.toggle.colReorder || toggleDefined && options.toggle.colReorder) && this.c.saveState.colReorder) { togglesToInsert.push(this.dom.colReorderToggle); } // Scroller toggle - check toggle and saving enabled if (this.s.hasScroller && ((!toggleDefined || options.toggle.scroller === undefined) && this.c.toggle.scroller || toggleDefined && options.toggle.scroller) && this.c.saveState.scroller) { togglesToInsert.push(this.dom.scrollerToggle); } // SearchBuilder toggle - check toggle and saving enabled if (this.s.hasSearchBuilder && ((!toggleDefined || options.toggle.searchBuilder === undefined) && this.c.toggle.searchBuilder || toggleDefined && options.toggle.searchBuilder) && this.c.saveState.searchBuilder) { togglesToInsert.push(this.dom.searchBuilderToggle); } // SearchPanes toggle - check toggle and saving enabled if (this.s.hasSearchPanes && ((!toggleDefined || options.toggle.searchPanes === undefined) && this.c.toggle.searchPanes || toggleDefined && options.toggle.searchPanes) && this.c.saveState.searchPanes) { togglesToInsert.push(this.dom.searchPanesToggle); } // Select toggle - check toggle and saving enabled if (this.s.hasSelect && ((!toggleDefined || options.toggle.select === undefined) && this.c.toggle.select || toggleDefined && options.toggle.select) && this.c.saveState.select) { togglesToInsert.push(this.dom.selectToggle); } // Columns toggle - check toggle and saving enabled if (typeof this.c.toggle.columns === 'boolean' && ((!toggleDefined || options.toggle.order === undefined) && this.c.toggle.columns || toggleDefined && options.toggle.order) && this.c.saveState.columns) { togglesToInsert.push(this.dom.columnsSearchToggle); togglesToInsert.push(this.dom.columnsVisibleToggle); } else if ((!toggleDefined || options.toggle.columns === undefined) && typeof this.c.toggle.columns !== 'boolean' || typeof options.toggle.order !== 'boolean') { if (typeof this.c.saveState.columns !== 'boolean' && this.c.saveState.columns) { // Column search toggle - check toggle and saving enabled if (( // columns.search is defined when passed in toggleDefined && options.toggle.columns !== undefined && typeof options.toggle.columns !== 'boolean' && options.toggle.columns.search || // Columns search is not defined when passed in but is in defaults (!toggleDefined || options.toggle.columns === undefined || typeof options.toggle.columns !== 'boolean' && options.toggle.columns.search === undefined) && typeof this.c.toggle.columns !== 'boolean' && this.c.toggle.columns.search) && this.c.saveState.columns.search) { togglesToInsert.push(this.dom.columnsSearchToggle); } // Column visiblity toggle - check toggle and saving enabled if (( // columns.visible is defined when passed in toggleDefined && options.toggle.columns !== undefined && typeof options.toggle.columns !== 'boolean' && options.toggle.columns.visible || // Columns visible is not defined when passed in but is in defaults (!toggleDefined || options.toggle.columns === undefined || typeof options.toggle.columns !== 'boolean' && options.toggle.columns.visible === undefined) && typeof this.c.toggle.columns !== 'boolean' && this.c.toggle.columns.visible) && this.c.saveState.columns.visible) { togglesToInsert.push(this.dom.columnsVisibleToggle); } } else if (this.c.saveState.columns) { togglesToInsert.push(this.dom.columnsSearchToggle); togglesToInsert.push(this.dom.columnsVisibleToggle); } } // Make sure that the toggles are displayed alphabetically togglesToInsert.sort(function (a, b) { var aVal = a.text(); var bVal = b.text(); if (aVal < bVal) { return -1; } else if (aVal > bVal) { return 1; } else { return 0; } }); // Append all of the toggles that are to be inserted var checkboxesEl = this.dom.checkboxInputRow .appendTo(this.dom.creationForm) .find('div.dtsr-input') .empty(); // let checkboxes = $('<div class="'+this.classes.formRow+' '+this.classes.checkRow+'"></div>') // .appendTo(this.dom.creationForm); for (var _i = 0, togglesToInsert_1 = togglesToInsert; _i < togglesToInsert_1.length; _i++) { toggle = togglesToInsert_1[_i]; checkboxesEl.append(toggle); } // Insert the toggle label next to the first check box // $(this.dom.creationForm.children('div.'+this.classes.checkRow)[0]).prepend(this.dom.toggleLabel); // Insert the creation modal and the background this.dom.background.appendTo(this.dom.dtContainer); this.dom.creation .append(this.dom.creationTitle) .append(this.dom.creationForm) .append(this.dom.createButtonRow) .appendTo(this.dom.dtContainer); $$1(this.s.dt.table().node()).trigger('dtsr-modal-inserted'); // Allow the label to be clicked to toggle the checkbox for (var _a = 0, togglesToInsert_2 = togglesToInsert; _a < togglesToInsert_2.length; _a++) { toggle = togglesToInsert_2[_a]; $$1(toggle.children('label:last-child')).on('click', function () { toggle.children('input').prop('checked', !toggle.children('input').prop('checked')); }); } var creationButton = $$1('button.' + this.classes.creationButton.replace(/ /g, '.')); var inputs = this.dom.creationForm.find('input'); // If there is an input focus on that if (inputs.length > 0) { $$1(inputs[0]).focus(); } // Otherwise focus on the confirmation button else { creationButton.focus(); } var background = $$1('div.' + this.classes.background.replace(/ /g, '.')); var keyupFunction = function (e) { if (e.key === 'Enter') { creationButton.click(); } else if (e.key === 'Escape') { background.click(); } }; if (this.c.modalCloseButton) { this.dom.creation.append(this.dom.closeButton); this.dom.closeButton.on('click', function () { return background.click(); }); } creationButton.on('click', function () { // Get the values of the checkBoxes var saveState = { colReorder: _this.dom.colReorderToggle.find('input').is(':checked'), columns: { search: _this.dom.columnsSearchToggle.find('input').is(':checked'), visible: _this.dom.columnsVisibleToggle.find('input').is(':checked') }, length: _this.dom.lengthToggle.find('input').is(':checked'), order: _this.dom.orderToggle.find('input').is(':checked'), paging: _this.dom.pagingToggle.find('input').is(':checked'), scroller: _this.dom.scrollerToggle.find('input').is(':checked'), search: _this.dom.searchToggle.find('input').is(':checked'), searchBuilder: _this.dom.searchBuilderToggle.find('input').is(':checked'), searchPanes: _this.dom.searchPanesToggle.find('input').is(':checked'), select: _this.dom.selectToggle.find('input').is(':checked') }; // Call the buttons functionality passing in the identifier and what should be saved var success = buttonAction($$1('input.' + _this.classes.nameInput.replace(/ /g, '.')).val(), { saveState: saveState }); if (success === true) { // Remove the dom elements as operation has completed _this.dom.background.remove(); _this.dom.creation.remove(); // Unbind the keyup function - don't want it to run unnecessarily on every keypress that occurs $$1(document).unbind('keyup', keyupFunction); } else { _this.dom.creation.children('.' + _this.classes.modalError).remove(); _this.dom.creation.append(_this.dom[success + 'Error']); } }); background.one('click', function () { // Remove the dome elements as operation has been cancelled _this.dom.background.remove(); _this.dom.creation.remove(); // Unbind the keyup function - don't want it to run unnecessarily on every keypress that occurs $$1(document).unbind('keyup', keyupFunction); // Rebuild the collection to ensure that the latest changes are present _this._collectionRebuild(); }); // Have to listen to the keyup event as `escape` doesn't trigger keypress $$1(document).on('keyup', keyupFunction); // Need to save the state before the focus is lost when the modal is interacted with this.s.dt.state.save(); }; /** * This callback is called when a state is removed. * This removes the state from storage and also strips it's button from the container * * @param identifier The value that is used to identify a state */ StateRestoreCollection.prototype._removeCallback = function (identifier) { for (var i = 0; i < this.s.states.length; i++) { if (this.s.states[i].s.identifier === identifier) { this.s.states.splice(i, 1); i--; } } this._collectionRebuild(); return true; }; /** * Creates a new confirmation modal for the user to approve an action * * @param title The title that is to be displayed at the top of the modal * @param buttonText The text that is to be displayed in the confirmation button of the modal * @param buttonAction The action that should be taken when the confirmation button is pressed * @param modalContents The contents for the main body of the modal */ StateRestoreCollection.prototype._newModal = function (title, buttonText, buttonAction, modalContents) { var _this = this; this.dom.background.appendTo(this.dom.dtContainer); this.dom.confirmationTitleRow.empty().append(title); var confirmationButton = $$1('<button class="' + this.classes.confirmationButton + ' ' + this.classes.dtButton + '">' + buttonText + '</button>'); this.dom.confirmation .empty() .append(this.dom.confirmationTitleRow) .append(modalContents) .append($$1('<div class="' + this.classes.confirmationButtons + '"></div>') .append(confirmationButton)) .appendTo(this.dom.dtContainer); $$1(this.s.dt.table().node()).trigger('dtsr-modal-inserted'); var inputs = modalContents.children('input'); // If there is an input focus on that if (inputs.length > 0) { $$1(inputs[0]).focus(); } // Otherwise focus on the confirmation button else { confirmationButton.focus(); } var background = $$1('div.' + this.classes.background.replace(/ /g, '.')); var keyupFunction = function (e) { // If enter same action as pressing the button if (e.key === 'Enter') { confirmationButton.click(); } // If escape close modal else if (e.key === 'Escape') { background.click(); } }; // When the button is clicked, call the appropriate action, // remove the background and modal from the screen and unbind the keyup event. confirmationButton.on('click', function () { var success = buttonAction(true); if (success === true) { _this.dom.background.remove(); _this.dom.confirmation.remove(); $$1(document).unbind('keyup', keyupFunction); confirmationButton.off('click'); } else { _this.dom.confirmation.children('.' + _this.classes.modalError).remove(); _this.dom.confirmation.append(_this.dom[success + 'Error']); } }); this.dom.confirmation.on('click', function (e) { e.stopPropagation(); }); // When the button is clicked, remove the background and modal from the screen and unbind the keyup event. background.one('click', function () { _this.dom.background.remove(); _this.dom.confirmation.remove(); $$1(document).unbind('keyup', keyupFunction); }); $$1(document).on('keyup', keyupFunction); }; /** * Private method that checks for previously created states on initialisation */ StateRestoreCollection.prototype._searchForStates = function () { var _this = this; var keys = Object.keys(localStorage); var _loop_2 = function (key) { // eslint-disable-next-line no-useless-escape if (key.match(new RegExp('^DataTables_stateRestore_.*_' + location.pathname + '$')) || key.match(new RegExp('^DataTables_stateRestore_.*_' + location.pathname + '_' + this_2.s.dt.table().node().id + '$'))) { var loadedState_1 = JSON.parse(localStorage.getItem(key)); if (loadedState_1.stateRestore.isPreDefined || (loadedState_1.stateRestore.tableId && loadedState_1.stateRestore.tableId !== this_2.s.dt.table().node().id)) { return "continue"; } var that_1 = this_2; var successCallback = function () { this.s.savedState = loadedState_1; that_1.s.states.push(this); that_1._collectionRebuild(); }; var newState_1 = new StateRestore(this_2.s.dt, $$1.extend(true, {}, this_2.c, { saveState: loadedState_1.c.saveState }), loadedState_1.stateRestore.state, loadedState_1, false, successCallback); $$1(this_2.s.dt.table().node()).on('dtsr-modal-inserted', function () { newState_1.dom.confirmation.one('dtsr-remove', function () { return _this._removeCallback(newState_1.s.identifier); }); newState_1.dom.confirmation.one('dtsr-rename', function () { return _this._collectionRebuild(); }); newState_1.dom.confirmation.one('dtsr-save', function () { return _this._collectionRebuild(); }); }); } }; var this_2 = this; for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { var key = keys_1[_i]; _loop_2(key); } }; StateRestoreCollection.version = '1.0.0'; StateRestoreCollection.classes = { background: 'dtsr-background', checkBox: 'dtsr-check-box', checkLabel: 'dtsr-check-label', checkRow: 'dtsr-check-row', closeButton: 'dtsr-popover-close', colReorderToggle: 'dtsr-colReorder-toggle', columnsSearchToggle: 'dtsr-columns-search-toggle', columnsVisibleToggle: 'dtsr-columns-visible-toggle', confirmation: 'dtsr-confirmation', confirmationButton: 'dtsr-confirmation-button', confirmationButtons: 'dtsr-confirmation-buttons', confirmationMessage: 'dtsr-confirmation-message dtsr-name-label', confirmationText: 'dtsr-confirmation-text', confirmationTitle: 'dtsr-confirmation-title', confirmationTitleRow: 'dtsr-confirmation-title-row', creation: 'dtsr-creation', creationButton: 'dtsr-creation-button', creationForm: 'dtsr-creation-form', creationText: 'dtsr-creation-text', creationTitle: 'dtsr-creation-title', dtButton: 'dt-button', emptyStates: 'dtsr-emptyStates', formRow: 'dtsr-form-row', leftSide: 'dtsr-left', lengthToggle: 'dtsr-length-toggle', modalError: 'dtsr-modal-error', modalFoot: 'dtsr-modal-foot', nameInput: 'dtsr-name-input', nameLabel: 'dtsr-name-label', orderToggle: 'dtsr-order-toggle', pagingToggle: 'dtsr-paging-toggle', rightSide: 'dtsr-right', scrollerToggle: 'dtsr-scroller-toggle', searchBuilderToggle: 'dtsr-searchBuilder-toggle', searchPanesToggle: 'dtsr-searchPanes-toggle', searchToggle: 'dtsr-search-toggle', selectToggle: 'dtsr-select-toggle', toggleLabel: 'dtsr-toggle-title' }; StateRestoreCollection.defaults = { _createInSaved: false, ajax: false, create: true, creationModal: false, i18n: { creationModal: { button: 'Create', colReorder: 'Column Order', columns: { search: 'Column Search', visible: 'Column Visibility' }, length: 'Page Length', name: 'Name:', order: 'Sorting', paging: 'Paging', scroller: 'Scroll Position', search: 'Search', searchBuilder: 'SearchBuilder', searchPanes: 'SearchPanes', select: 'Select', title: 'Create New State', toggleLabel: 'Include:' }, duplicateError: 'A state with this name already exists.', emptyError: 'Name cannot be empty.', emptyStates: 'No saved states', removeConfirm: 'Are you sure you want to remove %s?', removeError: 'Failed to remove state.', removeJoiner: ' and ', removeSubmit: 'Remove', removeTitle: 'Remove State', renameButton: 'Rename', renameLabel: 'New Name for %s:', renameTitle: 'Rename State' }, modalCloseButton: true, preDefined: {}, remove: true, rename: true, save: true, saveState: { colReorder: true, columns: { search: true, visible: true }, length: true, order: true, paging: true, scroller: true, search: true, searchBuilder: true, searchPanes: true, select: true }, splitSecondaries: [ 'updateState', 'renameState', 'removeState' ], toggle: { colReorder: false, columns: { search: false, visible: false }, length: false, order: false, paging: false, scroller: false, search: false, searchBuilder: false, searchPanes: false, select: false } }; return StateRestoreCollection; }()); /*! StateRestore 1.4.1 * © SpryMedia Ltd - datatables.net/license */ setJQuery$1($); setJQuery($); $.fn.dataTable.StateRestore = StateRestore; $.fn.DataTable.StateRestore = StateRestore; $.fn.dataTable.StateRestoreCollection = StateRestoreCollection; $.fn.DataTable.StateRestoreCollection = StateRestoreCollection; var apiRegister = DataTable.Api.register; apiRegister('stateRestore()', function () { return this; }); apiRegister('stateRestore.state()', function (identifier) { var ctx = this.context[0]; if (!ctx._stateRestore) { var api = DataTable.Api(ctx); var src = new DataTable.StateRestoreCollection(api, {}); _stateRegen(api, src); } this[0] = ctx._stateRestore.getState(identifier); return this; }); apiRegister('stateRestore.state.add()', function (identifier, options) { var ctx = this.context[0]; if (!ctx._stateRestore) { var api = DataTable.Api(ctx); var src = new DataTable.StateRestoreCollection(api, {}); _stateRegen(api, src); } if (!ctx._stateRestore.c.create) { return this; } if (ctx._stateRestore.addState) { var states = ctx._stateRestore.s.states; var ids = []; for (var _i = 0, states_1 = states; _i < states_1.length; _i++) { var intState = states_1[_i]; ids.push(intState.s.identifier); } ctx._stateRestore.addState(identifier, ids, options); return this; } }); apiRegister('stateRestore.states()', function (ids) { var ctx = this.context[0]; if (!ctx._stateRestore) { var api = DataTable.Api(ctx); var src = new DataTable.StateRestoreCollection(api, {}); _stateRegen(api, src); } this.length = 0; this.push.apply(this, ctx._stateRestore.getStates(ids)); return this; }); apiRegister('stateRestore.state().save()', function () { var ctx = this[0]; // Check if saving states is allowed if (ctx.c.save) { ctx.save(); } return this; }); apiRegister('stateRestore.state().rename()', function (newIdentifier) { var ctx = this.context[0]; var state = this[0]; // Check if renaming states is allowed if (state.c.save) { var states = ctx._stateRestore.s.states; var ids = []; for (var _i = 0, states_2 = states; _i < states_2.length; _i++) { var intState = states_2[_i]; ids.push(intState.s.identifier); } state.rename(newIdentifier, ids); } return this; }); apiRegister('stateRestore.state().load()', function () { var ctx = this[0]; ctx.load(); return this; }); apiRegister('stateRestore.state().remove()', function (skipModal) { var ctx = this[0]; // Check if removal of states is allowed if (ctx.c.remove) { ctx.remove(skipModal); } return this; }); apiRegister('stateRestore.states().remove()', function (skipModal) { var _this = this; var removeAllCallBack = function (skipModalIn) { var success = true; var that = _this.toArray(); while (that.length > 0) { var set = that[0]; if (set !== undefined && set.c.remove) { var tempSuccess = set.remove(skipModalIn); if (tempSuccess !== true) { success = tempSuccess; } else { that.splice(0, 1); } } else { break; } } return success; }; if (this.context[0]._stateRestore && this.context[0]._stateRestore.c.remove) { if (skipModal) { removeAllCallBack(skipModal); } else { this.context[0]._stateRestore.removeAll(removeAllCallBack); } } return this; }); apiRegister('stateRestore.activeStates()', function () { var ctx = this.context[0]; this.length = 0; if (!ctx._stateRestore) { var api = DataTable.Api(ctx); var src = new DataTable.StateRestoreCollection(api, {}); _stateRegen(api, src); } if (ctx._stateRestore) { this.push.apply(this, ctx._stateRestore.findActive()); } return this; }); DataTable.ext.buttons.stateRestore = { action: function (e, dt, node, config) { config._stateRestore.load(); node.blur(); }, className: 'dtsr-state', config: { split: ['updateState', 'renameState', 'removeState'] }, text: function (dt) { return dt.i18n('buttons.stateRestore', 'State %d', dt.stateRestore.states()[0].length + 1); } }; DataTable.ext.buttons.updateState = { action: function (e, dt, node, config) { $('div.dt-button-background').click(); config.parent._stateRestore.save(); }, text: function (dt) { return dt.i18n('buttons.updateState', 'Update'); } }; DataTable.ext.buttons.savedStates = { buttons: [], extend: 'collection', init: function (dt, node, config) { dt.on('stateRestore-change', function () { dt.button(node).text(dt.i18n('buttons.savedStates', 'Saved States', dt.stateRestore.states().length)); }); if (dt.settings()[0]._stateRestore === undefined) { _buttonInit(dt, config); } }, name: 'SaveStateRestore', text: function (dt) { return dt.i18n('buttons.savedStates', 'Saved States', 0); } }; DataTable.ext.buttons.savedStatesCreate = { buttons: [], extend: 'collection', init: function (dt, node, config) { dt.on('stateRestore-change', function () { dt.button(node).text(dt.i18n('buttons.savedStates', 'Saved States', dt.stateRestore.states().length)); }); if (dt.settings()[0]._stateRestore === undefined) { if (config.config === undefined) { config.config = {}; } config.config._createInSaved = true; _buttonInit(dt, config); } }, name: 'SaveStateRestore', text: function (dt) { return dt.i18n('buttons.savedStates', 'Saved States', 0); } }; DataTable.ext.buttons.createState = { action: function (e, dt, node, config) { e.stopPropagation(); var stateRestoreOpts = dt.settings()[0]._stateRestore.c; var language = dt.settings()[0].oLanguage; // If creation/saving is not allowed then return if (!stateRestoreOpts.create || !stateRestoreOpts.save) { return; } var prevStates = dt.stateRestore.states().toArray(); // Create a replacement regex based on the i18n values var defaultString = language.buttons !== undefined && language.buttons.stateRestore !== undefined ? language.buttons.stateRestore : 'State '; var replaceRegex; if (defaultString.indexOf('%d') === defaultString.length - 3) { replaceRegex = new RegExp(defaultString.replace(/%d/g, '')); } else { var splitString = defaultString.split('%d'); replaceRegex = []; for (var _i = 0, splitString_1 = splitString; _i < splitString_1.length; _i++) { var parts = splitString_1[_i]; replaceRegex.push(new RegExp(parts)); } } var getId = function (identifier) { var id; if (Array.isArray(replaceRegex)) { id = identifier; for (var _i = 0, replaceRegex_1 = replaceRegex; _i < replaceRegex_1.length; _i++) { var reg = replaceRegex_1[_i]; id = id.replace(reg, ''); } } else { id = identifier.replace(replaceRegex, ''); } // If the id after replacement is not a number, or the length is the same as before, // it has been customised so return 0 if (isNaN(+id) || id.length === identifier) { return 0; } // Otherwise return the number that has been assigned previously else { return +id; } }; // Extract the numbers from the identifiers that use the standard naming convention var identifiers = prevStates .map(function (state) { return getId(state.s.identifier); }) .sort(function (a, b) { return +a < +b ? 1 : +a > +b ? -1 : 0; }); var lastNumber = identifiers[0]; dt.stateRestore.state.add(dt.i18n('buttons.stateRestore', 'State %d', lastNumber !== undefined ? lastNumber + 1 : 1), config.config); var states = dt.stateRestore.states().sort(function (a, b) { var aId = +getId(a.s.identifier); var bId = +getId(b.s.identifier); return aId > bId ? 1 : aId < bId ? -1 : 0; }); var button = dt.button('SaveStateRestore:name'); var stateButtons = button[0] !== undefined && button[0].inst.c.buttons[0].buttons !== undefined ? button[0].inst.c.buttons[0].buttons : []; // remove any states from the previous rebuild - if they are still there they will be added later for (var i = 0; i < stateButtons.length; i++) { if (stateButtons[i].extend === 'stateRestore') { stateButtons.splice(i, 1); i--; } } if (stateRestoreOpts._createInSaved) { stateButtons.push('createState'); } for (var _a = 0, states_3 = states; _a < states_3.length; _a++) { var state = states_3[_a]; var split = stateRestoreOpts.splitSecondaries.slice(); if (split.includes('updateState') && !stateRestoreOpts.save) { split.splice(split.indexOf('updateState'), 1); } if (split.includes('renameState') && (!stateRestoreOpts.save || !stateRestoreOpts.rename)) { split.splice(split.indexOf('renameState'), 1); } if (split.includes('removeState') && !stateRestoreOpts.remove) { split.splice(split.indexOf('removeState'), 1); } stateButtons.push({ _stateRestore: state, attr: { title: state.s.identifier }, config: { split: split }, extend: 'stateRestore', text: StateRestore.entityEncode(state.s.identifier), popoverTitle: StateRestore.entityEncode(state.s.identifier) }); } dt.button('SaveStateRestore:name').collectionRebuild(stateButtons); node.blur(); // Need to disable the removeAllStates button if there are no states and it is present var buttons = dt.buttons(); for (var _b = 0, buttons_1 = buttons; _b < buttons_1.length; _b++) { var butt = buttons_1[_b]; if ($(butt.node).hasClass('dtsr-removeAllStates')) { if (states.length === 0) { dt.button(butt.node).disable(); } else { dt.button(butt.node).enable(); } } } }, init: function (dt, node, config) { if (dt.settings()[0]._stateRestore === undefined && dt.button('SaveStateRestore:name').length > 1) { _buttonInit(dt, config); } }, text: function (dt) { return dt.i18n('buttons.createState', 'Create State'); } }; DataTable.ext.buttons.removeState = { action: function (e, dt, node, config) { config.parent._stateRestore.remove(); node.blur(); }, text: function (dt) { return dt.i18n('buttons.removeState', 'Remove'); } }; DataTable.ext.buttons.removeAllStates = { action: function (e, dt, node) { dt.stateRestore.states().remove(true); node.blur(); }, className: 'dt-button dtsr-removeAllStates', init: function (dt, node) { if (!dt.settings()[0]._stateRestore || dt.stateRestore.states().length === 0) { $(node).addClass('disabled'); } }, text: function (dt) { return dt.i18n('buttons.removeAllStates', 'Remove All States'); } }; DataTable.ext.buttons.renameState = { action: function (e, dt, node, config) { var states = dt.settings()[0]._stateRestore.s.states; var ids = []; for (var _i = 0, states_4 = states; _i < states_4.length; _i++) { var state = states_4[_i]; ids.push(state.s.identifier); } config.parent._stateRestore.rename(undefined, ids); node.blur(); }, text: function (dt) { return dt.i18n('buttons.renameState', 'Rename'); } }; function _init(settings, options) { if (options === void 0) { options = null; } var api = new DataTable.Api(settings); var opts = options ? options : api.init().stateRestore || DataTable.defaults.stateRestore; var stateRestore = new StateRestoreCollection(api, opts); _stateRegen(api, stateRestore); return stateRestore; } /** * Initialisation function if initialising using a button * * @param dt The datatables instance * @param config the config for the button */ function _buttonInit(dt, config) { var SRC = new DataTable.StateRestoreCollection(dt, config.config); _stateRegen(dt, SRC); } function _stateRegen(dt, src) { var states = dt.stateRestore.states(); var button = dt.button('SaveStateRestore:name'); var stateButtons = []; var i; // Need to get the original configuration object, so we can rebuild it // It might be nested, so need to traverse down the tree if (button[0]) { var idxs = button.index().split('-'); stateButtons = button[0].inst.c.buttons; for (i = 0; i < idxs.length; i++) { if (stateButtons[idxs[i]].buttons) { stateButtons = stateButtons[idxs[i]].buttons; } else { stateButtons = []; break; } } } var stateRestoreOpts = dt.settings()[0]._stateRestore.c; // remove any states from the previous rebuild - if they are still there they will be added later for (i = 0; i < stateButtons.length; i++) { if (stateButtons[i].extend === 'stateRestore') { stateButtons.splice(i, 1); i--; } } if (stateRestoreOpts._createInSaved) { stateButtons.push('createState'); } if (states === undefined || states.length === 0) { stateButtons.push('<span class="' + src.classes.emptyStates + '">' + dt.i18n('stateRestore.emptyStates', src.c.i18n.emptyStates) + '</span>'); } else { for (var _i = 0, states_5 = states; _i < states_5.length; _i++) { var state = states_5[_i]; var split = stateRestoreOpts.splitSecondaries.slice(); if (split.includes('updateState') && !stateRestoreOpts.save) { split.splice(split.indexOf('updateState'), 1); } if (split.includes('renameState') && (!stateRestoreOpts.save || !stateRestoreOpts.rename)) { split.splice(split.indexOf('renameState'), 1); } if (split.includes('removeState') && !stateRestoreOpts.remove) { split.splice(split.indexOf('removeState'), 1); } stateButtons.push({ _stateRestore: state, attr: { title: state.s.identifier }, config: { split: split }, extend: 'stateRestore', text: StateRestore.entityEncode(state.s.identifier), popoverTitle: StateRestore.entityEncode(state.s.identifier) }); } } dt.button('SaveStateRestore:name').collectionRebuild(stateButtons); // Need to disable the removeAllStates button if there are no states and it is present var buttons = dt.buttons(); for (var _a = 0, buttons_2 = buttons; _a < buttons_2.length; _a++) { var butt = buttons_2[_a]; if ($(butt.node).hasClass('dtsr-removeAllStates')) { if (states.length === 0) { dt.button(butt.node).disable(); } else { dt.button(butt.node).enable(); } } } } // Attach a listener to the document which listens for DataTables initialisation // events so we can automatically initialise $(document).on('preInit.dt.dtsr', function (e, settings) { if (e.namespace !== 'dt') { return; } if (settings.oInit.stateRestore || DataTable.defaults.stateRestore) { if (!settings._stateRestore) { _init(settings, null); } } }); })(); export default DataTable;