From e5ef4156ac2439209704a1fda348fca77cf98eb2 Mon Sep 17 00:00:00 2001 From: Roy Orbitson Date: Thu, 13 Jun 2024 15:10:12 +0930 Subject: [PATCH] Fuzzy search of docs Allow partial terms and multiple search tokens instead of rigid 'begins-with' substring matching. --- include/footer.inc | 2 +- js/ext/FuzzySearch.min.js | 10 ++ js/ext/typeahead.jquery.min.js | 8 ++ js/ext/typeahead.min.js | 1 - js/search.js | 203 +++++++++++++++------------------ styles/theme-base.css | 2 + 6 files changed, 110 insertions(+), 116 deletions(-) create mode 100644 js/ext/FuzzySearch.min.js create mode 100644 js/ext/typeahead.jquery.min.js delete mode 100644 js/ext/typeahead.min.js diff --git a/include/footer.inc b/include/footer.inc index f4dad0d68e..778a3cb55f 100644 --- a/include/footer.inc +++ b/include/footer.inc @@ -99,7 +99,7 @@ if (!empty($_SERVER['BASE_PAGE']) ' . "\n"; diff --git a/js/ext/FuzzySearch.min.js b/js/ext/FuzzySearch.min.js new file mode 100644 index 0000000000..ac8d3d6c9d --- /dev/null +++ b/js/ext/FuzzySearch.min.js @@ -0,0 +1,10 @@ +/** + * @license FuzzySearch.js + * Autocomplete suggestion engine using approximate string matching + * https://github.com/jeancroy/FuzzySearch + * + * Copyright (c) 2015, Jean Christophe Roy + * Licensed under The MIT License. + * http://opensource.org/licenses/MIT + */ +!function(){"use strict";function a(b){return void 0===b&&(b={}),this instanceof a?void a.setOptions(this,b,a.defaultOptions,F,!0,this._optionsHook):new a(b)}function b(a,b){for(var c in a)a.hasOwnProperty(c)&&(this[c]=b.hasOwnProperty(c)&&void 0!==b[c]?b[c]:a[c])}function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a,b){for(var c=b.length,d=0,e=-1;++e0?a.substr(d):a}function e(a){var b=a.length;if(!b)return null;for(var c=g(a[0]),d=0;++de?1:e>d?-1:0}function j(a,b,c,d,e,f,g){this.normalized=a,this.words=b,this.tokens_groups=c,this.fused_str=d,this.fused_map=e,this.fused_score=0,this.has_children=f,this.children=g}function k(a,b,c){this.tokens=a,this.map=b,this.gate=c;for(var d=a.length,e=-1,f=new Array(d);++ed&&(e=b[d++],"*"!==e&&""!==e);){if(null==a||!(e in a))return c;a=a[e]}if(null==a)return c;var i=Object.prototype.toString.call(a),j="[object Array]"===i,k="[object Object]"===i;if(d===h)if(j)for(f=-1,g=a.length;++fc;c++)r(f[c],d,e);return d}function r(a,b,c){var d=a.length;0!=d&&(d>=3&&t(a,6,b,c),d>=2&&s(a,4,b,c),u(a[0],b,c))}function s(a,b,c,d){for(var e=Math.min(a.length,b),f=0;e-1>f;f++)for(var g=f+1;e>g;g++)u(a[f]+a[g],c,d);return c}function t(a,b,c,d){for(var e=Math.min(a.length,b),f=0;e-2>f;f++)for(var g=f+1;e-1>g;g++)for(var h=g+1;e>h;h++)u(a[f]+a[g]+a[h],c,d);return c}function u(a,b,c){a in c||(c[a]=!0,b.push(a))}function v(a,b){var c={};if(0==a.length)return[];for(var d=0;de;e++)h[e]={};var i,j=new D(a,h,c,d),k=B(j,0,0).score,l=0;for(e=0;g>e&&(i=h[e][l],i);e++)b[e]=f=i.index,f>-1&&(l|=1<G&&(i=G);var j,k,l,m=f[c],n=0,o=-1,p=h-1>c,q=e[c+1];for(j=0;i>j;j++){var r=1<k))){if(p){l=b|r;var s=l in q?q[l]:B(a,l,c+1);k+=s.score,j=n&&(n=k,o=j)}}p&&(l=b,k=l in q?q[l].score:B(a,l,c+1).score,k>n&&(n=k,o=-1));var t=new C(n,o);return e[c][b]=t,t}function C(a,b){this.score=a,this.index=b}function D(a,b,c,d){this.score_grid=a,this.cache_tree=b,this.score_thresholds=c,this.order_bonus=d}function E(a,b){var c,d,e=a.slice();for(a.length=b,c=0;b>c;c++)a[c]=-1;for(c=0;c-1&&b>d&&(a[d]=c)}a.defaultOptions={minimum_match:1,thresh_include:2,thresh_relative_to_best:.5,field_good_enough:20,bonus_match_start:.5,bonus_token_order:2,bonus_position_decay:.7,score_per_token:!0,score_test_fused:!1,score_acronym:!1,token_sep:" .,-:",score_round:.1,output_limit:0,sorter:i,normalize:x,filter:null,output_map:"item",join_str:", ",token_query_min_length:2,token_field_min_length:3,token_query_max_length:64,token_field_max_length:64,token_fused_max_length:64,token_min_rel_size:.6,token_max_rel_size:10,interactive_debounce:150,interactive_mult:1.2,interactive_burst:3,source:[],keys:[],lazy:!1,token_re:/\s+/g,identify_item:null,use_index_store:!1,store_thresh:.7,store_max_results:1500};var F={keys:[],tags:[],index:[],index_map:{},nb_indexed:0,store:{},tags_re:null,acro_re:null,token_re:null,options:null,dirty:!1,query:null,results:[],start_time:0,search_time:0},G=32;b.update=function(a,b,c){for(var d in c)c.hasOwnProperty(d)&&b.hasOwnProperty(d)&&(a[d]=void 0===c[d]?b[d]:c[d])},a.setOptions=function(a,d,e,f,g,h){g?(c(a,f),a.options=new b(e,d)):b.update(a.options,e,d),h.call(a,d)},c(a.prototype,{setOptions:function(b,c){void 0===c&&(c=b.reset||!1),a.setOptions(this,b,a.defaultOptions,F,c,this._optionsHook)},_optionsHook:function(a){var b=this.options;"output_map"in a&&"string"==typeof a.output_map&&("alias"===b.output_map?b.output_map=this.aliasResult:b.output_map=d(b.output_map,["root","."])),this.source=b.source;var c;if("keys"in a&&void 0!==(c=a.keys)){var h,i,j=Object.prototype.toString.call(c);if(this.tags=null,"[object String]"===j)this.keys=c.length?[c]:[];else if("[object Object]"===j){this.keys=[],this.tags=[],h=0;for(var k in c)c.hasOwnProperty(k)&&(this.tags[h]=k,this.keys[h]=c[k],h++)}else this.keys=c;for(c=this.keys,i=c.length,h=-1;++h0&&e>d&&(e=d),"function"!=typeof b)return a.slice(0,e);for(var f=new Array(e),g=-1;++g0&&d>c&&(d=c),""===b)return a.slice(0,d);var e,f,g=new Array(d);if(-1===b.indexOf("."))for(f=-1;++f=c&&(h[++f]=d);return h},c(a.prototype,{_prepQuery:function(b){var c,d,e,f,g,h,i,k=this.options,l=k.score_per_token,m=k.score_test_fused,n=k.token_fused_max_length,o=k.token_field_min_length,p=k.token_field_max_length,q=this.tags,r=this.tags_re,s=q.length,t=this.token_re;if(l&&s&&r){var u,v=0,w=0,x=new Array(s+1),y=r.exec(b);for(g=null!==y;null!==y;)u=y.index,x[w]=b.substring(v,u),v=u+y[0].length,w=q.indexOf(y[1])+1,y=r.exec(b);x[w]=b.substring(v),f=[];for(var z=-1;++za&&(a=this.fused_score),this.has_children)for(var h=this.children,i=-1,j=h.length;++iG?a.posVector(b):a.bitVector(b,{},0)},a.mapAlphabet=function(b){for(var c=b.length,d=new Array(c),e=-1;++eG?d[e]=a.posVector(f):d[e]=a.bitVector(f,{},0)}return d},a.bitVector=function(a,b,c){for(var d,e=a.length,f=-1,g=c;++fd;){for(var g=[],h={},i=0,j=0;++d=G){c=new k([l],a.posVector(l),4294967295);break}if(m+i>=G){d--;break}g.push(l),a.bitVector(l,h,i),j|=(1<0&&f.push(new k(g,h,j)),c&&(f.push(c),c=null)}return f},a.prototype.score=function(b,c){var d=a.alphabet(b);return a.score_map(b,c,d,this.options)},a.score_map=function(b,c,d,e){var f,g,h=b.length,i=c.length,j=e.bonus_match_start,k=i>h?h:i;if(0===k)return 0;var l=(h+i)/(2*h*i),m=0;if(b===c)m=k;else for(;b[m]===c[m]&&++mG)return g=a.llcs_large(b,c,d,m),l*g*g+j*m;var n,o,p=(1<>1&1431655765,q=(858993459&q)+(q>>2&858993459),g=16843009*(q+(q>>4)&252645135)>>24,g+=m,l*g*g+j*m},a.score_single=function(b,c,d){var e=b.tokens[0],f=e.length,g=c.length;return gd.token_max_rel_size*f?[0]:[a.score_map(e,c,b.map,d)]},a.score_pack=function(b,c,d){var e=b.tokens,f=e.length;if(1==f)return a.score_single(b,c,d);for(var g,h,i=4294967295,j=0|b.gate,k=b.map,l=-1,m=c.length;++lm||m>p*w)q[s]=0,r+=w;else{if(v===c)u=t=w;else{var x=m>w?w:m;for(u=0;v[u]===c[u]&&++u>>r&(1<>>u;y;)y&=y-1,t++}r+=w;var z=(w+m)/(2*w*m);q[s]=z*t*t+n*u}}return q},a.llcs_large=function(a,b,c,d){var e,f,g,h,i,j;void 0===d&&(d=0),g=d?[new l(0,d),new l(1/0,1/0)]:[new l(1/0,1/0)];var k,m,n,o,p,q,r=d,s=g.length,t=b.length;for(q=d;t>q;q++){var u=b[q];if(u in c){k=c[u];var v=new Array(Math.min(2*s,r+2));for(h=-1,m=0,f=k[0],j=-1,o=-1;++of;)f=k[++m];f>=e?v[++h]=n:(f===i?v[h].end++:1===p?(n.start=f,n.end=f+1,v[++h]=n):v[++h]=new l(f,f+1),p>1&&(n.start++,v[++h]=n))}e>f&&(v[++h]=n,r++),g=v,s=++h}}return r},c(a.prototype,{search:function(b){var c=Date.now();this.start_time=c;var d=this.options;this.dirty&&d.lazy&&(this._buildIndexFromSource(),this.dirty=!1);var e=this.query=this._prepQuery(b),f=this.index,g=[];d.use_index_store&&(f=this._storeSearch(e,f)),d.filter&&(f=d.filter.call(this,f));var h=this._searchIndex(e,f,g);g=a.filterGTE(g,"score",h),"function"==typeof d.sorter&&(g=g.sort(d.sorter)),(d.output_map||d.output_limit>0)&&(g="function"==typeof d.output_map?a.map(g,d.output_map,this,d.output_limit):a.mapField(g,d.output_map,d.output_limit));var i=Date.now();return this.search_time=i-c,this.results=g,g},_searchIndex:function(b,c,d){for(var e=this.options,f=e.bonus_position_decay,g=e.field_good_enough,i=e.thresh_relative_to_best,j=e.score_per_token,k=e.score_round,l=e.thresh_include,m=0,n=b.children,o=-1,p=c.length;++oy&&(y=F,z=D)}if(y*=1+v,v*=f,y>s&&(s=y,t=w,u=z,y>g))break}if(j){var H=b.scoreItem();s=.5*s+.5*H}if(s>m){m=s;var I=s*i;I>l&&(l=I)}s>l&&(s=Math.round(s/k)*k,d.push(new h(q.item,r,s,t,u,r[0][0].join(" "))))}return l},_scoreField:function(b,c){var d=c.tokens_groups,e=d.length,f=b.length;if(!e||!f)return 0;for(var g,h,i,j,k,l=0,m=-1,n=this.options,o=n.bonus_token_order,p=n.minimum_match,q=-1;++qh||o>h-g&&k>0&&u[k]<=u[k-1])&&(t[k]=g,u[k]=v);var w=r.score_item;for(k=-1;++kp){var x=u[k],y=x-m,z=o*(1/(1+Math.abs(y)));y>0&&(z*=2),l+=z,g+=z,m=x}g>w[k]&&(w[k]=g)}}if(n.score_test_fused){for(var A=n.score_acronym?f-1:f,B=b[0],C=0;++Cl?D:l,D>c.fused_score&&(c.fused_score=D)}return l}}),c(a.prototype,{_prepItem:function(b,c){for(var d=a.generateFields(b,c),e=d.length,f=-1;++f2*this.options.token_field_min_length&&(k=a.filterSize(k,this.options.token_field_min_length,this.options.token_field_max_length)),this.options.score_acronym&&k.push(j.replace(this.acro_re,"$1")),g[h]=k}return new m(b,d)},add:function(a,b){void 0===b&&(b=!0);var c,d="function"==typeof this.options.identify_item?this.options.identify_item(a):null;null===d?(c=this.nb_indexed,this.nb_indexed++):d in this.index_map?c=this.index_map[d]:(this.index_map[d]=this.nb_indexed,c=this.nb_indexed,this.nb_indexed++);var e=this._prepItem(a,this.keys);this.index[c]=e,b&&(this.source[c]=a),this.options.use_index_store&&this._storeAdd(e,c)},_buildIndexFromSource:function(){var a=this.source.length;this.index=new Array(a),this.index_map={},this.nb_indexed=0;for(var b=-1;++b=b&&(i[++g]=c>e?d:d.substr(0,c));return i},c(a.defaultOptions,{highlight_prefix:!1,highlight_bridge_gap:2,highlight_before:'',highlight_after:""}),a.prototype.highlight=function(b,c){var d,e,f=this.query.normalized;return c&&c.length&&(d=this.tags.indexOf(c))>-1&&(e=this.query.children[d])&&(f+=(f.length?" ":"")+e.normalized),a.highlight(f,b,this.options)},a.highlight=function(b,c,d){if(void 0===d&&(d=a.defaultOptions),!c)return"";var e=d.highlight_before,f=d.highlight_after,g=d.score_per_token,h=d.score_test_fused,i=d.score_acronym,j=d.token_re,k=d.normalize(b),l=d.normalize(c),m=k.split(j),n=l.split(j),o=[],p=[];z(c,j,o,p);var q=[],r=[],s=0,t=0;if(g&&(t=a.matchTokens(n,m,r,d,!1)),(h||!g||i)&&(s=a.score_map(k,l,a.alphabet(k),d)+d.bonus_token_order),0===t&&0===s)return c;(!g||s>t)&&(m=[k],n=[l],o=[c],r=[0]);for(var u=o.length,v=-1;++vB&&q.push(A.substring(B,G)),q.push(e+A.substring(G,H)+f),B=H}q.push(A.substring(B)+p[v])}else q.push(o[v]+p[v])}return q.join("")},a.align=function(b,c,d,e,f){void 0===f&&(f=a.defaultOptions);var g,h,i=100,j=-10,k=-1,l=0,m=1,n=2,o=3,p=f.score_acronym,q=f.token_sep,r=Math.min(b.length+1,f.token_query_max_length),s=Math.min(c.length+1,f.token_field_max_length),t=s>r?r:s,u=0;if(b===c)u=r,r=0;else if(f.highlight_prefix){for(g=0;t>g&&b[g]===c[g];g++)u++;u&&(b=b.substring(u),c=c.substring(u),r-=u,s-=u)}var v=0,w=0,x=0,y=new Array(r*s),z=s-1;if(r>1&&s>1){var A,B,C,D,E=new Array(s),F=new Array(s),G=0;for(h=0;s>h;h++)F[h]=0,E[h]=0,y[h]=l;for(g=1;r>g;g++)for(G=0,A=E[0],z++,y[z]=l,h=1;s>h;h++)switch(D=F[h]=Math.max(F[h]+k,E[h]+j),G=Math.max(G+k,E[h-1]+j),C=p?b[g-1]!==c[h-1]?-(1/0):A+i+(2>g||q.indexOf(b[g-2])>-1?i:0)+(2>h||q.indexOf(c[h-2])>-1?i:0):b[g-1]===c[h-1]?A+i:-(1/0),A=E[h],B=E[h]=Math.max(C,D,G,0),z++,B){case G:y[z]=n;break;case C:y[z]=o,B>v&&(v=B,w=g,x=h);break;case D:y[z]=m;break;default:y[z]=l}}var H=f.highlight_bridge_gap,I=0;if(v>0){g=w,h=x,z=g*s+h,I=x,e.push(x+u);for(var J=!0;J;)switch(y[z]){case m:g--,z-=s;break;case n:h--,z--;break;case o:I-h>H&&(d.push(I+u),e.push(h+u)),h--,g--,I=h,z-=s+1;break;case l:default:J=!1}d.push(I+u)}return u&&(I>0&&H>=I?d[d.length-1]=0:(d.push(0),e.push(u))),d.reverse(),e.reverse(),v+u},a.matchTokens=function(b,c,d,e,f){void 0===e&&(e=a.defaultOptions),void 0===f&&(f=!1);var g,h,i,j,k,l,m,n=e.minimum_match,o=e.thresh_relative_to_best,p=[],q=b.length,r=c.length,s=a.mapAlphabet(b),t=n,u=-1,v=-1,w=0,x=[];for(g=0;q>g;g++)if(i=[],d[g]=-1,t=n,j=b[g],j.length){for(l=s[g],h=0;r>h;h++)k=c[h],k.length?(m=a.score_map(j,k,l,e),i[h]=m,m>n&&w++,m>t&&(t=m,u=g,v=h)):i[h]=0;x[g]=t,p[g]=i}else{for(h=0;r>h;h++)i[h]=0;p[g]=i}if(0===w)return 0;if(1===w)return d[u]=v,f&&E(d,r),t;for(g=0;g',menu:'
'}}function d(a){var c={};return b.each(a,function(a,b){c[b]="."+a}),c}function e(){var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},menu:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),a}var f={wrapper:"twitter-typeahead",input:"tt-input",hint:"tt-hint",menu:"tt-menu",dataset:"tt-dataset",suggestion:"tt-suggestion",selectable:"tt-selectable",empty:"tt-empty",open:"tt-open",cursor:"tt-cursor",highlight:"tt-highlight"};return a}(),d=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d,e;return d="typeahead:",e={render:"rendered",cursorchange:"cursorchanged",select:"selected",autocomplete:"autocompleted"},b.mixin(c.prototype,{_trigger:function(b,c){var e=a.Event(d+b);return this.$el.trigger.call(this.$el,e,c||[]),e},before:function(a){var b,c;return b=[].slice.call(arguments,1),c=this._trigger("before"+a,b),c.isDefaultPrevented()},trigger:function(a){var b;this._trigger(a,[].slice.call(arguments,1)),(b=e[a])&&this._trigger(b,[].slice.call(arguments,1))}}),c}(),e=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(h),c=d?g(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(h);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(h),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&i(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&e