From d82023031506632d985ebbd2722a6151af34a2be Mon Sep 17 00:00:00 2001 From: "alpha.zero" Date: Sat, 15 Jul 2023 01:58:48 +0300 Subject: [PATCH] oposi --- .vs/alphazero-official.github.io/v16/.suo | Bin 75264 -> 77312 bytes .vs/slnx.sqlite | Bin 90112 -> 90112 bytes assets/js/sjs.js | 0 node_modules/fuzzysearch/.editorconfig | 13 + node_modules/fuzzysearch/.jshintignore | 2 + node_modules/fuzzysearch/.jshintrc | 21 + node_modules/fuzzysearch/.npmignore | 1 + node_modules/fuzzysearch/CHANGELOG.md | 18 + node_modules/fuzzysearch/LICENSE | 20 + node_modules/fuzzysearch/README.md | 45 ++ node_modules/fuzzysearch/index.js | 24 + node_modules/fuzzysearch/package.json | 51 +++ node_modules/fuzzysearch/test/fuzzysearch.js | 14 + node_modules/simple-jekyll-search/LICENSE.md | 21 + node_modules/simple-jekyll-search/README.md | 334 ++++++++++++++ .../dest/simple-jekyll-search.js | 433 ++++++++++++++++++ .../dest/simple-jekyll-search.min.js | 6 + .../simple-jekyll-search/package.json | 80 ++++ .../simple-jekyll-search/src/JSONLoader.js | 30 ++ .../src/OptionsValidator.js | 34 ++ .../simple-jekyll-search/src/Repository.js | 108 +++++ .../SearchStrategies/FuzzySearchStrategy.js | 14 + .../SearchStrategies/LiteralSearchStrategy.js | 13 + .../simple-jekyll-search/src/Templater.js | 29 ++ .../simple-jekyll-search/src/index.js | 138 ++++++ .../simple-jekyll-search/src/utils.js | 28 ++ package-lock.json | 19 + search.json | 14 + 28 files changed, 1510 insertions(+) create mode 100644 assets/js/sjs.js create mode 100644 node_modules/fuzzysearch/.editorconfig create mode 100644 node_modules/fuzzysearch/.jshintignore create mode 100644 node_modules/fuzzysearch/.jshintrc create mode 100644 node_modules/fuzzysearch/.npmignore create mode 100644 node_modules/fuzzysearch/CHANGELOG.md create mode 100644 node_modules/fuzzysearch/LICENSE create mode 100644 node_modules/fuzzysearch/README.md create mode 100644 node_modules/fuzzysearch/index.js create mode 100644 node_modules/fuzzysearch/package.json create mode 100644 node_modules/fuzzysearch/test/fuzzysearch.js create mode 100644 node_modules/simple-jekyll-search/LICENSE.md create mode 100644 node_modules/simple-jekyll-search/README.md create mode 100644 node_modules/simple-jekyll-search/dest/simple-jekyll-search.js create mode 100644 node_modules/simple-jekyll-search/dest/simple-jekyll-search.min.js create mode 100644 node_modules/simple-jekyll-search/package.json create mode 100644 node_modules/simple-jekyll-search/src/JSONLoader.js create mode 100644 node_modules/simple-jekyll-search/src/OptionsValidator.js create mode 100644 node_modules/simple-jekyll-search/src/Repository.js create mode 100644 node_modules/simple-jekyll-search/src/SearchStrategies/FuzzySearchStrategy.js create mode 100644 node_modules/simple-jekyll-search/src/SearchStrategies/LiteralSearchStrategy.js create mode 100644 node_modules/simple-jekyll-search/src/Templater.js create mode 100644 node_modules/simple-jekyll-search/src/index.js create mode 100644 node_modules/simple-jekyll-search/src/utils.js create mode 100644 package-lock.json create mode 100644 search.json diff --git a/.vs/alphazero-official.github.io/v16/.suo b/.vs/alphazero-official.github.io/v16/.suo index eca984965545cc8054295b6741edf7a1ef5ff46b..9906aae425977b4b90583f934375837432fd1226 100644 GIT binary patch delta 4855 zcmds*dr(x@9mn@vc9-1+bb&>A$zxpz3Jd#WcM;jUuwX`$_o{-cz-wV_9Bg>B7^~7(=|gC2kca%t!;$h%_P3!;pLf8HA7JtG!GG>X6Q) zNunT*ITRv-N8-lnXW>?O(zDAkMf;(F>OlLKVO)k#9h?Z&VFg0#yo7NkatG6E zFit`ukYa?E2Ln}R4m!o_h#Y<@P7>36m=PC7i5DuC2P(u#PA7CMN&#z+8vqDis~^M+9N zO~7x9fXdza@f9vYz6I`;KLkd-m)OCr_7DZks(%wjp2N4vL*GcZ$#&SU(h8Z0S0!G9 zOWKb)8x_!N*a#(Ida@U0n?0lx+|R!Xd`qT~soETPd)%whSW#No=5B2*!W0d@Xa&h5 zbB_;1n+-RwXMJ#XXM6Q4uXlXvQ$~;*Bbf}uWh)0eWDsAFyy__SG=LmKyhuPk zjHzu#k5&DgjIVWxrF72^$e=gAmz2P4yoWfzo#%;TF`LerhTskegFCBN%BUU=lYD!-O()hNefo%-9^~J#@ zcqA;=mkGC0!x?$7+5c#48P*XilR%gLd&nW=F!CZ27|0-(9X*5(IH$$%(pc3`$VlO` z``e6Rb5y|P-s2b0ii~JQGOMo=G3{3n zKl23{uhlSursg98{AwjA>l&#=*FDgpi40~r4+#f%y@yC)wtkLCgxQ7&X1qo7*gI;E zOH7B@78qjN%i)>|6a)8Nz_Wcax09^D`QsOEo?(ld&8Phrw*CP=!!#V}&Vre46ZpGT zpz6sXk>KdD!?my&@b=^a-xC8mM(W+C^6p~;zbe>#Fh^kb@nIu<45<0Tg7aWs_>vN! z_PhxN-(LnNUz7=buQ180Uf*qY&rq=AX1}fgSSU_)rdHOzu$7(;jt) z&R#lYcPZiz^}68NA*J9PIV=a}iuJ3l%V;s`%oe>>+hDRbX-%dElh$f5 z=(Ktp*JNyNw3>9b`meICa#M(O|Ai4j-Q{AqcCrZgbAGT-u7h2tRMgb;z@K8jUJC>N zDP4@AtkhyE)oY6_CZkrb$FB}loy&u|;pM=NvVwntC68)`^h2ci|C-_WFa79lN7;w9 z75``^^baRSY{at;J+MebuTjy>z)$*t9m|bb+HJuN3j9Uf$q!zvj)#$UD(z_qZf8a1(2yLiGvcKxLu+UZ)h8V-5Ql z+a%NxWy4s0T4cye0vVw-{>?ju=y7zy0R9Usyni7ZtJxOKL_NJi5^yD8zvu|4kGe?D z^O1xnK2AZhVc?P;e3#b1^(kLa!zp+Svk}m2zVU0m=mF-}TpO}n|JgOd$ze0~dhnOa zD`2-N9r`csftr~u;D7H@?EJ?!bh*DygQ$E&BM@pYN0Tp)Q}Dm1AilO`gmre|UjiIn zryE2q3pa^&QJbhx)Gq44k~UEh9x>_d3a{HmeI*68Tx&-Q*W0wWUEAJV{lR<*th1!U z_578 zfjy9ZyAlR+5{1mq5+g`8t(tKE`Qx=;Sbul9R1!FfL;uX$^NuL;D+UaovI6^ezkK|k ctn?w?&=hutO(D#gkpv<>kEv+p3EkiR1>Sm1&;S4c delta 3616 zcmdT`drX_x75Dx8z&39%iFqWpi6IWy;1^&g3=A03u8cslQI@3y+c=L2^NI~ACG)o> z-NGOQe3BBX{ZZVk(;~Hne38gj)_LlbkcBjXR{Nt{r=*d#wX9P&m90&euyc*wxNW9w zT~%rK(@*EzbMHOhdEE#5TLHTu7}Kj5UZkb)c&W(p5qDQtSE-cp=`&3q5+VW>qY&yv zPbHp#9?=nEffdG2TEWNP3G;DUQ8&)4&w|_h+&m+)NeI-jDvr?2NbQKkNWTuM1nV>L zkG$%LBn#;g#3sZY=n-!tweXxcTd)rMupll^6d^-Zei`Xq$dEjfIU14lAnipQM0gQC zSdzd)Jo2&5tU`|<{p(JY$`DF~36YE_M5G}$A~FyHL=i%b&>(0Q z^hom%Dg@Q8h|sbKb-^2gV)DRvQ#vSxZ5a*}Z$OkF+7WKVci@z8J2?bz2sZ_!UNzOK zAZQ6fg~&y0LQr`Wa9XO}KszQJFh>SUk(Na#jyqm}vG@z(XhLD}5jDvJUy7foVI`p< zF>EcZAJno+N5PxQCTzs@4G7vkZ)3Pb9@Q*GME^-GN?5aKM*Qm>%42+abS$Sq8eP~5yC*x0I7zRB0sT#&*T?YqF4-%tif{v_$_^oJ3nRwD+U5+^C$I4jTPJPVA(rn8kKFA;r)hp0Foo zfR>jl(uXmFCZ!8IbWcY22Fx2Q!F(q3+mT66AU%rsE@GU@#vO$ubEfG9GTxnVuD~m} zuhYeTbJ%HIKwGStpX9$7pDIA4>=e;T_lRIX`Jj-bBM(hGwZs7{%C)3NPmXYnwt?@V zVQBhQChWNpH+!Ri7zo%d$+BGzuX|rt?*aG0qWxY^$Kc@OX1(2HC@m|~fo<`J(6f-8 zGG70l>%F%$*UmoD)pG2q?qwJ~y+N9QKa4}zC*dy_zX8{`C&SIR74RISrl%V9Mw3oo zrZbpz``wQfdD<=DIIn!yB@ss@puDmLo?pt(p(n`$RPz|IZ`I@Xc$KlPw#-~> z&{YR5jEq)!v_*3XGL15k=Hdh{979BMni4Ee3f42gx^f_=xrOk-*L;MSxeuCkgv)Pu zJx)L?gA?rf2MM+?!Bz%TcNCmrw~zs~?2I^i@X-(ojkwJwAhoX;lzlnC?u>_P83yE) zVdxn_R2FCp?}xUS{Q&Pf2JtfSIsHTkE6!CS;8tAmOhD=V*ID!vOqyyK*m^Ce-TOY_ z)Zc6rP!Br89&~;$F2Rh(qgCMx3(oXu65hFb@%u0S$VP7$UZ7tFuk~rchE&$CB|NC= zuY^#48U*@_fZA(2B>Na*WqL-;9XoW04{Zas;2;A**3KOb&cy@_g8scQFq8y0o)B|$ zXX^$hU2QhDHc>06mT~ng;CJMwyDj5KK6?WH!NON;7%xp>8Ujbemrl4vgrq* z`*bDvXHwGZYD|X*%fE8qpsVgchx=f~V9izt{k%KHi@Vs%Z%+hvr});ISf{l&e87FyPPIViKX4e=S4&LU&NNd z^GGq3Lr%iXqzc&cHVFO17MRNi@@kgUgJ%;xu~7577sp`iln`p?9shAIAPGv~H}ek> zCse6z6M6y3g(Y^>S3 z+tJaz|KFP*4oS>k@!-ydmu|I)*2)yvxsU*BbqJ5%a$tYP27gUp=JG~3yd=f|WO25a zZ3J{v>%p|N<(beg8KMavz=KOq1A8e1s!C44>n%+ayLG!9Qev~L*d(-<65rKE1Ngr5E5%(StGBq*4F7PR=ZVSW-*$o ztd_&c;d=#a%WTwpN!0r3p3!FE(^n*mGp5v(fd|PpDeV6%W0P|Jd4^9;q*)DdmQ{uog4ULGQFpv zB=5>ZsE{;GjOUSJj=j#3XOjqC6fd{Vwq}txh4&A}Sq*6>AKjYDzK!<+Q$PgFJ!PMM jb~Ij5q|%oxtyg;>@;Jcy1LY+-mRg90cY=oZe^~lY)G|Bz diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index 40bccf72811301c43af44d5723b81dd98c01e9b8..2e9285e4c1697345934abd24335087ec91ccc269 100644 GIT binary patch delta 808 zcmZvaTS!z<6o%J6mwnEebN1{x>7=8EHcA%O3_Vm3s}P~b{8(fNDf3|S8&)o=@G;1LDo_)sbMVRBA4H*>o%dfwJ|-6D@{{x(J5*e% zzNQiKlPr)aGG*#X3B>$xb{eHbJ6!;<&lzj=-Od;gF^{+==n;9~pnIivvFUK4;8W-Z zCRf#Gc+^qiu|KvCX>Jv8VT!t zx{wTiM~)G^@ITgO{e>$@GDjzX&d~`|?;EF4I*)-<5QZLpX S`rsF89f(7g!(1Ab`hEd~qV&@M delta 765 zcmY*XTS!zv82;y+vvbbbbLNbzyXdB2nq;xK(nCd2UJz|xLa8=Nf}^aLR=g~pHE&5q zmxnA!hSkUFAqa`m4kbpVbbIJQdMO_aGDL__GM7Rrq*=8a-^|ba^E2Q4-^brO;pm-k zTuVm-{TU@_V5I73J{n{X@(&=vj_13Qq@W{)nNl>6trXJ=TtF}3Wil)WsoVHYKR8Zu z?E4KnE2&Eg$)%7EnMlR;jp1nMl)u61QKrw&oVgz8lVv=Fhk&oWkR_Ka#>JNeXRW8lH}^aV3!7-$hZN5 zYD{EGMQ7opj>%~wZp`YHq=f9!Zfe8E6{nAWq?h#~V(LC;CHbuR=?m?(Rzhx()io@U z4R8mZDyhx}NbHml7gyiX8eUg8$YLkn$zz}-+GMSjfo*R==4T>q7R*RvTYb3Mf_^Nz z5O++=1yo!R%QB}su ztLo?youX5QNPdtwnI*HfYfA>P-#5*noLr9=0QP&*c--wt1&0U%#AH$65eE4s=45j% znNm=tlqr$U!cW>b@f**L5j|V~rq5}|wXktmy-gRL$8?!^w6E$sx$7KLUuqYfZ%Bx| z`XAhv0>xhKKnVHnclnS`9)XTF1hPHdBa$MykUifW5K9ASU1*Y&iG=kT(j_naQJE}d w3BtdVv(|C4VE(lmVs_`*zAYHh1)vMIYhsqNg?p(yUje$p^Doq18JBPT0`{HjasU7T diff --git a/assets/js/sjs.js b/assets/js/sjs.js new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/fuzzysearch/.editorconfig b/node_modules/fuzzysearch/.editorconfig new file mode 100644 index 0000000..5d12634 --- /dev/null +++ b/node_modules/fuzzysearch/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/node_modules/fuzzysearch/.jshintignore b/node_modules/fuzzysearch/.jshintignore new file mode 100644 index 0000000..f06235c --- /dev/null +++ b/node_modules/fuzzysearch/.jshintignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/node_modules/fuzzysearch/.jshintrc b/node_modules/fuzzysearch/.jshintrc new file mode 100644 index 0000000..63bccb7 --- /dev/null +++ b/node_modules/fuzzysearch/.jshintrc @@ -0,0 +1,21 @@ +{ + "curly": true, + "eqeqeq": true, + "newcap": true, + "noarg": true, + "noempty": true, + "nonew": true, + "sub": true, + "validthis": true, + "undef": true, + "trailing": true, + "boss": true, + "eqnull": true, + "strict": true, + "immed": true, + "expr": true, + "latedef": "nofunc", + "quotmark": "single", + "indent": 2, + "node": true +} diff --git a/node_modules/fuzzysearch/.npmignore b/node_modules/fuzzysearch/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/fuzzysearch/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/fuzzysearch/CHANGELOG.md b/node_modules/fuzzysearch/CHANGELOG.md new file mode 100644 index 0000000..711183d --- /dev/null +++ b/node_modules/fuzzysearch/CHANGELOG.md @@ -0,0 +1,18 @@ +# v1.0.3 Short Fuse + +- Improved circuit-breaker when `needle` and `haystack` length are equal + +# v1.0.2 Vodka Tonic + +- Slightly updated circuit-breaker that tests for equal length first +- Doubled method performance ([see jsperf tests](http://jsperf.com/fuzzysearch-regex/3)) + +# v1.0.1 Circuit Breaker + +- Introduced a circuit-breaker where queries longer than the searched string will return `false` +- Introduced a circuit-breaker where queries identical to the searched string will return `true` +- Introduced a circuit-breaker where text containing the entire query will return `true` + +# v1.0.0 IPO + +- Initial Public Release diff --git a/node_modules/fuzzysearch/LICENSE b/node_modules/fuzzysearch/LICENSE new file mode 100644 index 0000000..b980cef --- /dev/null +++ b/node_modules/fuzzysearch/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright © 2015 Nicolas Bevacqua + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/fuzzysearch/README.md b/node_modules/fuzzysearch/README.md new file mode 100644 index 0000000..15b38aa --- /dev/null +++ b/node_modules/fuzzysearch/README.md @@ -0,0 +1,45 @@ +# fuzzysearch + +> Tiny and blazing-fast fuzzy search in JavaScript + +Fuzzy searching allows for flexibly matching a string with partial input, useful for filtering data very quickly based on lightweight user input. + +# Demo + +To see `fuzzysearch` in action, head over to [bevacqua.github.io/horsey][3], which is a demo of an autocomplete component that uses `fuzzysearch` to filter out results based on user input. + +# Install + +From `npm` + +```shell +npm install --save fuzzysearch +``` + +# `fuzzysearch(needle, haystack)` + +Returns `true` if `needle` matches `haystack` using a fuzzy-searching algorithm. Note that this program doesn't implement _[levenshtein distance][2]_, but rather a simplified version where **there's no approximation**. The method will return `true` only if each character in the `needle` can be found in the `haystack` and occurs after the preceding character. + +```js +fuzzysearch('twl', 'cartwheel') // <- true +fuzzysearch('cart', 'cartwheel') // <- true +fuzzysearch('cw', 'cartwheel') // <- true +fuzzysearch('ee', 'cartwheel') // <- true +fuzzysearch('art', 'cartwheel') // <- true +fuzzysearch('eeel', 'cartwheel') // <- false +fuzzysearch('dog', 'cartwheel') // <- false +``` + +An exciting application for this kind of algorithm is to filter options from an autocomplete menu, check out [horsey][3] for an example on how that might look like. + +# But! _`RegExp`s...!_ + +![chart showing abysmal performance for regexp-based implementation][1] + +# License + +MIT + +[1]: https://cloud.githubusercontent.com/assets/934293/6495796/106a61a6-c2ac-11e4-945d-3d1bb066a76e.png +[2]: http://en.wikipedia.org/wiki/Levenshtein_distance +[3]: http://bevacqua.github.io/horsey diff --git a/node_modules/fuzzysearch/index.js b/node_modules/fuzzysearch/index.js new file mode 100644 index 0000000..047762f --- /dev/null +++ b/node_modules/fuzzysearch/index.js @@ -0,0 +1,24 @@ +'use strict'; + +function fuzzysearch (needle, haystack) { + var tlen = haystack.length; + var qlen = needle.length; + if (qlen > tlen) { + return false; + } + if (qlen === tlen) { + return needle === haystack; + } + outer: for (var i = 0, j = 0; i < qlen; i++) { + var nch = needle.charCodeAt(i); + while (j < tlen) { + if (haystack.charCodeAt(j++) === nch) { + continue outer; + } + } + return false; + } + return true; +} + +module.exports = fuzzysearch; diff --git a/node_modules/fuzzysearch/package.json b/node_modules/fuzzysearch/package.json new file mode 100644 index 0000000..690aba7 --- /dev/null +++ b/node_modules/fuzzysearch/package.json @@ -0,0 +1,51 @@ +{ + "_from": "fuzzysearch@^1.0.3", + "_id": "fuzzysearch@1.0.3", + "_inBundle": false, + "_integrity": "sha512-s+kNWQuI3mo9OALw0HJ6YGmMbLqEufCh2nX/zzV5CrICQ/y4AwPxM+6TIiF9ItFCHXFCyM/BfCCmN57NTIJuPg==", + "_location": "/fuzzysearch", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "fuzzysearch@^1.0.3", + "name": "fuzzysearch", + "escapedName": "fuzzysearch", + "rawSpec": "^1.0.3", + "saveSpec": null, + "fetchSpec": "^1.0.3" + }, + "_requiredBy": [ + "/simple-jekyll-search" + ], + "_resolved": "https://registry.npmjs.org/fuzzysearch/-/fuzzysearch-1.0.3.tgz", + "_shasum": "dffc80f6d6b04223f2226aa79dd194231096d008", + "_spec": "fuzzysearch@^1.0.3", + "_where": "C:\\alphazero-official.github.io\\node_modules\\simple-jekyll-search", + "author": { + "name": "Nicolas Bevacqua", + "email": "ng@bevacqua.io", + "url": "http://bevacqua.io" + }, + "bugs": { + "url": "https://github.com/bevacqua/fuzzysearch/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Tiny and blazing-fast fuzzy search in JavaScript", + "devDependencies": { + "jshint": "^2.6.0", + "tape": "^3.5.0" + }, + "homepage": "https://github.com/bevacqua/fuzzysearch", + "license": "MIT", + "name": "fuzzysearch", + "repository": { + "type": "git", + "url": "git://github.com/bevacqua/fuzzysearch.git" + }, + "scripts": { + "test": "jshint . && tape test/*.js" + }, + "version": "1.0.3" +} diff --git a/node_modules/fuzzysearch/test/fuzzysearch.js b/node_modules/fuzzysearch/test/fuzzysearch.js new file mode 100644 index 0000000..b178185 --- /dev/null +++ b/node_modules/fuzzysearch/test/fuzzysearch.js @@ -0,0 +1,14 @@ +'use strict'; + +var test = require('tape'); +var fuzzysearch = require('..'); + +test('fuzzysearch should match expectations', function (t) { + t.equal(fuzzysearch('car', 'cartwheel'), true); + t.equal(fuzzysearch('cwhl', 'cartwheel'), true); + t.equal(fuzzysearch('cwheel', 'cartwheel'), true); + t.equal(fuzzysearch('cartwheel', 'cartwheel'), true); + t.equal(fuzzysearch('cwheeel', 'cartwheel'), false); + t.equal(fuzzysearch('lw', 'cartwheel'), false); + t.end(); +}); diff --git a/node_modules/simple-jekyll-search/LICENSE.md b/node_modules/simple-jekyll-search/LICENSE.md new file mode 100644 index 0000000..7ea5087 --- /dev/null +++ b/node_modules/simple-jekyll-search/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Christian Fei + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/simple-jekyll-search/README.md b/node_modules/simple-jekyll-search/README.md new file mode 100644 index 0000000..c5925d7 --- /dev/null +++ b/node_modules/simple-jekyll-search/README.md @@ -0,0 +1,334 @@ +# [Simple-Jekyll-Search](https://www.npmjs.com/package/simple-jekyll-search) + +[![Build Status](https://img.shields.io/travis/christian-fei/Simple-Jekyll-Search/master.svg?)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search) +[![dependencies Status](https://img.shields.io/david/christian-fei/Simple-Jekyll-Search.svg)](https://david-dm.org/christian-fei/Simple-Jekyll-Search) +[![devDependencies Status](https://img.shields.io/david/dev/christian-fei/Simple-Jekyll-Search.svg)](https://david-dm.org/christian-fei/Simple-Jekyll-Search?type=dev) + +A JavaScript library to add search functionality to any Jekyll blog. + +## Use case + +You have a blog, built with Jekyll, and want a **lightweight search functionality** on your blog, purely client-side? + +*No server configurations or databases to maintain*. + +Just **5 minutes** to have a **fully working searchable blog**. + +--- + +## Installation + +### npm + +```sh +npm install simple-jekyll-search +``` + +## Getting started + +### Create `search.json` + +Place the following code in a file called `search.json` in the **root** of your Jekyll blog. (You can also get a copy [from here](/example/search.json)) + +This file will be used as a small data source to perform the searches on the client side: + +```yaml +--- +layout: none +--- +[ + {% for post in site.posts %} + { + "title" : "{{ post.title | escape }}", + "category" : "{{ post.category }}", + "tags" : "{{ post.tags | join: ', ' }}", + "url" : "{{ site.baseurl }}{{ post.url }}", + "date" : "{{ post.date }}" + } {% unless forloop.last %},{% endunless %} + {% endfor %} +] +``` + + +## Preparing the plugin + +### Add DOM elements + +SimpleJekyllSearch needs two `DOM` elements to work: + +- a search input field +- a result container to display the results + +#### Give me the code + +Here is the code you can use with the default configuration: + +You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it) + +For example in **_layouts/default.html**: + +```html + + +
    + + + +``` + + +## Usage + +Customize SimpleJekyllSearch by passing in your configuration options: + +```js +var sjs = SimpleJekyllSearch({ + searchInput: document.getElementById('search-input'), + resultsContainer: document.getElementById('results-container'), + json: '/search.json' +}) +``` + +### returns { search } + +A new instance of SimpleJekyllSearch returns an object, with the only property `search`. + +`search` is a function used to simulate a user input and display the matching results.  + +E.g.: + +```js +var sjs = SimpleJekyllSearch({ ...options }) +sjs.search('Hello') +``` + +💡 it can be used to filter posts by tags or categories! + +## Options + +Here is a list of the available options, usage questions, troubleshooting & guides. + +### searchInput (Element) [required] + +The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles. + + +### resultsContainer (Element) [required] + +The container element in which the search results should be rendered in. Typically a `
      `. + + +### json (String|JSON) [required] + +You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data. + + +### searchResultTemplate (String) [optional] + +The template of a single rendered search result. + +The templating syntax is very simple: You just enclose the properties you want to replace with curly braces. + +E.g. + +The template + +```js +var sjs = SimpleJekyllSearch({ + searchInput: document.getElementById('search-input'), + resultsContainer: document.getElementById('results-container'), + json: '/search.json', + searchResultTemplate: '
    • {title}
    • ' +}) +``` + +will render to the following + +```html +
    • Welcome to Jekyll!
    • +``` + +If the `search.json` contains this data + +```json +[ + { + "title" : "Welcome to Jekyll!", + "category" : "", + "tags" : "", + "url" : "/jekyll/update/2014/11/01/welcome-to-jekyll.html", + "date" : "2014-11-01 21:07:22 +0100" + } +] +``` + + +### templateMiddleware (Function) [optional] + +A function that will be called whenever a match in the template is found. + +It gets passed the current property name, property value, and the template. + +If the function returns a non-undefined value, it gets replaced in the template. + +This can be potentially useful for manipulating URLs etc. + +Example: + +```js +SimpleJekyllSearch({ + ... + templateMiddleware: function(prop, value, template) { + if (prop === 'bar') { + return value.replace(/^\//, '') + } + } + ... +}) +``` + +See the [tests](https://github.com/christian-fei/Simple-Jekyll-Search/blob/master/tests/Templater.test.js) for an in-depth code example + +### sortMiddleware (Function) [optional] + +A function that will be used to sort the filtered results. + +It can be used for example to group the sections together. + +Example: + +```js +SimpleJekyllSearch({ + ... + sortMiddleware: function(a, b) { + var astr = String(a.section) + "-" + String(a.caption); + var bstr = String(b.section) + "-" + String(b.caption); + return astr.localeCompare(bstr) + } + ... +}) +``` + +### noResultsText (String) [optional] + +The HTML that will be shown if the query didn't match anything. + + +### limit (Number) [optional] + +You can limit the number of posts rendered on the page. + + +### fuzzy (Boolean) [optional] + +Enable fuzzy search to allow less restrictive matching. + +### exclude (Array) [optional] + +Pass in a list of terms you want to exclude (terms will be matched against a regex, so URLs, words are allowed). + +### success (Function) [optional] + +A function called once the data has been loaded. + +### debounceTime (Number) [optional] + +Limit how many times the search function can be executed over the given time window. This is especially useful to improve the user experience when searching over a large dataset (either with rare terms or because the number of posts to display is large). If no `debounceTime` (milliseconds) is provided a search will be triggered on each keystroke. + +--- + +## If search isn't working due to invalid JSON + +- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter. + +For example: in search.json, replace + +```json +"content": "{{ page.content | strip_html | strip_newlines }}" +``` + +with + +```json +"content": "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}" +``` + +If this doesn't work when using Github pages you can try `jsonify` to make sure the content is json compatible: + +```js +"content": {{ page.content | jsonify }} +``` + +**Note: you don't need to use quotes `"` in this since `jsonify` automatically inserts them.** + + +## Enabling full-text search + +Replace `search.json` with the following code: + +```yaml +--- +layout: none +--- +[ + {% for post in site.posts %} + { + "title" : "{{ post.title | escape }}", + "category" : "{{ post.category }}", + "tags" : "{{ post.tags | join: ', ' }}", + "url" : "{{ site.baseurl }}{{ post.url }}", + "date" : "{{ post.date }}", + "content" : "{{ post.content | strip_html | strip_newlines }}" + } {% unless forloop.last %},{% endunless %} + {% endfor %} + , + {% for page in site.pages %} + { + {% if page.title != nil %} + "title" : "{{ page.title | escape }}", + "category" : "{{ page.category }}", + "tags" : "{{ page.tags | join: ', ' }}", + "url" : "{{ site.baseurl }}{{ page.url }}", + "date" : "{{ page.date }}", + "content" : "{{ page.content | strip_html | strip_newlines }}" + {% endif %} + } {% unless forloop.last %},{% endunless %} + {% endfor %} +] +``` + + + +## Development + +- `npm install` +- `npm test` + +#### Acceptance tests + +```bash +cd example; jekyll serve + +# in another tab + +npm run cypress -- run +``` + +## Contributors + +Thanks to all [contributors](https://github.com/christian-fei/Simple-Jekyll-Search/graphs/contributors) over the years! You are the best :) + +> [@daviddarnes](https://github.com/daviddarnes) +[@XhmikosR](https://github.com/XhmikosR) +[@PeterDaveHello](https://github.com/PeterDaveHello) +[@mikeybeck](https://github.com/mikeybeck) +[@egladman](https://github.com/egladman) +[@midzer](https://github.com/midzer) +[@eduardoboucas](https://github.com/eduardoboucas) +[@kremalicious](https://github.com/kremalicious) +[@tibotiber](https://github.com/tibotiber) +and many others! + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/christian-fei/Simple-Jekyll-Search.svg)](https://starchart.cc/christian-fei/Simple-Jekyll-Search) diff --git a/node_modules/simple-jekyll-search/dest/simple-jekyll-search.js b/node_modules/simple-jekyll-search/dest/simple-jekyll-search.js new file mode 100644 index 0000000..3afbb60 --- /dev/null +++ b/node_modules/simple-jekyll-search/dest/simple-jekyll-search.js @@ -0,0 +1,433 @@ +/*! + * Simple-Jekyll-Search + * Copyright 2015-2020, Christian Fei + * Licensed under the MIT License. + */ + +(function(){ +'use strict' + +var _$Templater_7 = { + compile: compile, + setOptions: setOptions +} + +const options = {} +options.pattern = /\{(.*?)\}/g +options.template = '' +options.middleware = function () {} + +function setOptions (_options) { + options.pattern = _options.pattern || options.pattern + options.template = _options.template || options.template + if (typeof _options.middleware === 'function') { + options.middleware = _options.middleware + } +} + +function compile (data) { + return options.template.replace(options.pattern, function (match, prop) { + const value = options.middleware(prop, data[prop], options.template) + if (typeof value !== 'undefined') { + return value + } + return data[prop] || match + }) +} + +'use strict'; + +function fuzzysearch (needle, haystack) { + var tlen = haystack.length; + var qlen = needle.length; + if (qlen > tlen) { + return false; + } + if (qlen === tlen) { + return needle === haystack; + } + outer: for (var i = 0, j = 0; i < qlen; i++) { + var nch = needle.charCodeAt(i); + while (j < tlen) { + if (haystack.charCodeAt(j++) === nch) { + continue outer; + } + } + return false; + } + return true; +} + +var _$fuzzysearch_1 = fuzzysearch; + +'use strict' + +/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */; + +var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy() + +function FuzzySearchStrategy () { + this.matches = function (string, crit) { + return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase()) + } +} + +'use strict' + +var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy() + +function LiteralSearchStrategy () { + this.matches = function (str, crit) { + if (!str) return false + + str = str.trim().toLowerCase() + crit = crit.trim().toLowerCase() + + return crit.split(' ').filter(function (word) { + return str.indexOf(word) >= 0 + }).length === crit.split(' ').length + } +} + +'use strict' + +var _$Repository_4 = { + put: put, + clear: clear, + search: search, + setOptions: __setOptions_4 +} + +/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */; +/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */; + +function NoSort () { + return 0 +} + +const data = [] +let opt = {} + +opt.fuzzy = false +opt.limit = 10 +opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6 +opt.sort = NoSort +opt.exclude = [] + +function put (data) { + if (isObject(data)) { + return addObject(data) + } + if (isArray(data)) { + return addArray(data) + } + return undefined +} +function clear () { + data.length = 0 + return data +} + +function isObject (obj) { + return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]' +} + +function isArray (obj) { + return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]' +} + +function addObject (_data) { + data.push(_data) + return data +} + +function addArray (_data) { + const added = [] + clear() + for (let i = 0, len = _data.length; i < len; i++) { + if (isObject(_data[i])) { + added.push(addObject(_data[i])) + } + } + return added +} + +function search (crit) { + if (!crit) { + return [] + } + return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort) +} + +function __setOptions_4 (_opt) { + opt = _opt || {} + + opt.fuzzy = _opt.fuzzy || false + opt.limit = _opt.limit || 10 + opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6 + opt.sort = _opt.sort || NoSort + opt.exclude = _opt.exclude || [] +} + +function findMatches (data, crit, strategy, opt) { + const matches = [] + for (let i = 0; i < data.length && matches.length < opt.limit; i++) { + const match = findMatchesInObject(data[i], crit, strategy, opt) + if (match) { + matches.push(match) + } + } + return matches +} + +function findMatchesInObject (obj, crit, strategy, opt) { + for (const key in obj) { + if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) { + return obj + } + } +} + +function isExcluded (term, excludedTerms) { + for (let i = 0, len = excludedTerms.length; i < len; i++) { + const excludedTerm = excludedTerms[i] + if (new RegExp(excludedTerm).test(term)) { + return true + } + } + return false +} + +/* globals ActiveXObject:false */ + +'use strict' + +var _$JSONLoader_2 = { + load: load +} + +function load (location, callback) { + const xhr = getXHR() + xhr.open('GET', location, true) + xhr.onreadystatechange = createStateChangeListener(xhr, callback) + xhr.send() +} + +function createStateChangeListener (xhr, callback) { + return function () { + if (xhr.readyState === 4 && xhr.status === 200) { + try { + callback(null, JSON.parse(xhr.responseText)) + } catch (err) { + callback(err, null) + } + } + } +} + +function getXHR () { + return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP') +} + +'use strict' + +var _$OptionsValidator_3 = function OptionsValidator (params) { + if (!validateParams(params)) { + throw new Error('-- OptionsValidator: required options missing') + } + + if (!(this instanceof OptionsValidator)) { + return new OptionsValidator(params) + } + + const requiredOptions = params.required + + this.getRequiredOptions = function () { + return requiredOptions + } + + this.validate = function (parameters) { + const errors = [] + requiredOptions.forEach(function (requiredOptionName) { + if (typeof parameters[requiredOptionName] === 'undefined') { + errors.push(requiredOptionName) + } + }) + return errors + } + + function validateParams (params) { + if (!params) { + return false + } + return typeof params.required !== 'undefined' && params.required instanceof Array + } +} + +'use strict' + +var _$utils_9 = { + merge: merge, + isJSON: isJSON +} + +function merge (defaultParams, mergeParams) { + const mergedOptions = {} + for (const option in defaultParams) { + mergedOptions[option] = defaultParams[option] + if (typeof mergeParams[option] !== 'undefined') { + mergedOptions[option] = mergeParams[option] + } + } + return mergedOptions +} + +function isJSON (json) { + try { + if (json instanceof Object && JSON.parse(JSON.stringify(json))) { + return true + } + return false + } catch (err) { + return false + } +} + +var _$src_8 = {}; +(function (window) { + 'use strict' + + let options = { + searchInput: null, + resultsContainer: null, + json: [], + success: Function.prototype, + searchResultTemplate: '
    • {title}
    • ', + templateMiddleware: Function.prototype, + sortMiddleware: function () { + return 0 + }, + noResultsText: 'No results found', + limit: 10, + fuzzy: false, + debounceTime: null, + exclude: [] + } + + let debounceTimerHandle + const debounce = function (func, delayMillis) { + if (delayMillis) { + clearTimeout(debounceTimerHandle) + debounceTimerHandle = setTimeout(func, delayMillis) + } else { + func.call() + } + } + + const requiredOptions = ['searchInput', 'resultsContainer', 'json'] + + /* removed: const _$Templater_7 = require('./Templater') */; + /* removed: const _$Repository_4 = require('./Repository') */; + /* removed: const _$JSONLoader_2 = require('./JSONLoader') */; + const optionsValidator = _$OptionsValidator_3({ + required: requiredOptions + }) + /* removed: const _$utils_9 = require('./utils') */; + + window.SimpleJekyllSearch = function (_options) { + const errors = optionsValidator.validate(_options) + if (errors.length > 0) { + throwError('You must specify the following required options: ' + requiredOptions) + } + + options = _$utils_9.merge(options, _options) + + _$Templater_7.setOptions({ + template: options.searchResultTemplate, + middleware: options.templateMiddleware + }) + + _$Repository_4.setOptions({ + fuzzy: options.fuzzy, + limit: options.limit, + sort: options.sortMiddleware, + exclude: options.exclude + }) + + if (_$utils_9.isJSON(options.json)) { + initWithJSON(options.json) + } else { + initWithURL(options.json) + } + + const rv = { + search: search + } + + typeof options.success === 'function' && options.success.call(rv) + return rv + } + + function initWithJSON (json) { + _$Repository_4.put(json) + registerInput() + } + + function initWithURL (url) { + _$JSONLoader_2.load(url, function (err, json) { + if (err) { + throwError('failed to get JSON (' + url + ')') + } + initWithJSON(json) + }) + } + + function emptyResultsContainer () { + options.resultsContainer.innerHTML = '' + } + + function appendToResultsContainer (text) { + options.resultsContainer.innerHTML += text + } + + function registerInput () { + options.searchInput.addEventListener('input', function (e) { + if (isWhitelistedKey(e.which)) { + emptyResultsContainer() + debounce(function () { search(e.target.value) }, options.debounceTime) + } + }) + } + + function search (query) { + if (isValidQuery(query)) { + emptyResultsContainer() + render(_$Repository_4.search(query), query) + } + } + + function render (results, query) { + const len = results.length + if (len === 0) { + return appendToResultsContainer(options.noResultsText) + } + for (let i = 0; i < len; i++) { + results[i].query = query + appendToResultsContainer(_$Templater_7.compile(results[i])) + } + } + + function isValidQuery (query) { + return query && query.length > 0 + } + + function isWhitelistedKey (key) { + return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1 + } + + function throwError (message) { + throw new Error('SimpleJekyllSearch --- ' + message) + } +})(window) + +}()); diff --git a/node_modules/simple-jekyll-search/dest/simple-jekyll-search.min.js b/node_modules/simple-jekyll-search/dest/simple-jekyll-search.min.js new file mode 100644 index 0000000..81df5d5 --- /dev/null +++ b/node_modules/simple-jekyll-search/dest/simple-jekyll-search.min.js @@ -0,0 +1,6 @@ +/*! + * Simple-Jekyll-Search + * Copyright 2015-2020, Christian Fei + * Licensed under the MIT License. + */ +!function(){"use strict";var f={compile:function(r){return i.template.replace(i.pattern,function(t,e){var n=i.middleware(e,r[e],i.template);return void 0!==n?n:r[e]||t})},setOptions:function(t){i.pattern=t.pattern||i.pattern,i.template=t.template||i.template,"function"==typeof t.middleware&&(i.middleware=t.middleware)}};const i={pattern:/\{(.*?)\}/g,template:"",middleware:function(){}};var n=function(t,e){var n=e.length,r=t.length;if(n{title}',templateMiddleware:Function.prototype,sortMiddleware:function(){return 0},noResultsText:"No results found",limit:10,fuzzy:!1,debounceTime:null,exclude:[]},n;const e=function(t,e){e?(clearTimeout(n),n=setTimeout(t,e)):t.call()};var r=["searchInput","resultsContainer","json"];const o=m({required:r});function u(t){d.put(t),i.searchInput.addEventListener("input",function(t){-1===[13,16,20,37,38,39,40,91].indexOf(t.which)&&(c(),e(function(){l(t.target.value)},i.debounceTime))})}function c(){i.resultsContainer.innerHTML=""}function s(t){i.resultsContainer.innerHTML+=t}function l(t){var e;(e=t)&&0 dest/simple-jekyll-search.js", + "build": "npm run browserify && npm run uglify", + "copy-example-code": "cp dest/* example/js/", + "cypress": "cypress", + "dist": "npm run build && npm run copy-example-code", + "lint": "standard", + "postbuild": "npm run copy-example-code", + "prebuild": "npm run test", + "pretest": "npm run lint", + "start": "cd example; jekyll serve", + "test": "ava", + "uglify": "uglifyjs --compress --mangle --ie8 --comments \"/^/*!/\" --output dest/simple-jekyll-search.min.js dest/simple-jekyll-search.js" + }, + "standard": { + "ignore": [ + "cypress/**", + "example/**", + "dest/**" + ] + }, + "version": "1.10.0" +} diff --git a/node_modules/simple-jekyll-search/src/JSONLoader.js b/node_modules/simple-jekyll-search/src/JSONLoader.js new file mode 100644 index 0000000..fc4e9a4 --- /dev/null +++ b/node_modules/simple-jekyll-search/src/JSONLoader.js @@ -0,0 +1,30 @@ +/* globals ActiveXObject:false */ + +'use strict' + +module.exports = { + load: load +} + +function load (location, callback) { + const xhr = getXHR() + xhr.open('GET', location, true) + xhr.onreadystatechange = createStateChangeListener(xhr, callback) + xhr.send() +} + +function createStateChangeListener (xhr, callback) { + return function () { + if (xhr.readyState === 4 && xhr.status === 200) { + try { + callback(null, JSON.parse(xhr.responseText)) + } catch (err) { + callback(err, null) + } + } + } +} + +function getXHR () { + return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP') +} diff --git a/node_modules/simple-jekyll-search/src/OptionsValidator.js b/node_modules/simple-jekyll-search/src/OptionsValidator.js new file mode 100644 index 0000000..d29a668 --- /dev/null +++ b/node_modules/simple-jekyll-search/src/OptionsValidator.js @@ -0,0 +1,34 @@ +'use strict' + +module.exports = function OptionsValidator (params) { + if (!validateParams(params)) { + throw new Error('-- OptionsValidator: required options missing') + } + + if (!(this instanceof OptionsValidator)) { + return new OptionsValidator(params) + } + + const requiredOptions = params.required + + this.getRequiredOptions = function () { + return requiredOptions + } + + this.validate = function (parameters) { + const errors = [] + requiredOptions.forEach(function (requiredOptionName) { + if (typeof parameters[requiredOptionName] === 'undefined') { + errors.push(requiredOptionName) + } + }) + return errors + } + + function validateParams (params) { + if (!params) { + return false + } + return typeof params.required !== 'undefined' && params.required instanceof Array + } +} diff --git a/node_modules/simple-jekyll-search/src/Repository.js b/node_modules/simple-jekyll-search/src/Repository.js new file mode 100644 index 0000000..8a02a2d --- /dev/null +++ b/node_modules/simple-jekyll-search/src/Repository.js @@ -0,0 +1,108 @@ +'use strict' + +module.exports = { + put: put, + clear: clear, + search: search, + setOptions: setOptions +} + +const FuzzySearchStrategy = require('./SearchStrategies/FuzzySearchStrategy') +const LiteralSearchStrategy = require('./SearchStrategies/LiteralSearchStrategy') + +function NoSort () { + return 0 +} + +const data = [] +let opt = {} + +opt.fuzzy = false +opt.limit = 10 +opt.searchStrategy = opt.fuzzy ? FuzzySearchStrategy : LiteralSearchStrategy +opt.sort = NoSort +opt.exclude = [] + +function put (data) { + if (isObject(data)) { + return addObject(data) + } + if (isArray(data)) { + return addArray(data) + } + return undefined +} +function clear () { + data.length = 0 + return data +} + +function isObject (obj) { + return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]' +} + +function isArray (obj) { + return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]' +} + +function addObject (_data) { + data.push(_data) + return data +} + +function addArray (_data) { + const added = [] + clear() + for (let i = 0, len = _data.length; i < len; i++) { + if (isObject(_data[i])) { + added.push(addObject(_data[i])) + } + } + return added +} + +function search (crit) { + if (!crit) { + return [] + } + return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort) +} + +function setOptions (_opt) { + opt = _opt || {} + + opt.fuzzy = _opt.fuzzy || false + opt.limit = _opt.limit || 10 + opt.searchStrategy = _opt.fuzzy ? FuzzySearchStrategy : LiteralSearchStrategy + opt.sort = _opt.sort || NoSort + opt.exclude = _opt.exclude || [] +} + +function findMatches (data, crit, strategy, opt) { + const matches = [] + for (let i = 0; i < data.length && matches.length < opt.limit; i++) { + const match = findMatchesInObject(data[i], crit, strategy, opt) + if (match) { + matches.push(match) + } + } + return matches +} + +function findMatchesInObject (obj, crit, strategy, opt) { + for (const key in obj) { + if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) { + return obj + } + } +} + +function isExcluded (term, excludedTerms) { + for (let i = 0, len = excludedTerms.length; i < len; i++) { + const excludedTerm = excludedTerms[i] + if (new RegExp(excludedTerm).test(term)) { + return true + } + } + return false +} diff --git a/node_modules/simple-jekyll-search/src/SearchStrategies/FuzzySearchStrategy.js b/node_modules/simple-jekyll-search/src/SearchStrategies/FuzzySearchStrategy.js new file mode 100644 index 0000000..6a9e55c --- /dev/null +++ b/node_modules/simple-jekyll-search/src/SearchStrategies/FuzzySearchStrategy.js @@ -0,0 +1,14 @@ +'use strict' + +const fuzzysearch = require('fuzzysearch') + +module.exports = new FuzzySearchStrategy() + +function FuzzySearchStrategy () { + this.matches = function (string, crit) { + if (string === null) { + return false + } + return fuzzysearch(crit.toLowerCase(), string.toLowerCase()) + } +} diff --git a/node_modules/simple-jekyll-search/src/SearchStrategies/LiteralSearchStrategy.js b/node_modules/simple-jekyll-search/src/SearchStrategies/LiteralSearchStrategy.js new file mode 100644 index 0000000..0ca0762 --- /dev/null +++ b/node_modules/simple-jekyll-search/src/SearchStrategies/LiteralSearchStrategy.js @@ -0,0 +1,13 @@ +'use strict' + +module.exports = new LiteralSearchStrategy() + +function LiteralSearchStrategy () { + this.matches = function (str, crit) { + if (!str) return false + str = str.trim().toLowerCase() + crit = crit.endsWith(' ') ? [crit.toLowerCase()] : crit.trim().toLowerCase().split(' ') + + return crit.filter(word => str.indexOf(word) >= 0).length === crit.length + } +} diff --git a/node_modules/simple-jekyll-search/src/Templater.js b/node_modules/simple-jekyll-search/src/Templater.js new file mode 100644 index 0000000..f89ea22 --- /dev/null +++ b/node_modules/simple-jekyll-search/src/Templater.js @@ -0,0 +1,29 @@ +'use strict' + +module.exports = { + compile: compile, + setOptions: setOptions +} + +const options = {} +options.pattern = /\{(.*?)\}/g +options.template = '' +options.middleware = function () {} + +function setOptions (_options) { + options.pattern = _options.pattern || options.pattern + options.template = _options.template || options.template + if (typeof _options.middleware === 'function') { + options.middleware = _options.middleware + } +} + +function compile (data) { + return options.template.replace(options.pattern, function (match, prop) { + const value = options.middleware(prop, data[prop], options.template) + if (typeof value !== 'undefined') { + return value + } + return data[prop] || match + }) +} diff --git a/node_modules/simple-jekyll-search/src/index.js b/node_modules/simple-jekyll-search/src/index.js new file mode 100644 index 0000000..8f9317f --- /dev/null +++ b/node_modules/simple-jekyll-search/src/index.js @@ -0,0 +1,138 @@ +(function (window) { + 'use strict' + + let options = { + searchInput: null, + resultsContainer: null, + json: [], + success: Function.prototype, + searchResultTemplate: '
    • {title}
    • ', + templateMiddleware: Function.prototype, + sortMiddleware: function () { + return 0 + }, + noResultsText: 'No results found', + limit: 10, + fuzzy: false, + debounceTime: null, + exclude: [], + onSearch: Function.prototype + } + + let debounceTimerHandle + const debounce = function (func, delayMillis) { + if (delayMillis) { + clearTimeout(debounceTimerHandle) + debounceTimerHandle = setTimeout(func, delayMillis) + } else { + func.call() + } + } + + const requiredOptions = ['searchInput', 'resultsContainer', 'json'] + + const templater = require('./Templater') + const repository = require('./Repository') + const jsonLoader = require('./JSONLoader') + const optionsValidator = require('./OptionsValidator')({ + required: requiredOptions + }) + const utils = require('./utils') + + window.SimpleJekyllSearch = function (_options) { + const errors = optionsValidator.validate(_options) + if (errors.length > 0) { + throwError('You must specify the following required options: ' + requiredOptions) + } + + options = utils.merge(options, _options) + + templater.setOptions({ + template: options.searchResultTemplate, + middleware: options.templateMiddleware + }) + + repository.setOptions({ + fuzzy: options.fuzzy, + limit: options.limit, + sort: options.sortMiddleware, + exclude: options.exclude + }) + + if (utils.isJSON(options.json)) { + initWithJSON(options.json) + } else { + initWithURL(options.json) + } + + const rv = { + search: search + } + + typeof options.success === 'function' && options.success.call(rv) + return rv + } + + function initWithJSON (json) { + repository.put(json) + registerInput() + } + + function initWithURL (url) { + jsonLoader.load(url, function (err, json) { + if (err) { + throwError('failed to get JSON (' + url + ')') + } + initWithJSON(json) + }) + } + + function emptyResultsContainer () { + options.resultsContainer.innerHTML = '' + } + + function appendToResultsContainer (text) { + options.resultsContainer.innerHTML += text + } + + function registerInput () { + options.searchInput.addEventListener('input', function (e) { + if (isWhitelistedKey(e.which)) { + emptyResultsContainer() + debounce(function () { search(e.target.value) }, options.debounceTime) + } + }) + } + + function search (query) { + if (isValidQuery(query)) { + emptyResultsContainer() + render(repository.search(query), query) + + typeof options.onSearch === 'function' && options.onSearch.call() + } + } + + function render (results, query) { + const len = results.length + if (len === 0) { + return appendToResultsContainer(options.noResultsText) + } + for (let i = 0; i < len; i++) { + results[i].query = query + appendToResultsContainer(templater.compile(results[i])) + } + } + + function isValidQuery (query) { + return query && query.length > 0 + } + + function isWhitelistedKey (key) { + return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1 + } + + function throwError (message) { + throw new Error('SimpleJekyllSearch --- ' + message) + } +})(window) diff --git a/node_modules/simple-jekyll-search/src/utils.js b/node_modules/simple-jekyll-search/src/utils.js new file mode 100644 index 0000000..2ff6011 --- /dev/null +++ b/node_modules/simple-jekyll-search/src/utils.js @@ -0,0 +1,28 @@ +'use strict' + +module.exports = { + merge: merge, + isJSON: isJSON +} + +function merge (defaultParams, mergeParams) { + const mergedOptions = {} + for (const option in defaultParams) { + mergedOptions[option] = defaultParams[option] + if (typeof mergeParams[option] !== 'undefined') { + mergedOptions[option] = mergeParams[option] + } + } + return mergedOptions +} + +function isJSON (json) { + try { + if (json instanceof Object && JSON.parse(JSON.stringify(json))) { + return true + } + return false + } catch (err) { + return false + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..673ef7d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,19 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "fuzzysearch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fuzzysearch/-/fuzzysearch-1.0.3.tgz", + "integrity": "sha512-s+kNWQuI3mo9OALw0HJ6YGmMbLqEufCh2nX/zzV5CrICQ/y4AwPxM+6TIiF9ItFCHXFCyM/BfCCmN57NTIJuPg==" + }, + "simple-jekyll-search": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/simple-jekyll-search/-/simple-jekyll-search-1.10.0.tgz", + "integrity": "sha512-4SdHfAjEe9mngvj4wt8A7OsF9Rl3+onHY1ruQC+bUnecbNbdvzVcAbL+UH5mE+v2CWgUb95dyZjHhyqUGSa2hA==", + "requires": { + "fuzzysearch": "^1.0.3" + } + } + } +} diff --git a/search.json b/search.json new file mode 100644 index 0000000..a9a0c78 --- /dev/null +++ b/search.json @@ -0,0 +1,14 @@ +--- +layout: none +--- +[ + {% for post in site.posts %} + { + "title" : "{{ post.title | escape }}", + "category" : "{{ post.category }}", + "tags" : "{{ post.tags | join: ', ' }}", + "url" : "{{ site.baseurl }}{{ post.url }}", + "date" : "{{ post.date }}" + } {% unless forloop.last %},{% endunless %} + {% endfor %} +] \ No newline at end of file