UNPKG

handsontable

Version:

Handsontable is a JavaScript Data Grid available for React, Angular and Vue.

299 lines (286 loc) • 10.6 kB
import "core-js/modules/es.error.cause.js"; import "core-js/modules/es.array.push.js"; function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } import { BasePlugin } from "../base/index.mjs"; import { isObject } from "../../helpers/object.mjs"; import { rangeEach } from "../../helpers/number.mjs"; import { isUndefined } from "../../helpers/mixed.mjs"; export const PLUGIN_KEY = 'search'; export const PLUGIN_PRIORITY = 190; const DEFAULT_SEARCH_RESULT_CLASS = 'htSearchResult'; const DEFAULT_CALLBACK = function (instance, row, col, data, testResult) { instance.getCellMeta(row, col).isSearchResult = testResult; }; const DEFAULT_QUERY_METHOD = function (query, value, cellProperties) { if (isUndefined(query) || query === null || !query.toLocaleLowerCase || query.length === 0) { return false; } if (isUndefined(value) || value === null) { return false; } return value.toString().toLocaleLowerCase(cellProperties.locale).indexOf(query.toLocaleLowerCase(cellProperties.locale)) !== -1; }; /* eslint-disable jsdoc/require-description-complete-sentence */ /** * @plugin Search * @class Search * * @description * The search plugin provides an easy interface to search data across Handsontable. * * In order to enable search mechanism, {@link Options#search} option must be set to `true`. * * @example * ```js * // as boolean * search: true * // as a object with one or more options * search: { * callback: myNewCallbackFunction, * queryMethod: myNewQueryMethod, * searchResultClass: 'customClass' * } * * // Access to search plugin instance: * const searchPlugin = hot.getPlugin('search'); * * // Set callback programmatically: * searchPlugin.setCallback(myNewCallbackFunction); * // Set query method programmatically: * searchPlugin.setQueryMethod(myNewQueryMethod); * // Set search result cells class programmatically: * searchPlugin.setSearchResultClass(customClass); * ``` */ var _Search_brand = /*#__PURE__*/new WeakSet(); export class Search extends BasePlugin { constructor() { super(...arguments); /** * The `beforeRenderer` hook callback. * * @param {HTMLTableCellElement} TD The rendered `TD` element. * @param {number} row Visual row index. * @param {number} col Visual column index. * @param {string|number} prop Column property name or a column index, if datasource is an array of arrays. * @param {string} value Value of the rendered cell. * @param {object} cellProperties Object containing the cell's properties. */ _classPrivateMethodInitSpec(this, _Search_brand); /** * Function called during querying for each cell from the {@link DataMap}. * * @private * @type {Function} */ _defineProperty(this, "callback", DEFAULT_CALLBACK); /** * Query function is responsible for determining whether a query matches the value stored in a cell. * * @private * @type {Function} */ _defineProperty(this, "queryMethod", DEFAULT_QUERY_METHOD); /** * Class name added to each cell that belongs to the searched query. * * @private * @type {string} */ _defineProperty(this, "searchResultClass", DEFAULT_SEARCH_RESULT_CLASS); } static get PLUGIN_KEY() { return PLUGIN_KEY; } static get PLUGIN_PRIORITY() { return PLUGIN_PRIORITY; } /** * Checks if the plugin is enabled in the handsontable settings. This method is executed in {@link Hooks#beforeInit} * hook and if it returns `true` then the {@link AutoRowSize#enablePlugin} method is called. * * @returns {boolean} */ isEnabled() { return this.hot.getSettings()[PLUGIN_KEY]; } /** * Enables the plugin functionality for this Handsontable instance. */ enablePlugin() { var _this = this; if (this.enabled) { return; } const searchSettings = this.hot.getSettings()[PLUGIN_KEY]; this.updatePluginSettings(searchSettings); this.addHook('beforeRenderer', function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _assertClassBrand(_Search_brand, _this, _onBeforeRenderer).call(_this, ...args); }); super.enablePlugin(); } /** * Disables the plugin functionality for this Handsontable instance. */ disablePlugin() { var _this2 = this; const beforeRendererCallback = function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return _assertClassBrand(_Search_brand, _this2, _onBeforeRenderer).call(_this2, ...args); }; this.hot.addHook('beforeRenderer', beforeRendererCallback); this.hot.addHookOnce('afterViewRender', () => { this.hot.removeHook('beforeRenderer', beforeRendererCallback); }); super.disablePlugin(); } /** * Updates the plugin's state. * * This method is executed when [`updateSettings()`](@/api/core.md#updatesettings) is invoked with any of the following configuration options: * - [`search`](@/api/options.md#search) */ updatePlugin() { this.disablePlugin(); this.enablePlugin(); super.updatePlugin(); } /** * Makes the query. * * @param {string} queryStr Value to be search. * @param {Function} [callback] Callback function performed on cells with values which matches to the searched query. * @param {Function} [queryMethod] Query function responsible for determining whether a query matches the value stored in a cell. * @returns {object[]} Return an array of objects with `row`, `col`, `data` properties or empty array. */ query(queryStr) { let callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.getCallback(); let queryMethod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.getQueryMethod(); const rowCount = this.hot.countRows(); const colCount = this.hot.countCols(); const queryResult = []; const instance = this.hot; rangeEach(0, rowCount - 1, rowIndex => { rangeEach(0, colCount - 1, colIndex => { const cellData = this.hot.getDataAtCell(rowIndex, colIndex); const cellProperties = this.hot.getCellMeta(rowIndex, colIndex); const cellCallback = cellProperties.search.callback || callback; const cellQueryMethod = cellProperties.search.queryMethod || queryMethod; const testResult = cellQueryMethod(queryStr, cellData, cellProperties); if (testResult) { const singleResult = { row: rowIndex, col: colIndex, data: cellData }; queryResult.push(singleResult); } if (cellCallback) { cellCallback(instance, rowIndex, colIndex, cellData, testResult); } }); }); return queryResult; } /** * Gets the callback function. * * @returns {Function} Return the callback function. */ getCallback() { return this.callback; } /** * Sets the callback function. This function will be called during querying for each cell. * * @param {Function} newCallback A callback function. */ setCallback(newCallback) { this.callback = newCallback; } /** * Gets the query method function. * * @returns {Function} Return the query method. */ getQueryMethod() { return this.queryMethod; } /** * Sets the query method function. The function is responsible for determining whether a query matches the value stored in a cell. * * @param {Function} newQueryMethod A function with specific match logic. */ setQueryMethod(newQueryMethod) { this.queryMethod = newQueryMethod; } /** * Gets search result cells class name. * * @returns {string} Return the cell class name. */ getSearchResultClass() { return this.searchResultClass; } /** * Sets search result cells class name. This class name will be added to each cell that belongs to the searched query. * * @param {string} newElementClass CSS class name. */ setSearchResultClass(newElementClass) { this.searchResultClass = newElementClass; } /** * Updates the settings of the plugin. * * @param {object} searchSettings The plugin settings, taken from Handsontable configuration. * @private */ updatePluginSettings(searchSettings) { if (isObject(searchSettings)) { if (searchSettings.searchResultClass) { this.setSearchResultClass(searchSettings.searchResultClass); } if (searchSettings.queryMethod) { this.setQueryMethod(searchSettings.queryMethod); } if (searchSettings.callback) { this.setCallback(searchSettings.callback); } } } /** * Destroys the plugin instance. */ destroy() { super.destroy(); } } function _onBeforeRenderer(TD, row, col, prop, value, cellProperties) { // TODO: #4972 const className = cellProperties.className || []; let classArray = []; if (typeof className === 'string') { classArray = className.split(' '); } else { classArray.push(...className); } if (this.isEnabled() && cellProperties.isSearchResult) { if (!classArray.includes(this.searchResultClass)) { classArray.push(`${this.searchResultClass}`); } } else if (classArray.includes(this.searchResultClass)) { classArray.splice(classArray.indexOf(this.searchResultClass), 1); } cellProperties.className = classArray.join(' '); }