PageSourceSearch

https://huchengv5.github.io/js/super-search.js

js huchengv5.github.io collected 2026-10-03 09:18:45 UTC 16,414 bytes, 520 lines download raw bytes

1/* super-search
2Author: Kushagra Gour (http://kushagragour.in)
3MIT Licensed
4
5
6
7 */
8
9(function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require === 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); throw new Error("Cannot find module '" + o + "'") } var f = n[o] = {exports: {}}; t[o][0].call(f.exports, function (e) { var n = t[o][1][e]; return s(n || e) }, f, f.exports, e, t, n, r) } return n[o].exports } var i = typeof require === 'function' && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({1: [function (require, module, exports) {
10  'use strict'
11  module.exports = {
12    load: load
13  }
14
15  function load (location, callback) {
16    var xhr = getXHR()
17    xhr.open('GET', location, true)
18    xhr.onreadystatechange = createStateChangeListener(xhr, callback)
19    xhr.send()
20  }
21
22  function createStateChangeListener (xhr, callback) {
23    return function () {
24      if (xhr.readyState === 4 && xhr.status === 200) {
25        try {
26          callback(null, JSON.parse(xhr.responseText))
27        } catch (err) {
28          callback(err, null)
29        }
30      }
31    }
32  }
33
34  function getXHR () {
35    return (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
36  }
37}, {}],
38  2: [function (require, module, exports) {
39    'use strict'
40    module.exports = function OptionsValidator (params) {
41      if (!validateParams(params)) {
42        throw new Error('-- OptionsValidator: required options missing')
43      }
44      if (!(this instanceof OptionsValidator)) {
45        return new OptionsValidator(params)
46      }
47
48      var requiredOptions = params.required
49
50      this.getRequiredOptions = function () {
51        return requiredOptions
52      }
53
54      this.validate = function (parameters) {
55        var errors = []
56        requiredOptions.forEach(function (requiredOptionName) {
57          if (parameters[requiredOptionName] === undefined) {
58            errors.push(requiredOptionName)
59          }
60        })
61        return errors
62      }
63
64      function validateParams (params) {
65        if (!params) {
66          return false
67        }
68        return params.required !== undefined && params.required instanceof Array
69      }
70    }
71  }, {}],
72  3: [function (require, module, exports) {
73    'use strict'
74    module.exports = {
75      put: put,
76      clear: clear,
77      get: get,
78      search: search,
79      setOptions: setOptions
80    }
81
82    var FuzzySearchStrategy = require('./SearchStrategies/FuzzySearchStrategy')
83    var LiteralSearchStrategy = require('./SearchStrategies/LiteralSearchStrategy')
84
85    var data = []
86    var opt = {}
87    opt.fuzzy = false
88    opt.limit = 10
89    opt.searchStrategy = opt.fuzzy ? FuzzySearchStrategy : LiteralSearchStrategy
90
91    function put (data) {
92      if (isObject(data)) {
93        return addObject(data)
94      }
95      if (isArray(data)) {
96        return addArray(data)
97      }
98      return undefined
99    }
100    function clear () {
101      data.length = 0
102      return data
103    }
104
105    function get () {
106      return data
107    }
108
109    function isObject (obj) { return !!obj && Object.prototype.toString.call(obj) === '[object Object]' }
110    function isArray (obj) { return !!obj && Object.prototype.toString.call(obj) === '[object Array]' }
111
112    function addObject (_data) {
113      data.push(_data)
114      return data
115    }
116
117    function addArray (_data) {
118      var added = []
119      for (var i = 0; i < _data.length; i++) {
120        if (isObject(_data[i])) {
121          added.push(addObject(_data[i]))
122        }
123      }
124      return added
125    }
126
127    function search (crit) {
128      if (!crit) {
129        return []
130      }
131      return findMatches(data, crit, opt.searchStrategy, opt)
132    }
133
134    function setOptions (_opt) {
135      opt = _opt || {}
136
137      opt.fuzzy = _opt.fuzzy || false
138      opt.limit = _opt.limit || 10
139      opt.searchStrategy = _opt.fuzzy ? FuzzySearchStrategy : LiteralSearchStrategy
140    }
141
142    function findMatches (data, crit, strategy, opt) {
143      var matches = []
144      for (var i = 0; i < data.length && matches.length < opt.limit; i++) {
145        var match = findMatchesInObject(data[i], crit, strategy, opt)
146        if (match) {
147          matches.push(match)
148        }
149      }
150      return matches
151    }
152
153    function findMatchesInObject (obj, crit, strategy, opt) {
154      for (var key in obj) {
155        if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
156          return obj
157        }
158      }
159    }
160
161    function isExcluded (term, excludedTerms) {
162      var excluded = false
163      excludedTerms = excludedTerms || []
164      for (var i = 0; i < excludedTerms.length; i++) {
165        var excludedTerm = excludedTerms[i]
166        if (!excluded && new RegExp(term).test(excludedTerm)) {
167          excluded = true
168        }
169      }
170      return excluded
171    }
172  }, {'./SearchStrategies/FuzzySearchStrategy': 4, './SearchStrategies/LiteralSearchStrategy': 5}],
173  4: [function (require, module, exports) {
174    'use strict'
175    module.exports = new FuzzySearchStrategy()
176
177    function FuzzySearchStrategy () {
178      this.matches = function (string, crit) {
179        if (typeof string !== 'string' || typeof crit !== 'string') {
180          return false
181        }
182        var fuzzy = fuzzyFrom(crit)
183        return !!fuzzy.test(string)
184      }
185
186      function fuzzyFrom (string) {
187        var fuzzy = string
188              .trim()
189              .split('')
190              .join('.*?')
191              .replace('??', '?')
192        return new RegExp(fuzzy, 'gi')
193      }
194    }
195  }, {}],
196  5: [function (require, module, exports) {
197    'use strict'
198    module.exports = new LiteralSearchStrategy()
199
200    function LiteralSearchStrategy () {
201      this.matches = function (string, crit) {
202        if (typeof string !== 'string') {
203          return false
204        }
205        string = string.trim()
206        return string.toLowerCase().indexOf(crit.toLowerCase()) >= 0
207      }
208    }
209  }, {}],
210  6: [function (require, module, exports) {
211    'use strict'
212    module.exports = {
213      compile: compile,
214      setOptions: setOptions
215    }
216
217    var options = {}
218    options.pattern = /\{(.*?)\}/g
219    options.template = ''
220    options.middleware = function () {}
221
222    function setOptions (_options) {
223      options.pattern = _options.pattern || options.pattern
224      options.template = _options.template || options.template
225      if (typeof _options.middleware === 'function') {
226        options.middleware = _options.middleware
227      }
228    }
229
230    function compile (data) {
231      return options.template.replace(options.pattern, function (match, prop) {
232        var value = options.middleware(prop, data[prop], options.template)
233        if (value !== undefined) {
234          return value
235        }
236        return data[prop] || match
237      })
238    }
239  }, {}],
240  7: [function (require, module, exports) {
241    ;(function (window, document, undefined) {
242      'use strict'
243
244      var options = {
245        searchInput: null,
246        resultsContainer: null,
247        json: [],
248        searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
249        templateMiddleware: function () {},
250        noResultsText: 'No results found',
251        limit: 10,
252        fuzzy: false,
253        exclude: []
254      }
255
256      var requiredOptions = ['searchInput', 'resultsContainer', 'json']
257
258      var templater = require('./Templater')
259      var repository = require('./Repository')
260      var jsonLoader = require('./JSONLoader')
261      var optionsValidator = require('./OptionsValidator')({
262        required: requiredOptions
263      })
264      var utils = require('./utils')
265
266  /*
267    Public API
268  */
269      window.SimpleJekyllSearch = function SimpleJekyllSearch (_options) {
270        var errors = optionsValidator.validate(_options)
271        if (errors.length > 0) {
272          throwError('You must specify the following required options: ' + requiredOptions)
273        }
274
275        options = utils.merge(options, _options)
276
277        templater.setOptions({
278          template: options.searchResultTemplate,
279          middleware: options.templateMiddleware
280        })
281
282        repository.setOptions({
283          fuzzy: options.fuzzy,
284          limit: options.limit
285        })
286
287        if (utils.isJSON(options.json)) {
288          initWithJSON(options.json)
289        } else {
290          initWithURL(options.json)
291        }
292      }
293
294  // for backwards compatibility
295      window.SimpleJekyllSearch.init = window.SimpleJekyllSearch
296
297      function initWithJSON (json) {
298        repository.put(json)
299        registerInput()
300      }
301
302      function initWithURL (url) {
303        jsonLoader.load(url, function (err, json) {
304          if (err) {
305            throwError('failed to get JSON (' + url + ')')
306          }
307          initWithJSON(json)
308        })
309      }
310
311      function emptyResultsContainer () {
312        options.resultsContainer.innerHTML = ''
313      }
314
315      function appendToResultsContainer (text) {
316        options.resultsContainer.innerHTML += text
317      }
318
319      function registerInput () {
320        options.searchInput.addEventListener('keyup', function (e) {
321          var key = e.which
322          var query = e.target.value
323          if (isWhitelistedKey(key) && isValidQuery(query)) {
324            emptyResultsContainer()
325            render(repository.search(query))
326          }
327        })
328      }
329
330      function render (results) {
331        if (results.length === 0) {
332          return appendToResultsContainer(options.noResultsText)
333        }
334        for (var i = 0; i < results.length; i++) {
335          appendToResultsContainer(templater.compile(results[i]))
336        }
337      }
338
339      function isValidQuery (query) {
340        return query && query.length > 0
341      }
342
343      function isWhitelistedKey (key) {
344        return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
345      }
346
347      function throwError (message) { throw new Error('SimpleJekyllSearch --- ' + message) }
348    })(window, document)
349  }, {'./JSONLoader': 1, './OptionsValidator': 2, './Repository': 3, './Templater': 6, './utils': 8}],
350  8: [function (require, module, exports) {
351    'use strict'
352    module.exports = {
353      merge: merge,
354      isJSON: isJSON
355    }
356
357    function merge (defaultParams, mergeParams) {
358      var mergedOptions = {}
359      for (var option in defaultParams) {
360        mergedOptions[option] = defaultParams[option]
361        if (mergeParams[option] !== undefined) {
362          mergedOptions[option] = mergeParams[option]
363        }
364      }
365      return mergedOptions
366    }
367
368    function isJSON (json) {
369      try {
370        if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
371          return true
372        }
373        return false
374      } catch (e) {
375        return false
376      }
377    }
378  }, {}]}, {}, [7])
379
380
381// (function () {
382//     var searchFile = '../../sitemap.xml',
383//         searchEl,
384//         searchInputEl,
385//         searchResultsEl,
386//         currentInputValue = '',
387//         lastSearchResultHash,
388//         posts = [];
389
390//     // Changes XML to JSON
391//     // Modified version from here: http://davidwalsh.name/convert-xml-json
392//     function xmlToJson(xml) {
393//         // Create the return object
394//         var obj = {};
395//         if (xml.nodeType == 3) { // text
396//             obj = xml.nodeValue;
397//         }
398
399//         // do children
400//         // If all text nodes inside, get concatenated text from them.
401//         var textNodes = [].slice.call(xml.childNodes).filter(function (node) { return node.nodeType === 3; });
402//         if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
403//             obj = [].slice.call(xml.childNodes).reduce(function (text, node) { return text + node.nodeValue; }, '');
404//         }
405//         else if (xml.hasChildNodes()) {
406//             for(var i = 0; i < xml.childNodes.length; i++) {
407//                 var item = xml.childNodes.item(i);
408//                 var nodeName = item.nodeName;
409//                 if (typeof(obj[nodeName]) == "undefined") {
410//                     obj[nodeName] = xmlToJson(item);
411//                 } else {
412//                     if (typeof(obj[nodeName].push) == "undefined") {
413//                         var old = obj[nodeName];
414//                         obj[nodeName] = [];
415//                         obj[nodeName].push(old);
416//                     }
417//                     obj[nodeName].push(xmlToJson(item));
418//                 }
419//             }
420//         }
421//         return obj;
422//     }
423
424//     function getPostsFromXml(xml) {
425//         var json = xmlToJson(xml);
426//         // Atom 1.0 format
427//         if (json.entry && json.entry instanceof Array) {
428//             return json.entry;
429//         }
430//         // Atom 2.0 format
431//         else {
432//             return json.channel.item;
433//         }
434//     }
435
436//     window.toggleSearch = function toggleSearch() {
437//         searchEl.classList.toggle('is-active');
438//         if (searchEl.classList.contains('is-active')) {
439//             // while opening
440//             searchInputEl.value = '';
441//         } else {
442//             // while closing
443//             searchResultsEl.classList.add('is-hidden');
444//         }
445//         setTimeout(function () {
446//             searchInputEl.focus();
447//         }, 210);
448//     }
449
450//     function handleInput() {
451//         var currentResultHash, d;
452
453//         currentInputValue = (searchInputEl.value + '').toLowerCase();
454//         if (!currentInputValue || currentInputValue.length < 3) {
455//             lastSearchResultHash = '';
456//             searchResultsEl.classList.add('is-hidden');
457//             return;
458//         }
459//         searchResultsEl.style.offsetWidth;
460
461//         var matchingPosts = posts.filter(function (post) {
462//             // Search `description` and `content` both to support 1.0 and 2.0 formats.
463//             if ((post.title + '').toLowerCase().indexOf(currentInputValue) !== -1 || ((post.description || post.content) + '').toLowerCase().indexOf(currentInputValue) !== -1) {
464//                 return true;
465//             }
466//         });
467//         if (!matchingPosts.length) {
468//             searchResultsEl.classList.add('is-hidden');
469//         }
470//         currentResultHash = matchingPosts.reduce(function(hash, post) { return post.t
470itle + hash; }, '');
471//         if (matchingPosts.length && currentResultHash !== lastSearchResultHash) {
472//             searchResultsEl.classList.remove('is-hidden');
473//             searchResultsEl.innerHTML = matchingPosts.map(function (post) {
474//                 d = new Date(post.pubDate);
475//                 return '<li><a href="' + post.link + '">' + post.title + '<span class="super-search__result-date">' + d.toUTCString().replace(/.*(\d{2})\s+(\w{3})\s+(\d{4}).*/,'$2 $1, $3') + '</span></a></li>';
476//             }).join('');
477//         }
478//         lastSearchResultHash = currentResultHash;
479//     }
480
481//     function init(options) {
482//         searchFile = options.searchFile || searchFile;
483//         searchEl = document.querySelector(options.searchSelector || '#js-super-search');
484//         searchInputEl = document.querySelector(options.inputSelector || '#js-super-search__input');
485//         searchResultsEl = document.querySelector(options.resultsSelector || '#js-super-search__results');
486
487//         var xmlhttp=new XMLHttpRequest();
488//         xmlhttp.open('GET', searchFile);
489//         xmlhttp.onreadystatechange = function () {
490//             if (xmlhttp.readyState != 4) return;
491//             if (xmlhttp.status != 200 && xmlhttp.status != 304) { return; }
492//             var node = (new DOMParser).parseFromString(xmlhttp.responseText, 'text/xml');
493//             node = node.children[0];
494//             posts = getPostsFromXml(node);
495//         }
496//         xmlhttp.send();
497
498//         // Toggle on ESC key
499//         window.addEventListener('keyup', function onKeyPress(e) {
500//             if (e.which === 27) {
501//                 toggleSearch();
502//             }
503//         });
504//         // Open on '/' key
505//         window.addEventListener('keypress', function onKeyPress(e) {
506//             if (e.which === 47 && !searchEl.classList.contains('is-active')) {
507//                 toggleSearch();
508//             }
509//         });
510
511//         searchInputEl.addEventListener('input', function onInputChange() {
512//             handleInput();
513//         });
514//     }
515
516//     init.toggle = toggleSearch;
517
518//     window.superSearch = init;
519
520// })();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.