UNPKG

@senx/discovery-widgets

Version:

Discovery Widgets Elements

1,331 lines (1,193 loc) 103 kB
import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client'; import { c as commonjsGlobal, P as Param, U as Utils, G as GTSLib, L as Logger, v as v4 } from './utils.js'; import { d as domtoimage } from './dom-to-image.js'; import { d as defineCustomElement$4 } from './discovery-input-chips2.js'; import { d as defineCustomElement$3 } from './discovery-input-chips-chip2.js'; import { d as defineCustomElement$2 } from './discovery-input-date-range2.js'; import { d as defineCustomElement$1 } from './discovery-slider2.js'; var autoComplete$1 = {exports: {}}; (function (module, exports) { (function (global, factory) { module.exports = factory() ; })(commonjsGlobal, (function () { function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var n = 0, F = function () {}; return { s: F, n: function () { return n >= r.length ? { done: !0 } : { done: !1, value: r[n++] }; }, e: function (r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function () { t = t.call(r); }, n: function () { var r = t.next(); return a = r.done, r; }, e: function (r) { u = !0, o = r; }, f: function () { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } 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 _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } 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 _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } var select$1 = function select(element) { return typeof element === "string" ? document.querySelector(element) : element(); }; var create = function create(tag, options) { var el = typeof tag === "string" ? document.createElement(tag) : tag; for (var key in options) { var val = options[key]; if (key === "inside") { val.append(el); } else if (key === "dest") { select$1(val[0]).insertAdjacentElement(val[1], el); } else if (key === "around") { var ref = val; ref.parentNode.insertBefore(el, ref); el.append(ref); if (ref.getAttribute("autofocus") != null) ref.focus(); } else if (key in el) { el[key] = val; } else { el.setAttribute(key, val); } } return el; }; var getQuery = function getQuery(field) { return field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement ? field.value : field.innerHTML; }; var format = function format(value, diacritics) { value = String(value).toLowerCase(); return diacritics ? value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").normalize("NFC") : value; }; var debounce = function debounce(callback, duration) { var timer; return function () { clearTimeout(timer); timer = setTimeout(function () { return callback(); }, duration); }; }; var checkTrigger = function checkTrigger(query, condition, threshold) { return condition ? condition(query) : query.length >= threshold; }; var mark = function mark(value, cls) { return create("mark", _objectSpread2({ innerHTML: value }, typeof cls === "string" && { "class": cls })).outerHTML; }; var configure = (function (ctx) { var name = ctx.name, options = ctx.options, resultsList = ctx.resultsList, resultItem = ctx.resultItem; for (var option in options) { if (_typeof(options[option]) === "object") { if (!ctx[option]) ctx[option] = {}; for (var subOption in options[option]) { ctx[option][subOption] = options[option][subOption]; } } else { ctx[option] = options[option]; } } ctx.selector = ctx.selector || "#" + name; resultsList.destination = resultsList.destination || ctx.selector; resultsList.id = resultsList.id || name + "_list_" + ctx.id; resultItem.id = resultItem.id || name + "_result"; ctx.input = select$1(ctx.selector); }); var eventEmitter = (function (name, ctx) { ctx.input.dispatchEvent(new CustomEvent(name, { bubbles: true, detail: ctx.feedback, cancelable: true })); }); var search = (function (query, record, options) { var _ref = options || {}, mode = _ref.mode, diacritics = _ref.diacritics, highlight = _ref.highlight; var nRecord = format(record, diacritics); record = String(record); query = format(query, diacritics); if (mode === "loose") { query = query.replace(/ /g, ""); var qLength = query.length; var cursor = 0; var match = Array.from(record).map(function (character, index) { if (cursor < qLength && nRecord[index] === query[cursor]) { character = highlight ? mark(character, highlight) : character; cursor++; } return character; }).join(""); if (cursor === qLength) return match; } else { var _match = nRecord.indexOf(query); if (~_match) { query = record.substring(_match, _match + query.length); _match = highlight ? record.replace(query, mark(query, highlight)) : record; return _match; } } }); var getData = function getData(ctx, query) { return new Promise(function ($return, $error) { var data; data = ctx.data; if (data.cache && data.store) return $return(); return new Promise(function ($return, $error) { if (typeof data.src === "function") { return new Promise(function ($return, $error) { if (data.src.constructor.name === "AsyncFunction") { return data.src(query).then($return, $error); } return $return(data.src(query)); }).then($return, $error); } return $return(data.src); }).then(function ($await_7) { try { ctx.feedback = data.store = $await_7; eventEmitter("response", ctx); return $return(); } catch ($boundEx) { return $error($boundEx); } }, $error); }); }; var findMatches = function findMatches(query, ctx) { var data = ctx.data, searchEngine = ctx.searchEngine; var matches = []; data.store.forEach(function (value, index) { var find = function find(key) { var record = key ? value[key] : value; var match = typeof searchEngine === "function" ? searchEngine(query, record) : search(query, record, { mode: searchEngine, diacritics: ctx.diacritics, highlight: ctx.resultItem.highlight }); if (!match) return; var result = { match: match, value: value }; if (key) result.key = key; matches.push(result); }; if (data.keys) { var _iterator = _createForOfIteratorHelper(data.keys), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var key = _step.value; find(key); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } else { find(); } }); if (data.filter) matches = data.filter(matches); var results = matches.slice(0, ctx.resultsList.maxResults); ctx.feedback = { query: query, matches: matches, results: results }; eventEmitter("results", ctx); }; var Expand = "aria-expanded"; var Active = "aria-activedescendant"; var Selected = "aria-selected"; var feedback = function feedback(ctx, index) { ctx.feedback.selection = _objectSpread2({ index: index }, ctx.feedback.results[index]); }; var render = function render(ctx) { var resultsList = ctx.resultsList, list = ctx.list, resultItem = ctx.resultItem, feedback = ctx.feedback; var matches = feedback.matches, results = feedback.results; ctx.cursor = -1; list.innerHTML = ""; if (matches.length || resultsList.noResults) { var fragment = new DocumentFragment(); results.forEach(function (result, index) { var element = create(resultItem.tag, _objectSpread2({ id: "".concat(resultItem.id, "_").concat(index), role: "option", innerHTML: result.match, inside: fragment }, resultItem["class"] && { "class": resultItem["class"] })); if (resultItem.element) resultItem.element(element, result); }); list.append(fragment); if (resultsList.element) resultsList.element(list, feedback); open(ctx); } else { close(ctx); } }; var open = function open(ctx) { if (ctx.isOpen) return; (ctx.wrapper || ctx.input).setAttribute(Expand, true); ctx.list.removeAttribute("hidden"); ctx.isOpen = true; eventEmitter("open", ctx); }; var close = function close(ctx) { if (!ctx.isOpen) return; (ctx.wrapper || ctx.input).setAttribute(Expand, false); ctx.input.setAttribute(Active, ""); ctx.list.setAttribute("hidden", ""); ctx.isOpen = false; eventEmitter("close", ctx); }; var goTo = function goTo(index, ctx) { var resultItem = ctx.resultItem; var results = ctx.list.getElementsByTagName(resultItem.tag); var cls = resultItem.selected ? resultItem.selected.split(" ") : false; if (ctx.isOpen && results.length) { var _results$index$classL; var state = ctx.cursor; if (index >= results.length) index = 0; if (index < 0) index = results.length - 1; ctx.cursor = index; if (state > -1) { var _results$state$classL; results[state].removeAttribute(Selected); if (cls) (_results$state$classL = results[state].classList).remove.apply(_results$state$classL, _toConsumableArray(cls)); } results[index].setAttribute(Selected, true); if (cls) (_results$index$classL = results[index].classList).add.apply(_results$index$classL, _toConsumableArray(cls)); ctx.input.setAttribute(Active, results[ctx.cursor].id); ctx.list.scrollTop = results[index].offsetTop - ctx.list.clientHeight + results[index].clientHeight + 5; ctx.feedback.cursor = ctx.cursor; feedback(ctx, index); eventEmitter("navigate", ctx); } }; var next = function next(ctx) { goTo(ctx.cursor + 1, ctx); }; var previous = function previous(ctx) { goTo(ctx.cursor - 1, ctx); }; var select = function select(ctx, event, index) { index = index >= 0 ? index : ctx.cursor; if (index < 0) return; ctx.feedback.event = event; feedback(ctx, index); eventEmitter("selection", ctx); close(ctx); }; var click = function click(event, ctx) { var itemTag = ctx.resultItem.tag.toUpperCase(); var items = Array.from(ctx.list.querySelectorAll(itemTag)); var item = event.target.closest(itemTag); if (item && item.nodeName === itemTag) { select(ctx, event, items.indexOf(item)); } }; var navigate = function navigate(event, ctx) { switch (event.keyCode) { case 40: case 38: event.preventDefault(); event.keyCode === 40 ? next(ctx) : previous(ctx); break; case 13: if (!ctx.submit) event.preventDefault(); if (ctx.cursor >= 0) select(ctx, event); break; case 9: if (ctx.resultsList.tabSelect && ctx.cursor >= 0) select(ctx, event); break; case 27: ctx.input.value = ""; eventEmitter('clear', ctx); close(ctx); break; } }; function start (ctx, q) { var _this = this; return new Promise(function ($return, $error) { var queryVal, condition; queryVal = q || getQuery(ctx.input); queryVal = ctx.query ? ctx.query(queryVal) : queryVal; condition = checkTrigger(queryVal, ctx.trigger, ctx.threshold); if (condition) { return getData(ctx, queryVal).then(function ($await_2) { try { if (ctx.feedback instanceof Error) return $return(); findMatches(queryVal, ctx); if (ctx.resultsList) render(ctx); return $If_1.call(_this); } catch ($boundEx) { return $error($boundEx); } }, $error); } else { close(ctx); return $If_1.call(_this); } function $If_1() { return $return(); } }); } var eventsManager = function eventsManager(events, callback) { for (var element in events) { for (var event in events[element]) { callback(element, event); } } }; var addEvents = function addEvents(ctx) { var events = ctx.events; var run = debounce(function () { return start(ctx); }, ctx.debounce); var publicEvents = ctx.events = _objectSpread2({ input: _objectSpread2({}, events && events.input) }, ctx.resultsList && { list: events ? _objectSpread2({}, events.list) : {} }); var privateEvents = { input: { input: function input() { run(); }, keydown: function keydown(event) { navigate(event, ctx); }, blur: function blur() { close(ctx); } }, list: { mousedown: function mousedown(event) { event.preventDefault(); }, click: function click$1(event) { click(event, ctx); } } }; eventsManager(privateEvents, function (element, event) { if (!ctx.resultsList && event !== "input") return; if (publicEvents[element][event]) return; publicEvents[element][event] = privateEvents[element][event]; }); eventsManager(publicEvents, function (element, event) { ctx[element].addEventListener(event, publicEvents[element][event]); }); }; var removeEvents = function removeEvents(ctx) { eventsManager(ctx.events, function (element, event) { ctx[element].removeEventListener(event, ctx.events[element][event]); }); }; function init (ctx) { var _this = this; return new Promise(function ($return, $error) { var placeHolder, resultsList, parentAttrs; placeHolder = ctx.placeHolder; resultsList = ctx.resultsList; parentAttrs = { role: "combobox", "aria-owns": resultsList.id, "aria-haspopup": true, "aria-expanded": false }; create(ctx.input, _objectSpread2(_objectSpread2({ "aria-controls": resultsList.id, "aria-autocomplete": "both" }, placeHolder && { placeholder: placeHolder }), !ctx.wrapper && _objectSpread2({}, parentAttrs))); if (ctx.wrapper) ctx.wrapper = create("div", _objectSpread2({ around: ctx.input, "class": ctx.name + "_wrapper" }, parentAttrs)); if (resultsList) ctx.list = create(resultsList.tag, _objectSpread2({ dest: [resultsList.destination, resultsList.position], id: resultsList.id, role: "listbox", hidden: "hidden" }, resultsList["class"] && { "class": resultsList["class"] })); addEvents(ctx); if (ctx.data.cache) { return getData(ctx).then(function ($await_2) { try { return $If_1.call(_this); } catch ($boundEx) { return $error($boundEx); } }, $error); } function $If_1() { eventEmitter("init", ctx); return $return(); } return $If_1.call(_this); }); } function extend (autoComplete) { var prototype = autoComplete.prototype; prototype.init = function () { init(this); }; prototype.start = function (query) { start(this, query); }; prototype.unInit = function () { if (this.wrapper) { var parentNode = this.wrapper.parentNode; parentNode.insertBefore(this.input, this.wrapper); parentNode.removeChild(this.wrapper); } removeEvents(this); }; prototype.open = function () { open(this); }; prototype.close = function () { close(this); }; prototype.goTo = function (index) { goTo(index, this); }; prototype.next = function () { next(this); }; prototype.previous = function () { previous(this); }; prototype.select = function (index) { select(this, null, index); }; prototype.search = function (query, record, options) { return search(query, record, options); }; } function autoComplete(config) { this.options = config; this.id = autoComplete.instances = (autoComplete.instances || 0) + 1; this.name = "autoComplete"; this.wrapper = 1; this.threshold = 1; this.debounce = 0; this.resultsList = { position: "afterend", tag: "ul", maxResults: 5 }; this.resultItem = { tag: "li" }; configure(this); extend.call(this, autoComplete); init(this); } return autoComplete; })); }(autoComplete$1)); const autoComplete = autoComplete$1.exports; var fuzzysort$1 = {exports: {}}; (function (module) { ((root, UMD) => { if(module.exports) module.exports = UMD(); else root['fuzzysort'] = UMD(); })(commonjsGlobal, _ => { var single = (search, target) => { if(!search || !target) return NULL var preparedSearch = getPreparedSearch(search); if(!isPrepared(target)) target = getPrepared(target); var searchBitflags = preparedSearch.bitflags; if((searchBitflags & target._bitflags) !== searchBitflags) return NULL return algorithm(preparedSearch, target) }; var go = (search, targets, options) => { if(!search) return options?.all ? all(targets, options) : noResults var preparedSearch = getPreparedSearch(search); var searchBitflags = preparedSearch.bitflags; var containsSpace = preparedSearch.containsSpace; var threshold = denormalizeScore( options?.threshold || 0 ); var limit = options?.limit || INFINITY; var resultsLen = 0; var limitedCount = 0; var targetsLen = targets.length; function push_result(result) { if(resultsLen < limit) { q.add(result); ++resultsLen; } else { ++limitedCount; if(result._score > q.peek()._score) q.replaceTop(result); } } // This code is copy/pasted 3 times for performance reasons [options.key, options.keys, no keys] // options.key if(options?.key) { var key = options.key; for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]; var target = getValue(obj, key); if(!target) continue if(!isPrepared(target)) target = getPrepared(target); if((searchBitflags & target._bitflags) !== searchBitflags) continue var result = algorithm(preparedSearch, target); if(result === NULL) continue if(result._score < threshold) continue result.obj = obj; push_result(result); } // options.keys } else if(options?.keys) { var keys = options.keys; var keysLen = keys.length; outer: for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]; { // early out based on bitflags var keysBitflags = 0; for (var keyI = 0; keyI < keysLen; ++keyI) { var key = keys[keyI]; var target = getValue(obj, key); if(!target) { tmpTargets[keyI] = noTarget; continue } if(!isPrepared(target)) target = getPrepared(target); tmpTargets[keyI] = target; keysBitflags |= target._bitflags; } if((searchBitflags & keysBitflags) !== searchBitflags) continue } if(containsSpace) for(let i=0; i<preparedSearch.spaceSearches.length; i++) keysSpacesBestScores[i] = NEGATIVE_INFINITY; for (var keyI = 0; keyI < keysLen; ++keyI) { target = tmpTargets[keyI]; if(target === noTarget) { tmpResults[keyI] = noTarget; continue } tmpResults[keyI] = algorithm(preparedSearch, target, /*allowSpaces=*/false, /*allowPartialMatch=*/containsSpace); if(tmpResults[keyI] === NULL) { tmpResults[keyI] = noTarget; continue } // todo: this seems weird and wrong. like what if our first match wasn't good. this should just replace it instead of averaging with it // if our second match isn't good we ignore it instead of averaging with it if(containsSpace) for(let i=0; i<preparedSearch.spaceSearches.length; i++) { if(allowPartialMatchScores[i] > -1000) { if(keysSpacesBestScores[i] > NEGATIVE_INFINITY) { var tmp = (keysSpacesBestScores[i] + allowPartialMatchScores[i]) / 4;/*bonus score for having multiple matches*/ if(tmp > keysSpacesBestScores[i]) keysSpacesBestScores[i] = tmp; } } if(allowPartialMatchScores[i] > keysSpacesBestScores[i]) keysSpacesBestScores[i] = allowPartialMatchScores[i]; } } if(containsSpace) { for(let i=0; i<preparedSearch.spaceSearches.length; i++) { if(keysSpacesBestScores[i] === NEGATIVE_INFINITY) continue outer } } else { var hasAtLeast1Match = false; for(let i=0; i < keysLen; i++) { if(tmpResults[i]._score !== NEGATIVE_INFINITY) { hasAtLeast1Match = true; break } } if(!hasAtLeast1Match) continue } var objResults = new KeysResult(keysLen); for(let i=0; i < keysLen; i++) { objResults[i] = tmpResults[i]; } if(containsSpace) { var score = 0; for(let i=0; i<preparedSearch.spaceSearches.length; i++) score += keysSpacesBestScores[i]; } else { // todo could rewrite this scoring to be more similar to when there's spaces // if we match multiple keys give us bonus points var score = NEGATIVE_INFINITY; for(let i=0; i<keysLen; i++) { var result = objResults[i]; if(result._score > -1000) { if(score > NEGATIVE_INFINITY) { var tmp = (score + result._score) / 4;/*bonus score for having multiple matches*/ if(tmp > score) score = tmp; } } if(result._score > score) score = result._score; } } objResults.obj = obj; objResults._score = score; if(options?.scoreFn) { score = options.scoreFn(objResults); if(!score) continue score = denormalizeScore(score); objResults._score = score; } if(score < threshold) continue push_result(objResults); } // no keys } else { for(var i = 0; i < targetsLen; ++i) { var target = targets[i]; if(!target) continue if(!isPrepared(target)) target = getPrepared(target); if((searchBitflags & target._bitflags) !== searchBitflags) continue var result = algorithm(preparedSearch, target); if(result === NULL) continue if(result._score < threshold) continue push_result(result); } } if(resultsLen === 0) return noResults var results = new Array(resultsLen); for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll(); results.total = resultsLen + limitedCount; return results }; // this is written as 1 function instead of 2 for minification. perf seems fine ... // except when minified. the perf is very slow var highlight = (result, open='<b>', close='</b>') => { var callback = typeof open === 'function' ? open : undefined; var target = result.target; var targetLen = target.length; var indexes = result.indexes; var highlighted = ''; var matchI = 0; var indexesI = 0; var opened = false; var parts = []; for(var i = 0; i < targetLen; ++i) { var char = target[i]; if(indexes[indexesI] === i) { ++indexesI; if(!opened) { opened = true; if(callback) { parts.push(highlighted); highlighted = ''; } else { highlighted += open; } } if(indexesI === indexes.length) { if(callback) { highlighted += char; parts.push(callback(highlighted, matchI++)); highlighted = ''; parts.push(target.substr(i+1)); } else { highlighted += char + close + target.substr(i+1); } break } } else { if(opened) { opened = false; if(callback) { parts.push(callback(highlighted, matchI++)); highlighted = ''; } else { highlighted += close; } } } highlighted += char; } return callback ? parts : highlighted }; var prepare = (target) => { if(typeof target === 'number') target = ''+target; else if(typeof target !== 'string') target = ''; var info = prepareLowerInfo(target); return new_result(target, {_targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _bitflags:info.bitflags}) }; var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear(); }; // Below this point is only internal code // Below this point is only internal code // Below this point is only internal code // Below this point is only internal code class Result { get ['indexes']() { return this._indexes.slice(0, this._indexes.len).sort((a,b)=>a-b) } set ['indexes'](indexes) { return this._indexes = indexes } ['highlight'](open, close) { return highlight(this, open, close) } get ['score']() { return normalizeScore(this._score) } set ['score'](score) { this._score = denormalizeScore(score); } } class KeysResult extends Array { get ['score']() { return normalizeScore(this._score) } set ['score'](score) { this._score = denormalizeScore(score); } } var new_result = (target, options) => { const result = new Result(); result['target'] = target; result['obj'] = options.obj ?? NULL; result._score = options._score ?? NEGATIVE_INFINITY; result._indexes = options._indexes ?? []; result._targetLower = options._targetLower ?? ''; result._targetLowerCodes = options._targetLowerCodes ?? NULL; result._nextBeginningIndexes = options._nextBeginningIndexes ?? NULL; result._bitflags = options._bitflags ?? 0; return result }; var normalizeScore = score => { if(score === NEGATIVE_INFINITY) return 0 if(score > 1) return score return Math.E ** ( ((-score + 1)**.04307 - 1) * -2) }; var denormalizeScore = normalizedScore => { if(normalizedScore === 0) return NEGATIVE_INFINITY if(normalizedScore > 1) return normalizedScore return 1 - Math.pow((Math.log(normalizedScore) / -2 + 1), 1 / 0.04307) }; var prepareSearch = (search) => { if(typeof search === 'number') search = ''+search; else if(typeof search !== 'string') search = ''; search = search.trim(); var info = prepareLowerInfo(search); var spaceSearches = []; if(info.containsSpace) { var searches = search.split(/\s+/); searches = [...new Set(searches)]; // distinct for(var i=0; i<searches.length; i++) { if(searches[i] === '') continue var _info = prepareLowerInfo(searches[i]); spaceSearches.push({lowerCodes:_info.lowerCodes, _lower:searches[i].toLowerCase(), containsSpace:false}); } } return {lowerCodes: info.lowerCodes, _lower: info._lower, containsSpace: info.containsSpace, bitflags: info.bitflags, spaceSearches: spaceSearches} }; var getPrepared = (target) => { if(target.length > 999) return prepare(target) // don't cache huge targets var targetPrepared = preparedCache.get(target); if(targetPrepared !== undefined) return targetPrepared targetPrepared = prepare(target); preparedCache.set(target, targetPrepared); return targetPrepared }; var getPreparedSearch = (search) => { if(search.length > 999) return prepareSearch(search) // don't cache huge searches var searchPrepared = preparedSearchCache.get(search); if(searchPrepared !== undefined) return searchPrepared searchPrepared = prepareSearch(search); preparedSearchCache.set(search, searchPrepared); return searchPrepared }; var all = (targets, options) => { var results = []; results.total = targets.length; // this total can be wrong if some targets are skipped var limit = options?.limit || INFINITY; if(options?.key) { for(var i=0;i<targets.length;i++) { var obj = targets[i]; var target = getValue(obj, options.key); if(target == NULL) continue if(!isPrepared(target)) target = getPrepared(target); var result = new_result(target.target, {_score: target._score, obj: obj}); results.push(result); if(results.length >= limit) return results } } else if(options?.keys) { for(var i=0;i<targets.length;i++) { var obj = targets[i]; var objResults = new KeysResult(options.keys.length); for (var keyI = options.keys.length - 1; keyI >= 0; --keyI) { var target = getValue(obj, options.keys[keyI]); if(!target) { objResults[keyI] = noTarget; continue } if(!isPrepared(target)) target = getPrepared(target); target._score = NEGATIVE_INFINITY; target._indexes.len = 0; objResults[keyI] = target; } objResults.obj = obj; objResults._score = NEGATIVE_INFINITY; results.push(objResults); if(results.length >= limit) return results } } else { for(var i=0;i<targets.length;i++) { var target = targets[i]; if(target == NULL) continue if(!isPrepared(target)) target = getPrepared(target); target._score = NEGATIVE_INFINITY; target._indexes.len = 0; results.push(target); if(results.length >= limit) return results } } return results }; var algorithm = (preparedSearch, prepared, allowSpaces=false, allowPartialMatch=false) => { if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared, allowPartialMatch) var searchLower = preparedSearch._lower; var searchLowerCodes = preparedSearch.lowerCodes; var searchLowerCode = searchLowerCodes[0]; var targetLowerCodes = prepared._targetLowerCodes; var searchLen = searchLowerCodes.length; var targetLen = targetLowerCodes.length; var searchI = 0; // where we at var targetI = 0; // where you at var matchesSimpleLen = 0; // very basic fuzzy match; to remove non-matching targets ASAP! // walk through target. find sequential matches. // if all chars aren't found then exit for(;;) { var isMatch = searchLowerCode === targetLowerCodes[targetI]; if(isMatch) { matchesSimple[matchesSimpleLen++] = targetI; ++searchI; if(searchI === searchLen) break searchLowerCode = searchLowerCodes[searchI]; } ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI } var searchI = 0; var successStrict = false; var matchesStrictLen = 0; var nextBeginningIndexes = prepared._nextBeginningIndexes; if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target); targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1]; // Our target string successfully matched all characters in sequence! // Let's try a more advanced and strict test to improve the score // only count it as a match if it's consecutive or a beginning character! var backtrackCount = 0; if(targetI !== targetLen) for(;;) { if(targetI >= targetLen) { // We failed to find a good spot for this search char, go back to the previous search char and force it forward if(searchI <= 0) break // We failed to push chars forward for a better match ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match --searchI; var lastMatch = matchesStrict[--matchesStrictLen]; targetI = nextBeginningIndexes[lastMatch]; } else { var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI]; if(isMatch) { matchesStrict[matchesStrictLen++] = targetI; ++searchI; if(searchI === searchLen) { successStrict = true; break } ++targetI; } else { targetI = nextBeginningIndexes[targetI]; } } } // check if it's a substring match var substringIndex = searchLen <= 1 ? -1 : prepared._targetLower.indexOf(searchLower, matchesSimple[0]); // perf: this is slow var isSubstring = !!~substringIndex; var isSubstringBeginning = !isSubstring ? false : substringIndex===0 || prepared._nextBeginningIndexes[substringIndex-1] === substringIndex; // if it's a substring match but not at a beginning index, let's try to find a substring starting at a beginning index for a better score if(isSubstring && !isSubstringBeginning) { for(var i=0; i<nextBeginningIndexes.length; i=nextBeginningIndexes[i]) { if(i <= substringIndex) continue for(var s=0; s<searchLen; s++) if(searchLowerCodes[s] !== prepared._targetLowerCodes[i+s]) break if(s === searchLen) { substringIndex = i; isSubstringBeginning = true; break } } } // tally up the score & keep track of matches for highlighting later // if it's a simple match, we'll switch to a substring match if a substring exists // if it's a strict match, we'll switch to a substring match only if that's a better score var calculateScore = matches => { var score = 0; var extraMatchGroupCount = 0; for(var i = 1; i < searchLen; ++i) { if(matches[i] - matches[i-1] !== 1) {score -= matches[i]; ++extraMatchGroupCount;} } var unmatchedDistance = matches[searchLen-1] - matches[0] - (searchLen-1); score -= (12+unmatchedDistance) * extraMatchGroupCount; // penality for more groups if(matches[0] !== 0) score -= matches[0]*matches[0]*.2; // penality for not starting near the beginning if(!successStrict) { score *= 1000; } else { // successStrict on a target with too many beginning indexes loses points for being a bad target var uniqueBeginningIndexes = 1; for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes; if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10; // quite arbitrary numbers here ... } score -= (targetLen - searchLen)/2; // penality for longer targets if(isSubstring) score /= 1+searchLen*searchLen*1; // bonus for being a full substring if(isSubstringBeginning) score /= 1+searchLen*searchLen*1; // bonus for substring starting on a beginningIndex score -= (targetLen - searchLen)/2; // penality for longer targets return score }; if(!successStrict) { if(isSubstring) for(var i=0; i<searchLen; ++i) matchesSimple[i] = substringIndex+i; // at this point it's safe to overwrite matchehsSimple with substr matches var matchesBest = matchesSimple; var score = calculateScore(matchesBest); } else { if(isSubstringBeginning) { for(var i=0; i<searchLen; ++i) matchesSimple[i] = substringIndex+i; // at this point it's safe to overwrite matchehsSimple with substr matches var matchesBest = matchesSimple; var score = calculateScore(matchesSimple); } else { var matchesBest = matchesStrict; var score = calculateScore(matchesStrict); } } prepared._score = score; for(var i = 0; i < searchLen; ++i) prepared._indexes[i] = matchesBest[i]; prepared._indexes.len = searchLen; const result = new Result(); result.target = prepared.target; result._score = prepared._score; result._indexes = prepared._indexes; return result }; var algorithmSpaces = (preparedSearch, target, allowPartialMatch) => { var seen_indexes = new Set(); var score = 0; var result = NULL; var first_seen_index_last_search = 0; var searches = preparedSearch.spaceSearches; var searchesLen = searches.length; var changeslen = 0; // Return _nextBeginningIndexes back to its normal state var resetNextBeginningIndexes = () => { for(let i=changeslen-1; i>=0; i--) target._nextBeginningIndexes[nextBeginningIndexesChanges[i*2 + 0]] = nextBeginningIndexesChanges[i*2 + 1]; }; var hasAtLeast1Match = false; for(var i=0; i<searchesLen; ++i) { allowPartialMatchScores[i] = NEGATIVE_INFINITY; var search = searches[i]; result = algorithm(search, target); if(allowPartialMatch) { if(result === NULL) continue hasAtLeast1Match = true; } else { if(result === NULL) {resetNextBeginningIndexes(); return NULL} } // if not the last search, we need to mutate _nextBeginningIndexes for the next search var isTheLastSearch = i === searchesLen - 1; if(!isTheLastSearch) { var indexes = result._indexes; var indexesIsConsecutiveSubstring = true; for(let i=0; i<indexes.len-1; i++) { if(indexes[i+1] - indexes[i] !== 1) { indexesIsConsecutiveSubstring = false; break; } } if(indexesIsConsecutiveSubstring) { var newBeginningIndex = indexes[indexes.len-1] + 1; var toReplace = target._nextBeginningIndexes[newBeginningIndex-1]; for(let i=newBeginningIndex-1; i>=0; i--) { if(toReplace !== target._nextBeginningIndexes[i]) break target._nextBeginningIndexes[i] = newBeginningIndex; nextBeginningIndexesChanges[changeslen*2 + 0] = i; nextBeginningIndexesChanges[changeslen*2 + 1] = toReplace; changeslen++; } } } score += result._score / searchesLen; allowPartialMatchScores[i] = result._score / searchesLen; // dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h if(result._indexes[0] < first_seen_index_last_search) { score -= (first_seen_index_last_search - result._indexes[0]) * 2; } first_seen_index_last_search = result._indexes[0]; for(var j=0; j<result._indexes.len; ++j) seen_indexes.add(result._indexes[j]); } if(allowPartialMatch && !hasAtLeast1Match) return NULL resetNextBeginningIndexes(); // allows a search with spaces that's an exact substring to score well var allowSpacesResult = algorithm(preparedSearch, target, /*allowSpaces=*/true); if(allowSpacesResult !== NULL && allowSpacesResult._score > score) { if(allowPartialMatch) { for(var i=0; i<searchesLen; ++i) { allowPartialMatchScores[i] = allowSpacesResult._score / searchesLen; } } return allowSpacesResult } if(allowPartialMatch) result = target; result._score = score; var i = 0; for (let index of seen_indexes) result._indexes[i++] = index; result._indexes.len = i; return result }; // we use this instead of just .normalize('NFD').replace(/[\u0300-\u036f]/g, '') because that screws with japanese characters var remove_accents = (str) => str.replace(/\p{Script=Latin}+/gu, match => match.normalize('NFD')).replace(/[\u0300-\u036f]/g, ''); var prepareLowerInfo = (str) => { str = remove_accents(str); var strLen = str.length; var lower = str.toLowerCase(); var lowerCodes = []; // new Array(strLen) sparse array is too slow var bitflags = 0; var containsSpace = false; // space isn't stored in bitflags because of how searching with a space works for(var i = 0; i < strLen; ++i) { var lowerCode = lowerCodes[i] = lower.charCodeAt(i); if(lowerCode === 32) { containsSpace = true; continue // it's important that we don't set any bitflags for space } var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet : lowerCode>=48&&lowerCode<=57 ? 26 // numbers // 3 bits available : lowerCode<=127 ? 30 // other ascii : 31; // other utf8 bitflags |= 1<<bit; } return {lowerCodes:lowerCodes, bitflags:bitflags, containsSpace:containsSpace, _lower:lower} }; var prepareBeginningIndexes = (target) => { var targetLen = target.length; var beginningIndexes = []; var beginningIndexesLen = 0; var wasUpper = false; var wasAlphanum = false; for(var i = 0; i < targetLen; ++i) { var targetCode = target.charCodeAt(i); var isUpper = targetCode>=65&&targetCode<=90; var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57; var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum; wasUpper = isUpper; wasAlphanum = isAlphanum; if(isBeginning) beginningIndexes[beginningIndexesLen++] = i; } return beginningIndexes }; var prepareNextBeginningIndexes = (target) => { target = remove_accents(target); var targetLen = target.length; var beginningIndexes = prepareBeginningIndexes(target); var nextBeginningIndexes = []; // new Array(targetLen) sparse array is too slow var lastIsBeginning = beginningIndexes[0]; var lastIsBeginningI = 0; for(var i = 0; i < targetLen; ++i) { if(lastIsBeginning > i) { nextBeginningIndexes[i] = lastIsBeginning; } else { lastIsBeginning = beginningIndexes[++lastIsBeginningI]; nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning; } } return nextBeginningIndexes }; var preparedCache = new Map(); var preparedSearchCache = new Map(); // the theory behind these being globals is to reduce garbage collection by not making new arrays var matchesSimple = []; var matchesStrict = []; var nextBeginningIndexesChanges = []; // allows straw berry to match strawberry well, by modifying the end of a substring to be considered a beginning index for the rest of the search var keysSpacesBestScores = []; var allowPartialMatchScores = []; var tmpTargets = []; var tmpResults = []; // prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop] // prop = 'key1.key2' 10ms // prop = ['key1', 'key2'] 27ms // prop = obj => obj.tags.join() ??ms var getValue = (obj, prop) => { var tmp = obj[prop]; if(tmp !== undefined) return tmp if(typeof prop === 'function') return prop(obj) // this should run first. but that makes string props slower var segs = prop; if(!Array.isArray(prop)) segs = prop.split('.'); var len = segs.length; var i = -1; while (obj && (++i < len)) obj = obj[segs[i]]; return obj }; var isPrepared = (x) => { return typeof x === 'object' && typeof x._bitflags === 'number' }; var INFINITY = Infinity; var NEGATIVE_INFINITY = -INFINITY; var noResults = []; noResults.total = 0; var NULL = null; var noTarget = prepare(''); // Hacked version of https://github.com/lemire/FastPriorityQueue.js var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c<o;){var s=c+1;a=c,s<o&&e[s]._score<e[c]._score&&(a=s),e[a-1>>1]=e[a],c=1+(a<<1);}for(var f=a-1>>1;a>0&&v._score<e[f]._score;f=(a=f)-1>>1)e[a]=e[f];e[a]=v;};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r._score<e[v]._score;v=(a=v)-1>>1)e[a]=e[v];e[a]=r;}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v();}),a}; var q = fastpriorityqueue(); // reuse this // fuzzysort is written this way for minification. all names are mangeled unless quoted return {'single':single, 'go':go, 'prepare':prepare, 'cleanup':cleanup} }); // UMD }(fuzzysort$1)); const fuzzysort = fuzzysort$1.exports; const discoveryInputCss = "/*!\n * Copyright 2022-2025 SenX S.A.S.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *//*!\n * Copyright 2022-2024 SenX S.A.S.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */.autoComplete_wrapper{display:inline-block;position:relative}.autoComplete_wrapper>input{width:370