handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
299 lines (286 loc) • 10.6 kB
JavaScript
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(' ');
}