diff options
Diffstat (limited to 'help3xsl')
-rw-r--r-- | help3xsl/flexsearch.debug.js | 963 | ||||
-rw-r--r-- | help3xsl/fuzzysort.js | 608 | ||||
-rw-r--r-- | help3xsl/help.js | 37 | ||||
-rw-r--r-- | help3xsl/online_transform.xsl | 2 | ||||
-rw-r--r-- | help3xsl/xap_templ_query.xsl | 2 |
5 files changed, 991 insertions, 621 deletions
diff --git a/help3xsl/flexsearch.debug.js b/help3xsl/flexsearch.debug.js new file mode 100644 index 0000000000..98e658130a --- /dev/null +++ b/help3xsl/flexsearch.debug.js @@ -0,0 +1,963 @@ +/**! + * FlexSearch.js v0.7.2 (Debug) + * Copyright 2018-2021 Nextapps GmbH + * Author: Thomas Wilkerling + * Licence: Apache-2.0 + * https://github.com/nextapps-de/flexsearch + */ +(function(self){'use strict'; +function r(a, b) { + return "undefined" !== typeof a ? a : b; +} +function v(a) { + const b = Array(a); + for (let c = 0; c < a; c++) { + b[c] = w(); + } + return b; +} +function w() { + return Object.create(null); +} +function aa(a, b) { + return b.length - a.length; +} +function x(a) { + return "string" === typeof a; +} +function z(a) { + return "object" === typeof a; +} +function D(a) { + return "function" === typeof a; +} +;function ba(a, b, c, d) { + if (a && (b && (a = E(a, b)), this.matcher && (a = E(a, this.matcher)), this.stemmer && 1 < a.length && (a = E(a, this.stemmer)), d && 1 < a.length && (a = F(a)), c || "" === c)) { + a = a.split(c); + if (this.filter) { + b = this.filter; + c = a.length; + d = []; + for (let e = 0, f = 0; e < c; e++) { + const g = a[e]; + g && !b[g] && (d[f++] = g); + } + a = d; + } + return a; + } + return a; +} +const ca = /[\p{Z}\p{S}\p{P}\p{C}]+/u, da = /[\u0300-\u036f]/g; +function ea(a, b) { + const c = Object.keys(a), d = c.length, e = []; + let f = "", g = 0; + for (let h = 0, k, m; h < d; h++) { + k = c[h], (m = a[k]) ? (e[g++] = G(b ? "(?!\\b)" + k + "(\\b|_)" : k), e[g++] = m) : f += (f ? "|" : "") + k; + } + f && (e[g++] = G(b ? "(?!\\b)(" + f + ")(\\b|_)" : "(" + f + ")"), e[g] = ""); + return e; +} +function E(a, b) { + for (let c = 0, d = b.length; c < d && (a = a.replace(b[c], b[c + 1]), a); c += 2) { + } + return a; +} +function G(a) { + return new RegExp(a, "g"); +} +function F(a) { + let b = "", c = ""; + for (let d = 0, e = a.length, f; d < e; d++) { + (f = a[d]) !== c && (b += c = f); + } + return b; +} +;var ha = {encode:fa, rtl:!1, tokenize:""}; +function fa(a) { + return ba.call(this, a.toLowerCase(), !1, ca, !1); +} +;const ia = {}, I = {}; +function ja(a) { + J(a, "add"); + J(a, "append"); + J(a, "search"); + J(a, "update"); + J(a, "remove"); +} +function J(a, b) { + a[b + "Async"] = function() { + const c = this, d = arguments; + var e = d[d.length - 1]; + let f; + D(e) && (f = e, delete d[d.length - 1]); + e = new Promise(function(g) { + setTimeout(function() { + c.async = !0; + const h = c[b].apply(c, d); + c.async = !1; + g(h); + }); + }); + return f ? (e.then(f), this) : e; + }; +} +;function ka(a, b, c, d) { + const e = a.length; + let f = [], g, h, k = 0; + d && (d = []); + for (let m = e - 1; 0 <= m; m--) { + const p = a[m], u = p.length, q = w(); + let n = !g; + for (let l = 0; l < u; l++) { + const t = p[l], y = t.length; + if (y) { + for (let C = 0, B, A; C < y; C++) { + if (A = t[C], g) { + if (g[A]) { + if (!m) { + if (c) { + c--; + } else { + if (f[k++] = A, k === b) { + return f; + } + } + } + if (m || d) { + q[A] = 1; + } + n = !0; + } + if (d && (h[A] = (B = h[A]) ? ++B : B = 1, B < e)) { + const H = d[B - 2] || (d[B - 2] = []); + H[H.length] = A; + } + } else { + q[A] = 1; + } + } + } + } + if (d) { + g || (h = q); + } else { + if (!n) { + return []; + } + } + g = q; + } + if (d) { + for (let m = d.length - 1, p, u; 0 <= m; m--) { + p = d[m]; + u = p.length; + for (let q = 0, n; q < u; q++) { + if (n = p[q], !g[n]) { + if (c) { + c--; + } else { + if (f[k++] = n, k === b) { + return f; + } + } + g[n] = 1; + } + } + } + } + return f; +} +function la(a, b) { + const c = w(), d = w(), e = []; + for (let f = 0; f < a.length; f++) { + c[a[f]] = 1; + } + for (let f = 0, g; f < b.length; f++) { + g = b[f]; + for (let h = 0, k; h < g.length; h++) { + k = g[h], c[k] && !d[k] && (d[k] = 1, e[e.length] = k); + } + } + return e; +} +;function K(a) { + this.limit = !0 !== a && a; + this.cache = w(); + this.queue = []; +} +function ma(a, b, c) { + z(a) && (a = a.query); + let d = this.cache.get(a); + d || (d = this.search(a, b, c), this.cache.set(a, d)); + return d; +} +K.prototype.set = function(a, b) { + if (!this.cache[a]) { + var c = this.queue.length; + c === this.limit ? delete this.cache[this.queue[c - 1]] : c++; + for (--c; 0 < c; c--) { + this.queue[c] = this.queue[c - 1]; + } + this.queue[0] = a; + } + this.cache[a] = b; +}; +K.prototype.get = function(a) { + const b = this.cache[a]; + if (this.limit && b && (a = this.queue.indexOf(a))) { + const c = this.queue[a - 1]; + this.queue[a - 1] = this.queue[a]; + this.queue[a] = c; + } + return b; +}; +K.prototype.del = function(a) { + for (let b = 0, c, d; b < this.queue.length; b++) { + d = this.queue[b], c = this.cache[d], -1 !== c.indexOf(a) && (this.queue.splice(b--, 1), delete this.cache[d]); + } +}; +const na = {memory:{charset:"latin:extra", resolution:3, minlength:4, fastupdate:!1}, performance:{resolution:3, minlength:3, optimize:!1, context:{depth:2, resolution:1}}, match:{charset:"latin:extra", tokenize:"reverse", }, score:{charset:"latin:advanced", resolution:20, minlength:3, context:{depth:3, resolution:9, }}, "default":{}, }; +function pa(a, b, c, d, e, f) { + setTimeout(function() { + const g = a(c, JSON.stringify(f)); + g && g.then ? g.then(function() { + b.export(a, b, c, d, e + 1); + }) : b.export(a, b, c, d, e + 1); + }); +} +;function L(a, b) { + if (!(this instanceof L)) { + return new L(a); + } + var c; + if (a) { + if (x(a)) { + na[a] || console.warn("Preset not found: " + a), a = na[a]; + } else { + if (c = a.preset) { + c[c] || console.warn("Preset not found: " + c), a = Object.assign({}, c[c], a); + } + } + c = a.charset; + var d = a.lang; + x(c) && (-1 === c.indexOf(":") && (c += ":default"), c = I[c]); + x(d) && (d = ia[d]); + } else { + a = {}; + } + let e, f, g = a.context || {}; + this.encode = a.encode || c && c.encode || fa; + this.register = b || w(); + this.resolution = e = a.resolution || 9; + this.tokenize = b = c && c.tokenize || a.tokenize || "strict"; + this.depth = "strict" === b && g.depth; + this.bidirectional = r(g.bidirectional, !0); + this.optimize = f = r(a.optimize, !0); + this.fastupdate = r(a.fastupdate, !0); + this.minlength = a.minlength || 1; + this.boost = a.boost; + this.map = f ? v(e) : w(); + this.resolution_ctx = e = g.resolution || 1; + this.ctx = f ? v(e) : w(); + this.rtl = c && c.rtl || a.rtl; + this.matcher = (b = a.matcher || d && d.matcher) && ea(b, !1); + this.stemmer = (b = a.stemmer || d && d.stemmer) && ea(b, !0); + if (c = b = a.filter || d && d.filter) { + c = b; + d = w(); + for (let h = 0, k = c.length; h < k; h++) { + d[c[h]] = 1; + } + c = d; + } + this.filter = c; + this.cache = (b = a.cache) && new K(b); +} +L.prototype.append = function(a, b) { + return this.add(a, b, !0); +}; +L.prototype.add = function(a, b, c, d) { + if (b && (a || 0 === a)) { + if (!d && !c && this.register[a]) { + return this.update(a, b); + } + b = this.encode(b); + if (d = b.length) { + const m = w(), p = w(), u = this.depth, q = this.resolution; + for (let n = 0; n < d; n++) { + let l = b[this.rtl ? d - 1 - n : n]; + var e = l.length; + if (l && e >= this.minlength && (u || !p[l])) { + var f = M(q, d, n), g = ""; + switch(this.tokenize) { + case "full": + if (3 < e) { + for (f = 0; f < e; f++) { + for (var h = e; h > f; h--) { + if (h - f >= this.minlength) { + var k = M(q, d, n, e, f); + g = l.substring(f, h); + this.push_index(p, g, k, a, c); + } + } + } + break; + } + case "reverse": + if (2 < e) { + for (h = e - 1; 0 < h; h--) { + g = l[h] + g, g.length >= this.minlength && (k = M(q, d, n, e, h), this.push_index(p, g, k, a, c)); + } + g = ""; + } + case "forward": + if (1 < e) { + for (h = 0; h < e; h++) { + g += l[h], g.length >= this.minlength && this.push_index(p, g, f, a, c); + } + break; + } + default: + if (this.boost && (f = Math.min(f / this.boost(b, l, n) | 0, q - 1)), this.push_index(p, l, f, a, c), u && 1 < d && n < d - 1) { + for (e = w(), g = this.resolution_ctx, f = l, h = Math.min(u + 1, d - n), e[f] = 1, k = 1; k < h; k++) { + if ((l = b[this.rtl ? d - 1 - n - k : n + k]) && l.length >= this.minlength && !e[l]) { + e[l] = 1; + const t = M(g + (d / 2 > g ? 0 : 1), d, n, h - 1, k - 1), y = this.bidirectional && l > f; + this.push_index(m, y ? f : l, t, a, c, y ? l : f); + } + } + } + } + } + } + this.fastupdate || (this.register[a] = 1); + } + } + return this; +}; +function M(a, b, c, d, e) { + return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0; +} +L.prototype.push_index = function(a, b, c, d, e, f) { + let g = f ? this.ctx : this.map; + if (!a[b] || f && !a[b][f]) { + this.optimize && (g = g[c]), f ? (a = a[b] || (a[b] = w()), a[f] = 1, g = g[f] || (g[f] = w())) : a[b] = 1, g = g[b] || (g[b] = []), this.optimize || (g = g[c] || (g[c] = [])), e && -1 !== g.indexOf(d) || (g[g.length] = d, this.fastupdate && (a = this.register[d] || (this.register[d] = []), a[a.length] = g)); + } +}; +L.prototype.search = function(a, b, c) { + c || (!b && z(a) ? (c = a, a = c.query) : z(b) && (c = b)); + let d = [], e; + let f, g = 0; + if (c) { + b = c.limit; + g = c.offset || 0; + var h = c.context; + f = c.suggest; + } + if (a && (a = this.encode(a), e = a.length, 1 < e)) { + c = w(); + var k = []; + for (let p = 0, u = 0, q; p < e; p++) { + if ((q = a[p]) && q.length >= this.minlength && !c[q]) { + if (this.optimize || f || this.map[q]) { + k[u++] = q, c[q] = 1; + } else { + return d; + } + } + } + a = k; + e = a.length; + } + if (!e) { + return d; + } + b || (b = 100); + h = this.depth && 1 < e && !1 !== h; + c = 0; + let m; + h ? (m = a[0], c = 1) : 1 < e && a.sort(aa); + for (let p, u; c < e; c++) { + u = a[c]; + h ? (p = this.add_result(d, f, b, g, 2 === e, u, m), f && !1 === p && d.length || (m = u)) : p = this.add_result(d, f, b, g, 1 === e, u); + if (p) { + return p; + } + if (f && c === e - 1) { + k = d.length; + if (!k) { + if (h) { + h = 0; + c = -1; + continue; + } + return d; + } + if (1 === k) { + return qa(d[0], b, g); + } + } + } + return ka(d, b, g, f); +}; +L.prototype.add_result = function(a, b, c, d, e, f, g) { + let h = [], k = g ? this.ctx : this.map; + this.optimize || (k = ra(k, f, g, this.bidirectional)); + if (k) { + let m = 0; + const p = Math.min(k.length, g ? this.resolution_ctx : this.resolution); + for (let u = 0, q = 0, n, l; u < p; u++) { + if (n = k[u]) { + if (this.optimize && (n = ra(n, f, g, this.bidirectional)), d && n && e && (l = n.length, l <= d ? (d -= l, n = null) : (n = n.slice(d), d = 0)), n && (h[m++] = n, e && (q += n.length, q >= c))) { + break; + } + } + } + if (m) { + if (e) { + return qa(h, c, 0); + } + a[a.length] = h; + return; + } + } + return !b && h; +}; +function qa(a, b, c) { + a = 1 === a.length ? a[0] : [].concat.apply([], a); + return c || a.length > b ? a.slice(c, c + b) : a; +} +function ra(a, b, c, d) { + c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b]; + return a; +} +L.prototype.contain = function(a) { + return !!this.register[a]; +}; +L.prototype.update = function(a, b) { + return this.remove(a).add(a, b); +}; +L.prototype.remove = function(a, b) { + const c = this.register[a]; + if (c) { + if (this.fastupdate) { + for (let d = 0, e; d < c.length; d++) { + e = c[d], e.splice(e.indexOf(a), 1); + } + } else { + N(this.map, a, this.resolution, this.optimize), this.depth && N(this.ctx, a, this.resolution_ctx, this.optimize); + } + b || delete this.register[a]; + this.cache && this.cache.del(a); + } + return this; +}; +function N(a, b, c, d, e) { + let f = 0; + if (a.constructor === Array) { + if (e) { + b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++; + } else { + e = Math.min(a.length, c); + for (let g = 0, h; g < e; g++) { + if (h = a[g]) { + f = N(h, b, c, d, e), d || f || delete a[g]; + } + } + } + } else { + for (let g in a) { + (f = N(a[g], b, c, d, e)) || delete a[g]; + } + } + return f; +} +L.prototype.searchCache = ma; +L.prototype.export = function(a, b, c, d, e) { + let f, g; + switch(e || (e = 0)) { + case 0: + f = "reg"; + if (this.fastupdate) { + g = w(); + for (let h in this.register) { + g[h] = 1; + } + } else { + g = this.register; + } + break; + case 1: + f = "cfg"; + g = {doc:0, opt:this.optimize ? 1 : 0}; + break; + case 2: + f = "map"; + g = this.map; + break; + case 3: + f = "ctx"; + g = this.ctx; + break; + default: + return; + } + pa(a, b || this, c ? c + "." + f : f, d, e, g); + return !0; +}; +L.prototype.import = function(a, b) { + if (b) { + switch(x(b) && (b = JSON.parse(b)), a) { + case "cfg": + this.optimize = !!b.opt; + break; + case "reg": + this.fastupdate = !1; + this.register = b; + break; + case "map": + this.map = b; + break; + case "ctx": + this.ctx = b; + } + } +}; +ja(L.prototype); +function sa(a) { + a = a.data; + var b = self._index; + const c = a.args; + var d = a.task; + switch(d) { + case "init": + d = a.options || {}; + a = a.factory; + b = d.encode; + d.cache = !1; + b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)()); + a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new L(d); + break; + default: + a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a}); + } +} +;let ta = 0; +function O(a) { + if (!(this instanceof O)) { + return new O(a); + } + var b; + a ? D(b = a.encode) && (a.encode = b.toString()) : a = {}; + (b = (self || window)._factory) && (b = b.toString()); + const c = self.exports, d = this; + this.worker = ua(b, c, a.worker); + this.resolver = w(); + if (this.worker) { + if (c) { + this.worker.on("message", function(e) { + d.resolver[e.id](e.msg); + delete d.resolver[e.id]; + }); + } else { + this.worker.onmessage = function(e) { + e = e.data; + d.resolver[e.id](e.msg); + delete d.resolver[e.id]; + }; + } + this.worker.postMessage({task:"init", factory:b, options:a}); + } +} +Q("add"); +Q("append"); +Q("search"); +Q("update"); +Q("remove"); +function Q(a) { + O.prototype[a] = O.prototype[a + "Async"] = function() { + const b = this, c = [].slice.call(arguments); + var d = c[c.length - 1]; + let e; + D(d) && (e = d, c.splice(c.length - 1, 1)); + d = new Promise(function(f) { + setTimeout(function() { + b.resolver[++ta] = f; + b.worker.postMessage({task:a, id:ta, args:c}); + }); + }); + return e ? (d.then(e), this) : d; + }; +} +function ua(a, b, c) { + let d; + try { + d = b ? eval('new (require("worker_threads")["Worker"])("../dist/node/node.js")') : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + sa.toString()], {type:"text/javascript"}))) : new Worker(x(c) ? c : "worker/worker.js", {type:"module"}); + } catch (e) { + } + return d; +} +;function R(a) { + if (!(this instanceof R)) { + return new R(a); + } + var b = a.document || a.doc || a, c; + this.tree = []; + this.field = []; + this.marker = []; + this.register = w(); + this.key = (c = b.key || b.id) && S(c, this.marker) || "id"; + this.fastupdate = r(a.fastupdate, !0); + this.storetree = (c = b.store) && !0 !== c && []; + this.store = c && w(); + this.tag = (c = b.tag) && S(c, this.marker); + this.tagindex = c && w(); + this.cache = (c = a.cache) && new K(c); + a.cache = !1; + this.worker = a.worker; + this.async = !1; + c = w(); + let d = b.index || b.field || b; + x(d) && (d = [d]); + for (let e = 0, f, g; e < d.length; e++) { + f = d[e], x(f) || (g = f, f = f.field), g = z(g) ? Object.assign({}, a, g) : a, this.worker && (c[f] = new O(g), c[f].worker || (this.worker = !1)), this.worker || (c[f] = new L(g, this.register)), this.tree[e] = S(f, this.marker), this.field[e] = f; + } + if (this.storetree) { + for (a = b.store, x(a) && (a = [a]), b = 0; b < a.length; b++) { + this.storetree[b] = S(a[b], this.marker); + } + } + this.index = c; +} +function S(a, b) { + const c = a.split(":"); + let d = 0; + for (let e = 0; e < c.length; e++) { + a = c[e], 0 <= a.indexOf("[]") && (a = a.substring(0, a.length - 2)) && (b[d] = !0), a && (c[d++] = a); + } + d < c.length && (c.length = d); + return 1 < d ? c : c[0]; +} +function T(a, b) { + if (x(b)) { + a = a[b]; + } else { + for (let c = 0; a && c < b.length; c++) { + a = a[b[c]]; + } + } + return a; +} +function U(a, b, c, d, e) { + a = a[e]; + if (d === c.length - 1) { + b[e] = a; + } else { + if (a) { + if (a.constructor === Array) { + for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) { + U(a, b, c, d, e); + } + } else { + b = b[e] || (b[e] = w()), e = c[++d], U(a, b, c, d, e); + } + } + } +} +function V(a, b, c, d, e, f, g, h) { + if (a = a[g]) { + if (d === b.length - 1) { + if (a.constructor === Array) { + if (c[d]) { + for (b = 0; b < a.length; b++) { + e.add(f, a[b], !0, !0); + } + return; + } + a = a.join(" "); + } + e.add(f, a, h, !0); + } else { + if (a.constructor === Array) { + for (g = 0; g < a.length; g++) { + V(a, b, c, d, e, f, g, h); + } + } else { + g = b[++d], V(a, b, c, d, e, f, g, h); + } + } + } +} +R.prototype.add = function(a, b, c) { + z(a) && (b = a, a = T(b, this.key)); + if (b && (a || 0 === a)) { + if (!c && this.register[a]) { + return this.update(a, b); + } + for (let d = 0, e, f; d < this.field.length; d++) { + f = this.field[d], e = this.tree[d], x(e) && (e = [e]), V(b, e, this.marker, 0, this.index[f], a, e[0], c); + } + if (this.tag) { + let d = T(b, this.tag), e = w(); + x(d) && (d = [d]); + for (let f = 0, g, h; f < d.length; f++) { + if (g = d[f], !e[g] && (e[g] = 1, h = this.tagindex[g] || (this.tagindex[g] = []), !c || -1 === h.indexOf(a))) { + if (h[h.length] = a, this.fastupdate) { + const k = this.register[a] || (this.register[a] = []); + k[k.length] = h; + } + } + } + } + if (this.store && (!c || !this.store[a])) { + let d; + if (this.storetree) { + d = w(); + for (let e = 0, f; e < this.storetree.length; e++) { + f = this.storetree[e], x(f) ? d[f] = b[f] : U(b, d, f, 0, f[0]); + } + } + this.store[a] = d || b; + } + } + return this; +}; +R.prototype.append = function(a, b) { + return this.add(a, b, !0); +}; +R.prototype.update = function(a, b) { + return this.remove(a).add(a, b); +}; +R.prototype.remove = function(a) { + z(a) && (a = T(a, this.key)); + if (this.register[a]) { + for (var b = 0; b < this.field.length && (this.index[this.field[b]].remove(a, !this.worker), !this.fastupdate); b++) { + } + if (this.tag && !this.fastupdate) { + for (let c in this.tagindex) { + b = this.tagindex[c]; + const d = b.indexOf(a); + -1 !== d && (1 < b.length ? b.splice(d, 1) : delete this.tagindex[c]); + } + } + this.store && delete this.store[a]; + delete this.register[a]; + } + return this; +}; +R.prototype.search = function(a, b, c, d) { + c || (!b && z(a) ? (c = a, a = c.query) : z(b) && (c = b, b = 0)); + let e = [], f = [], g, h, k, m, p, u, q = 0; + if (c) { + if (c.constructor === Array) { + k = c, c = null; + } else { + k = (g = c.pluck) || c.index || c.field; + m = c.tag; + h = this.store && c.enrich; + p = "and" === c.bool; + b = c.limit || 100; + u = c.offset || 0; + if (m && (x(m) && (m = [m]), !a)) { + for (let l = 0, t; l < m.length; l++) { + if (t = va.call(this, m[l], b, u, h)) { + e[e.length] = t, q++; + } + } + return q ? e : []; + } + x(k) && (k = [k]); + } + } + k || (k = this.field); + p = p && (1 < k.length || m && 1 < m.length); + const n = !d && (this.worker || this.async) && []; + for (let l = 0, t, y, C; l < k.length; l++) { + let B; + y = k[l]; + x(y) || (B = y, y = y.field); + if (n) { + n[l] = this.index[y].searchAsync(a, b, B || c); + } else { + C = (t = d ? d[l] : this.index[y].search(a, b, B || c)) && t.length; + if (m && C) { + const A = []; + let H = 0; + p && (A[0] = [t]); + for (let W = 0, oa, P; W < m.length; W++) { + if (oa = m[W], C = (P = this.tagindex[oa]) && P.length) { + H++, A[A.length] = p ? [P] : P; + } + } + H && (t = p ? ka(A, b || 100, u || 0) : la(t, A), C = t.length); + } + if (C) { + f[q] = y, e[q++] = t; + } else { + if (p) { + return []; + } + } + } + } + if (n) { + const l = this; + return new Promise(function(t) { + Promise.all(n).then(function(y) { + t(l.search(a, b, c, y)); + }); + }); + } + if (!q) { + return []; + } + if (g && (!h || !this.store)) { + return e[0]; + } + for (let l = 0, t; l < f.length; l++) { + t = e[l]; + t.length && h && (t = wa.call(this, t)); + if (g) { + return t; + } + e[l] = {field:f[l], result:t}; + } + return e; +}; +function va(a, b, c, d) { + let e = this.tagindex[a], f = e && e.length - c; + if (f && 0 < f) { + if (f > b || c) { + e = e.slice(c, c + b); + } + d && (e = wa.call(this, e)); + return {tag:a, result:e}; + } +} +function wa(a) { + const b = Array(a.length); + for (let c = 0, d; c < a.length; c++) { + d = a[c], b[c] = {id:d, doc:this.store[d]}; + } + return b; +} +R.prototype.contain = function(a) { + return !!this.register[a]; +}; +R.prototype.get = function(a) { + return this.store[a]; +}; +R.prototype.set = function(a, b) { + this.store[a] = b; + return this; +}; +R.prototype.searchCache = ma; +R.prototype.export = function(a, b, c, d, e) { + e || (e = 0); + d || (d = 0); + if (d < this.field.length) { + const f = this.field[d], g = this.index[f]; + b = this; + setTimeout(function() { + g.export(a, b, e ? f.replace(":", "-") : "", d, e++) || (d++, e = 1, b.export(a, b, f, d, e)); + }); + } else { + let f; + switch(e) { + case 1: + c = "tag"; + f = this.tagindex; + break; + case 2: + c = "store"; + f = this.store; + break; + default: + return; + } + pa(a, this, c, d, e, f); + } +}; +R.prototype.import = function(a, b) { + if (b) { + switch(x(b) && (b = JSON.parse(b)), a) { + case "tag": + this.tagindex = b; + break; + case "reg": + this.fastupdate = !1; + this.register = b; + for (let d = 0, e; d < this.field.length; d++) { + e = this.index[this.field[d]], e.register = b, e.fastupdate = !1; + } + break; + case "store": + this.store = b; + break; + default: + a = a.split("."); + const c = a[0]; + a = a[1]; + c && a && this.index[c].import(a, b); + } + } +}; +ja(R.prototype); +var ya = {encode:xa, rtl:!1, tokenize:""}; +const za = G("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), Aa = G("[\u00e8\u00e9\u00ea\u00eb]"), Ba = G("[\u00ec\u00ed\u00ee\u00ef]"), Ca = G("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), Da = G("[\u00f9\u00fa\u00fb\u00fc\u0171]"), Ea = G("[\u00fd\u0177\u00ff]"), Fa = G("\u00f1"), Ga = G("[\u00e7c]"), Ha = G("\u00df"), Ia = G(" & "), Ja = [za, "a", Aa, "e", Ba, "i", Ca, "o", Da, "u", Ea, "y", Fa, "n", Ga, "k", Ha, "s", Ia, " and "]; +function xa(a) { + var b = a = "" + a; + b.normalize && (b = b.normalize("NFD").replace(da, "")); + return ba.call(this, b.toLowerCase(), !a.normalize && Ja, ca, !1); +} +;var La = {encode:Ka, rtl:!1, tokenize:"strict"}; +const Ma = /[^a-z0-9]+/, Na = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"}; +function Ka(a) { + a = xa.call(this, a).join(" "); + const b = []; + if (a) { + const c = a.split(Ma), d = c.length; + for (let e = 0, f, g = 0; e < d; e++) { + if ((a = c[e]) && (!this.filter || !this.filter[a])) { + f = a[0]; + let h = Na[f] || f, k = h; + for (let m = 1; m < a.length; m++) { + f = a[m]; + const p = Na[f] || f; + p && p !== k && (h += p, k = p); + } + b[g++] = h; + } + } + } + return b; +} +;var Pa = {encode:Oa, rtl:!1, tokenize:""}; +const Qa = G("ae"), Ra = G("oe"), Sa = G("sh"), Ta = G("th"), Ua = G("ph"), Va = G("pf"), Wa = [Qa, "a", Ra, "o", Sa, "s", Ta, "t", Ua, "f", Va, "f", G("(?![aeo])h(?![aeo])"), "", G("(?!^[aeo])h(?!^[aeo])"), ""]; +function Oa(a, b) { + a && (a = Ka.call(this, a).join(" "), 2 < a.length && (a = E(a, Wa)), b || (1 < a.length && (a = F(a)), a && (a = a.split(" ")))); + return a; +} +;var Ya = {encode:Xa, rtl:!1, tokenize:""}; +const Za = G("(?!\\b)[aeo]"); +function Xa(a) { + a && (a = Oa.call(this, a, !0), 1 < a.length && (a = a.replace(Za, "")), 1 < a.length && (a = F(a)), a && (a = a.split(" "))); + return a; +} +;I["latin:default"] = ha; +I["latin:simple"] = ya; +I["latin:balance"] = La; +I["latin:advanced"] = Pa; +I["latin:extra"] = Ya; +const X = self; +let Y; +const Z = {Index:L, Document:R, Worker:O, registerCharset:function(a, b) { + I[a] = b; +}, registerLanguage:function(a, b) { + ia[a] = b; +}}; +(Y = X.define) && Y.amd ? Y([], function() { + return Z; +}) : X.exports ? X.exports = Z : X.FlexSearch = Z; +}(this)); diff --git a/help3xsl/fuzzysort.js b/help3xsl/fuzzysort.js deleted file mode 100644 index 71f1733903..0000000000 --- a/help3xsl/fuzzysort.js +++ /dev/null @@ -1,608 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Stephen Kamenar - -WHAT: SublimeText-like Fuzzy Search - -USAGE: - fuzzysort.single('fs', 'Fuzzy Search') // {score: -16} - fuzzysort.single('test', 'test') // {score: 0} - fuzzysort.single('doesnt exist', 'target') // null - - fuzzysort.go('mr', ['Monitor.cpp', 'MeshRenderer.cpp']) - // [{score: -18, target: "MeshRenderer.cpp"}, {score: -6009, target: "Monitor.cpp"}] - - fuzzysort.highlight(fuzzysort.single('fs', 'Fuzzy Search'), '<b>', '</b>') - // <b>F</b>uzzy <b>S</b>earch -*/ - -// UMD (Universal Module Definition) for fuzzysort -;(function(root, UMD) { - if(typeof define === 'function' && define.amd) define([], UMD) - else if(typeof module === 'object' && module.exports) module.exports = UMD() - else root.fuzzysort = UMD() -})(this, function UMD() { function fuzzysortNew(instanceOptions) { - - var fuzzysort = { - - single: function(search, target, options) { - if(!search) return null - if(!isObj(search)) search = fuzzysort.getPreparedSearch(search) - - if(!target) return null - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo - : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo - : true - var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo - return algorithm(search, target, search[0]) - // var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 - // var result = algorithm(search, target, search[0]) - // if(result === null) return null - // if(result.score < threshold) return null - // return result - }, - - go: function(search, targets, options) { - if(!search) return noResults - search = fuzzysort.prepareSearch(search) - var searchLowerCode = search[0] - - var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 - var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991 - var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo - : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo - : true - var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo - var resultsLen = 0; var limitedCount = 0 - var targetsLen = targets.length - - // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys] - - // options.keys - if(options && options.keys) { - var scoreFn = options.scoreFn || defaultScoreFn - var keys = options.keys - var keysLen = keys.length - for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i] - var objResults = new Array(keysLen) - for (var keyI = keysLen - 1; keyI >= 0; --keyI) { - var key = keys[keyI] - var target = getValue(obj, key) - if(!target) { objResults[keyI] = null; continue } - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - objResults[keyI] = algorithm(search, target, searchLowerCode) - } - objResults.obj = obj // before scoreFn so scoreFn can use it - var score = scoreFn(objResults) - if(score === null) continue - if(score < threshold) continue - objResults.score = score - if(resultsLen < limit) { q.add(objResults); ++resultsLen } - else { - ++limitedCount - if(score > q.peek().score) q.replaceTop(objResults) - } - } - - // options.key - } else if(options && options.key) { - var key = options.key - for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i] - var target = getValue(obj, key) - if(!target) continue - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - var result = algorithm(search, target, searchLowerCode) - if(result === null) continue - if(result.score < threshold) continue - - // have to clone result so duplicate targets from different obj can each reference the correct obj - result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj} // hidden - - if(resultsLen < limit) { q.add(result); ++resultsLen } - else { - ++limitedCount - if(result.score > q.peek().score) q.replaceTop(result) - } - } - - // no keys - } else { - for(var i = targetsLen - 1; i >= 0; --i) { var target = targets[i] - if(!target) continue - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - var result = algorithm(search, target, searchLowerCode) - if(result === null) continue - if(result.score < threshold) continue - if(resultsLen < limit) { q.add(result); ++resultsLen } - else { - ++limitedCount - if(result.score > q.peek().score) q.replaceTop(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 - }, - - goAsync: function(search, targets, options) { - var canceled = false - var p = new Promise(function(resolve, reject) { - if(!search) return resolve(noResults) - search = fuzzysort.prepareSearch(search) - var searchLowerCode = search[0] - - var q = fastpriorityqueue() - var iCurrent = targets.length - 1 - var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 - var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991 - var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo - : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo - : true - var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo - var resultsLen = 0; var limitedCount = 0 - function step() { - if(canceled) return reject('canceled') - - var startMs = Date.now() - - // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys] - - // options.keys - if(options && options.keys) { - var scoreFn = options.scoreFn || defaultScoreFn - var keys = options.keys - var keysLen = keys.length - for(; iCurrent >= 0; --iCurrent) { var obj = targets[iCurrent] - var objResults = new Array(keysLen) - for (var keyI = keysLen - 1; keyI >= 0; --keyI) { - var key = keys[keyI] - var target = getValue(obj, key) - if(!target) { objResults[keyI] = null; continue } - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - objResults[keyI] = algorithm(search, target, searchLowerCode) - } - objResults.obj = obj // before scoreFn so scoreFn can use it - var score = scoreFn(objResults) - if(score === null) continue - if(score < threshold) continue - objResults.score = score - if(resultsLen < limit) { q.add(objResults); ++resultsLen } - else { - ++limitedCount - if(score > q.peek().score) q.replaceTop(objResults) - } - - if(iCurrent%1000/*itemsPerCheck*/ === 0) { - if(Date.now() - startMs >= 10/*asyncInterval*/) { - isNode?setImmediate(step):setTimeout(step) - return - } - } - } - - // options.key - } else if(options && options.key) { - var key = options.key - for(; iCurrent >= 0; --iCurrent) { var obj = targets[iCurrent] - var target = getValue(obj, key) - if(!target) continue - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - var result = algorithm(search, target, searchLowerCode) - if(result === null) continue - if(result.score < threshold) continue - - // have to clone result so duplicate targets from different obj can each reference the correct obj - result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj} // hidden - - if(resultsLen < limit) { q.add(result); ++resultsLen } - else { - ++limitedCount - if(result.score > q.peek().score) q.replaceTop(result) - } - - if(iCurrent%1000/*itemsPerCheck*/ === 0) { - if(Date.now() - startMs >= 10/*asyncInterval*/) { - isNode?setImmediate(step):setTimeout(step) - return - } - } - } - - // no keys - } else { - for(; iCurrent >= 0; --iCurrent) { var target = targets[iCurrent] - if(!target) continue - if(!isObj(target)) target = fuzzysort.getPrepared(target) - - var result = algorithm(search, target, searchLowerCode) - if(result === null) continue - if(result.score < threshold) continue - if(resultsLen < limit) { q.add(result); ++resultsLen } - else { - ++limitedCount - if(result.score > q.peek().score) q.replaceTop(result) - } - - if(iCurrent%1000/*itemsPerCheck*/ === 0) { - if(Date.now() - startMs >= 10/*asyncInterval*/) { - isNode?setImmediate(step):setTimeout(step) - return - } - } - } - } - - if(resultsLen === 0) return resolve(noResults) - var results = new Array(resultsLen) - for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() - results.total = resultsLen + limitedCount - resolve(results) - } - - isNode?setImmediate(step):step() - }) - p.cancel = function() { canceled = true } - return p - }, - - highlight: function(result, hOpen, hClose) { - if(result === null) return null - if(hOpen === undefined) hOpen = '<b>' - if(hClose === undefined) hClose = '</b>' - var highlighted = '' - var matchesIndex = 0 - var opened = false - var target = result.target - var targetLen = target.length - var matchesBest = result.indexes - for(var i = 0; i < targetLen; ++i) { var char = target[i] - if(matchesBest[matchesIndex] === i) { - ++matchesIndex - if(!opened) { opened = true - highlighted += hOpen - } - - if(matchesIndex === matchesBest.length) { - highlighted += char + hClose + target.substr(i+1) - break - } - } else { - if(opened) { opened = false - highlighted += hClose - } - } - highlighted += char - } - - return highlighted - }, - - prepare: function(target) { - if(!target) return - return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:null, score:null, indexes:null, obj:null} // hidden - }, - prepareSlow: function(target) { - if(!target) return - return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:fuzzysort.prepareNextBeginningIndexes(target), score:null, indexes:null, obj:null} // hidden - }, - prepareSearch: function(search) { - if(!search) return - return fuzzysort.prepareLowerCodes(search) - }, - - - - // 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 - - - - getPrepared: function(target) { - if(target.length > 999) return fuzzysort.prepare(target) // don't cache huge targets - var targetPrepared = preparedCache.get(target) - if(targetPrepared !== undefined) return targetPrepared - targetPrepared = fuzzysort.prepare(target) - preparedCache.set(target, targetPrepared) - return targetPrepared - }, - getPreparedSearch: function(search) { - if(search.length > 999) return fuzzysort.prepareSearch(search) // don't cache huge searches - var searchPrepared = preparedSearchCache.get(search) - if(searchPrepared !== undefined) return searchPrepared - searchPrepared = fuzzysort.prepareSearch(search) - preparedSearchCache.set(search, searchPrepared) - return searchPrepared - }, - - algorithm: function(searchLowerCodes, prepared, searchLowerCode) { - 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 typoSimpleI = 0 - 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[typoSimpleI===0?searchI : (typoSimpleI===searchI?searchI+1 : (typoSimpleI===searchI-1?searchI-1 : searchI))] - } - - ++targetI; if(targetI >= targetLen) { // Failed to find searchI - // Check for typo or exit - // we go as far as possible before trying to transpose - // then we transpose backwards until we reach the beginning - for(;;) { - if(searchI <= 1) return null // not allowed to transpose first char - if(typoSimpleI === 0) { // we haven't tried to transpose yet - --searchI - var searchLowerCodeNew = searchLowerCodes[searchI] - if(searchLowerCode === searchLowerCodeNew) continue // doesn't make sense to transpose a repeat char - typoSimpleI = searchI - } else { - if(typoSimpleI === 1) return null // reached the end of the line for transposing - --typoSimpleI - searchI = typoSimpleI - searchLowerCode = searchLowerCodes[searchI + 1] - var searchLowerCodeNew = searchLowerCodes[searchI] - if(searchLowerCode === searchLowerCodeNew) continue // doesn't make sense to transpose a repeat char - } - matchesSimpleLen = searchI - targetI = matchesSimple[matchesSimpleLen - 1] + 1 - break - } - } - } - - var searchI = 0 - var typoStrictI = 0 - var successStrict = false - var matchesStrictLen = 0 - - var nextBeginningIndexes = prepared._nextBeginningIndexes - if(nextBeginningIndexes === null) nextBeginningIndexes = prepared._nextBeginningIndexes = fuzzysort.prepareNextBeginningIndexes(prepared.target) - var firstPossibleI = 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! - 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) { // We failed to push chars forward for a better match - // transpose, starting from the beginning - ++typoStrictI; if(typoStrictI > searchLen-2) break - if(searchLowerCodes[typoStrictI] === searchLowerCodes[typoStrictI+1]) continue // doesn't make sense to transpose a repeat char - targetI = firstPossibleI - continue - } - - --searchI - var lastMatch = matchesStrict[--matchesStrictLen] - targetI = nextBeginningIndexes[lastMatch] - - } else { - var isMatch = searchLowerCodes[typoStrictI===0?searchI : (typoStrictI===searchI?searchI+1 : (typoStrictI===searchI-1?searchI-1 : searchI))] === targetLowerCodes[targetI] - if(isMatch) { - matchesStrict[matchesStrictLen++] = targetI - ++searchI; if(searchI === searchLen) { successStrict = true; break } - ++targetI - } else { - targetI = nextBeginningIndexes[targetI] - } - } - } - - { // tally up the score & keep track of matches for highlighting later - if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen } - else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen } - var score = 0 - var lastTargetI = -1 - for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i] - // score only goes down if they're not consecutive - if(lastTargetI !== targetI - 1) score -= targetI - lastTargetI = targetI - } - if(!successStrict) { - score *= 1000 - if(typoSimpleI !== 0) score += -20/*typoPenalty*/ - } else { - if(typoStrictI !== 0) score += -20/*typoPenalty*/ - } - score -= targetLen - searchLen - prepared.score = score - prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) prepared.indexes[i] = matchesBest[i] - - return prepared - } - }, - - algorithmNoTypo: function(searchLowerCodes, prepared, searchLowerCode) { - 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 = fuzzysort.prepareNextBeginningIndexes(prepared.target) - var firstPossibleI = 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! - 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 - - --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] - } - } - } - - { // tally up the score & keep track of matches for highlighting later - if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen } - else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen } - var score = 0 - var lastTargetI = -1 - for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i] - // score only goes down if they're not consecutive - if(lastTargetI !== targetI - 1) score -= targetI - lastTargetI = targetI - } - if(!successStrict) score *= 1000 - score -= targetLen - searchLen - prepared.score = score - prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) prepared.indexes[i] = matchesBest[i] - - return prepared - } - }, - - prepareLowerCodes: function(str) { - var strLen = str.length - var lowerCodes = [] // new Array(strLen) sparse array is too slow - var lower = str.toLowerCase() - for(var i = 0; i < strLen; ++i) lowerCodes[i] = lower.charCodeAt(i) - return lowerCodes - }, - prepareBeginningIndexes: function(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 - }, - prepareNextBeginningIndexes: function(target) { - var targetLen = target.length - var beginningIndexes = fuzzysort.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 - }, - - cleanup: cleanup, - new: fuzzysortNew, - } - return fuzzysort -} // fuzzysortNew - -// This stuff is outside fuzzysortNew, because it's shared with instances of fuzzysort.new() -var isNode = typeof require !== 'undefined' && typeof window === 'undefined' -// var MAX_INT = Number.MAX_SAFE_INTEGER -// var MIN_INT = Number.MIN_VALUE -var preparedCache = new Map() -var preparedSearchCache = new Map() -var noResults = []; noResults.total = 0 -var matchesSimple = []; var matchesStrict = [] -function cleanup() { preparedCache.clear(); preparedSearchCache.clear(); matchesSimple = []; matchesStrict = [] } -function defaultScoreFn(a) { - var max = -9007199254740991 - for (var i = a.length - 1; i >= 0; --i) { - var result = a[i]; if(result === null) continue - var score = result.score - if(score > max) max = score - } - if(max === -9007199254740991) return null - return max -} - -// 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 -function getValue(obj, prop) { - var tmp = obj[prop]; if(tmp !== undefined) return tmp - 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 -} - -function isObj(x) { return typeof x === 'object' } // faster as a function - -// Hacked version of https://github.com/lemire/FastPriorityQueue.js -var fastpriorityqueue=function(){var r=[],o=0,e={};function n(){for(var e=0,n=r[e],c=1;c<o;){var f=c+1;e=c,f<o&&r[f].score<r[c].score&&(e=f),r[e-1>>1]=r[e],c=1+(e<<1)}for(var a=e-1>>1;e>0&&n.score<r[a].score;a=(e=a)-1>>1)r[e]=r[a];r[e]=n}return e.add=function(e){var n=o;r[o++]=e;for(var c=n-1>>1;n>0&&e.score<r[c].score;c=(n=c)-1>>1)r[n]=r[c];r[n]=e},e.poll=function(){if(0!==o){var e=r[0];return r[0]=r[--o],n(),e}},e.peek=function(e){if(0!==o)return r[0]},e.replaceTop=function(o){r[0]=o,n()},e}; -var q = fastpriorityqueue() // reuse this, except for async, it needs to make its own - -return fuzzysortNew() -}) // UMD - -// TODO: (performance) wasm version!? - -// TODO: (performance) layout memory in an optimal way to go fast by avoiding cache misses - -// TODO: (performance) preparedCache is a memory leak - -// TODO: (like sublime) backslash === forwardslash - -// TODO: (performance) i have no idea how well optimized the allowing typos algorithm is diff --git a/help3xsl/help.js b/help3xsl/help.js index 17d4909058..1f767a9c12 100644 --- a/help3xsl/help.js +++ b/help3xsl/help.js @@ -7,7 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// Pagination and fuzzy search +// Pagination and bookmark search var url = window.location.pathname; var moduleRegex = new RegExp('text\\/(\\w+)\\/'); var regexArray = moduleRegex.exec(url); @@ -16,6 +16,19 @@ var indexEl = document.getElementsByClassName("index")[0]; var fullLinks = fullLinkify(indexEl, bookmarks, modules, currentModule()); var search = document.getElementById('search-bar'); search.addEventListener('keyup', debounce(filter, 100, indexEl)); +var flexIndex = new FlexSearch.Document({ document: { + // Only the text content gets indexed, the others get stored as-is + index: [{ + field: 'text', + tokenize: 'full' + }], + store: ['url','app','text'] + } +}); +// Populate FlexSearch index +loadSearch(); +// Render the unfiltered index list on page load +fillIndex(indexEl, fullLinks, modules); // Preserve search input value during the session search.value = sessionStorage.getItem('searchsave'); if (search.value !== undefined) { @@ -24,8 +37,6 @@ if (search.value !== undefined) { window.addEventListener('unload', function(event) { sessionStorage.setItem('searchsave', search.value); }); -// render the unfiltered index list on page load -fillIndex(indexEl, fullLinks, modules); function currentModule() { var module = ''; @@ -55,6 +66,11 @@ function fullLinkify(indexEl, bookmarks, modules, currentModule) { }); return fullLinkified; } +function loadSearch() { + bookmarks.forEach((el, i) => { + flexIndex.add(i, el); + }); +} function fillIndex(indexEl, content, modules) { indexEl.innerHTML = content; var indexKids = indexEl.children; @@ -72,23 +88,23 @@ function fillIndex(indexEl, content, modules) { } // filter the index list based on search field input function filter(indexList) { - var results = null; - var group = []; - var target = search.value.trim(); - var filtered = ''; + let group = []; + let target = search.value.trim(); + let filtered = ''; if (target.length < 1) { fillIndex(indexEl, fullLinks, modules); return; } - - results = fuzzysort.go(target, bookmarks, {threshold: -15000, key:'text'}); + // Regex for highlighting the match + let regex = new RegExp(target.split(/\s+/).filter((i) => i?.length).join("|"), 'gi'); + let results = flexIndex.search(target, { pluck: "text", enrich: true, limit: 1000 }); // tdf#123506 - Group the filtered list into module groups, keeping the ordering modules.forEach(function(module) { group[module] = ''; }); results.forEach(function(result) { - group[result.obj['app']] += '<a href="' + result.obj['url'] + '" class="' + result.obj['app'] + '">' + fuzzysort.highlight(result) + '</a>'; + group[result.doc.app] += '<a href="' + result.doc.url + '" class="' + result.doc.app + '">' + result.doc.text.replace(regex, (match) => `<strong>${match}</strong>`) + '</a>'; }); modules.forEach(function(module) { if (group[module].length > 0) { @@ -97,7 +113,6 @@ function filter(indexList) { }); fillIndex(indexList, filtered, modules); - }; // delay the rendering of the filtered results while user is typing function debounce(fn, wait, indexList) { diff --git a/help3xsl/online_transform.xsl b/help3xsl/online_transform.xsl index b7502f6f49..7ccb97b766 100644 --- a/help3xsl/online_transform.xsl +++ b/help3xsl/online_transform.xsl @@ -147,7 +147,7 @@ <script type="text/javascript" src="polyfills.js"></script> <script type="text/javascript" src="languages.js"></script> <script type="text/javascript" src="{$lang}/langnames.js"></script> - <script type="text/javascript" src="fuzzysort.js"></script> + <script type="text/javascript" src="flexsearch.debug.js"></script> <script type="text/javascript" src="prism.js"></script> <script type="text/javascript" src="help2.js" defer=""></script> <script type="text/javascript" src="a11y-toggle.js" defer=""></script> diff --git a/help3xsl/xap_templ_query.xsl b/help3xsl/xap_templ_query.xsl index a606d2fc2a..4189aadfdc 100644 --- a/help3xsl/xap_templ_query.xsl +++ b/help3xsl/xap_templ_query.xsl @@ -82,7 +82,7 @@ $def{SPAGE,<input type=submit name="[" value="$1" disabled=disabled>} <script type="text/javascript" src="polyfills.js"></script> <script type="text/javascript" src="languages.js"></script> <script type="text/javascript" src="]]><xsl:value-of select="$lang"/><![CDATA[/langnames.js"></script> -<script type="text/javascript" src="fuzzysort.js"></script> +<script type="text/javascript" src="flexsearch.debug.js"></script> <script type="text/javascript" src="prism.js"></script> <script type="text/javascript" src="help2.js" defer=""></script> <script type="text/javascript" src="a11y-toggle.js" defer=""></script> |