%PDF- %PDF-
Direktori : /var/www/projetos/suporte.iigd.com.br.old/js/modules/SearchTokenizer/ |
Current File : /var/www/projetos/suporte.iigd.com.br.old/js/modules/SearchTokenizer/SearchTokenizer.js |
/** * --------------------------------------------------------------------- * * GLPI - Gestionnaire Libre de Parc Informatique * * http://glpi-project.org * * @copyright 2015-2022 Teclib' and contributors. * @copyright 2003-2014 by the INDEPNET Development Team. * @licence https://www.gnu.org/licenses/gpl-3.0.html * * --------------------------------------------------------------------- * * LICENSE * * This file is part of GLPI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * --------------------------------------------------------------------- */ import SearchToken from "./SearchToken.js"; import SearchTokenizerResult from "./SearchTokenizerResult.js"; /** * Inspired by/rebuilt from https://github.com/tatsuya/search-text-tokenizer */ export default class SearchTokenizer { /** * @typedef TagDefinition * @property {string} description * @property {string[]|function} autocomplete_values * @property {string[]} supported_prefixes */ /** * @typedef TokenizerOptions * @property {Object.<string, {}>} custom_prefixes Object of custom prefixes as keys and properties. These characters can be located at the start of a token's tag and will be stripped from the token's tag. * The stripped prefix is then stored in the token's `prefix` property. The properties for the custom prefixes can be unique for the implementation of the tokenizer. * The only built-in properties are `token_color` which can be used by {@link SearchInput} to change the color of the token, and `label` which can be used by {@link SearchInput} for buttons within suggestions. */ /** * * @param {Object.<string, TagDefinition>} allowed_tags Tags the tokenizer should recognize * The object keys are the tag names. Each tag can have multiple properties to store * additional information such as descriptions. * @param {boolean} drop_unallowed_tags If true, unallowed tags are ignored. If false, the token is treated as a plain term. * @param {TokenizerOptions} options Additional tokenizer options */ constructor(allowed_tags = {}, drop_unallowed_tags = false, options = {}) { this.token_pattern = /([^\s"']?\w+:)?("[^"]*"|'[^']*'|[^\s]+)/g; this.EXCLUSION_PREFIX = '!'; this.allowed_tags = allowed_tags; this.drop_unallowed_tags = drop_unallowed_tags; this.options = Object.assign({ custom_prefixes: {}, }, options); // Ignore custom prefixes used by core delete this.options.custom_prefixes[this.EXCLUSION_PREFIX]; delete this.options.custom_prefixes['\'']; delete this.options.custom_prefixes['"']; } /** * Check if a given tag is allowed by the tokenizer * @param {string|null} tag * @return {boolean} */ isAllowedTag(tag) { if (tag === null || tag === undefined) { return true; } const result = Object.keys(this.allowed_tags).length === 0 || (tag in this.allowed_tags); return result; } clearAutocomplete() { Object.keys(this.allowed_tags).forEach((k) => { this.allowed_tags[k].autocomplete_values = []; }); } setAutocomplete(tag, values) { if (tag in this.allowed_tags) { this.allowed_tags[tag].autocomplete_values = values; } } /** * Get autocomplete values for a given tag * @param tag * @return {string[]} */ getAutocomplete(tag) { let result = []; if (tag in this.allowed_tags) { if (typeof this.allowed_tags[tag].autocomplete_values === 'function') { result = this.allowed_tags[tag].autocomplete_values(); } else { result = this.allowed_tags[tag].autocomplete_values; } } return result || []; } /** * * @param {string} input * @returns {SearchTokenizerResult} */ tokenize(input) { input = input || ''; input = input.trim(); const result = new SearchTokenizerResult(); let token = null; let pos = 0; while ((token = this.token_pattern.exec(input)) !== null) { let is_exclusion = false; let tag = token[1] || null; let term = token[2].trim(); // Tag without the separator if (tag) { tag = tag.slice(0, -1); } if (tag === null && term.endsWith(':')) { tag = term.slice(0, -1); term = ''; } let token_prefix = null; // Handle custom prefixes if (tag && tag.length > 1) { const custom_prefix = tag.slice(0, 1); const allowed_prefixes = Object.keys(this.options.custom_prefixes); if (custom_prefix === this.EXCLUSION_PREFIX) { is_exclusion = true; tag = tag.slice(1); } else { if (allowed_prefixes.includes(custom_prefix)) { const new_tag = tag.slice(1); if (this.allowed_tags[new_tag] && this.allowed_tags[new_tag].supported_prefixes.includes(custom_prefix)) { token_prefix = custom_prefix; tag = new_tag; } } } } // Remove exclusion if the tag doesn't support that prefix if (!this.allowed_tags[tag] || !(this.allowed_tags[tag].supported_prefixes || []).includes(this.EXCLUSION_PREFIX)) { is_exclusion = false; } term = term || ''; if (term.length > 0) { if (/^".+"$/.test(term)) { term = term.trim().replace(/^"/, '').replace(/"$/, '').trim(); } if (/^'.+'$/.test(term)) { term = term.trim().replace(/^'/, '').replace(/'$/, '').trim(); } } if (this.isAllowedTag(tag)) { result.tokens.push(new SearchToken(term, tag, is_exclusion, pos++, token[0], token_prefix)); } else if (!this.drop_unallowed_tags) { result.tokens.push(new SearchToken(token[0], null, false, pos++, token[0])); } } return result; } }