Last active
November 13, 2015 20:16
-
-
Save hkfoster/1d124262ba56b6b6e31f to your computer and use it in GitHub Desktop.
A full-text search engine for Ghost based on lunr.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Spectral.js 0.0.6 | |
* Full-text search for the Ghost blogging platform | |
* @author Kyle Foster (@hkfoster) | |
* @license MIT (http://www.opensource.org/licenses/mit-license.php/) | |
*/ | |
// Lunr 0.6.0 | lunrjs.com | by Oliver Nightingale | @license MIT | |
!function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.6.0",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(e<i.idx)return this.list=new t.Vector.Node(e,n,i),this.length++;for(var r=i,o=i.next;void 0!=o;){if(e<o.idx)return r.next=new t.Vector.Node(e,n,o),this.length++;r=o,o=o.next}return r.next=new t.Vector.Node(e,n,o),this.length++},t.Vector.prototype.magnitude=function(){if(this._magnitude)return this._magnitude;for(var t,e=this.list,n=0;e;)t=e.val,n+=t*t,e=e.next;return this._magnitude=Math.sqrt(n)},t.Vector.prototype.dot=function(t){for(var e=this.list,n=t.list,i=0;e&&n;)e.idx<n.idx?e=e.next:e.idx>n.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t<arguments.length;t++)e=arguments[t],~this.indexOf(e)||this.elements.splice(this.locationFor(e),0,e);this.length=this.elements.length},t.SortedSet.prototype.toArray=function(){return this.elements.slice()},t.SortedSet.prototype.map=function(t,e){return this.elements.map(t,e)},t.SortedSet.prototype.forEach=function(t,e){return this.elements.forEach(t,e)},t.SortedSet.prototype.indexOf=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]<h[r]?i++:a[i]>h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;return this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone(),i.add.apply(i,n.toArray()),i},t.SortedSet.prototype.toJSON=function(){return this.toArray()},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.Store,this.tokenStore=new t.TokenStore,this.corpusTokens=new t.SortedSet,this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var t=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,t)},t.Index.prototype.off=function(t,e){return this.eventEmitter.removeListener(t,e)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;return n._fields=e.fields,n._ref=e.ref,n.documentStore=t.Store.load(e.documentStore),n.tokenStore=t.TokenStore.load(e.tokenStore),n.corpusTokens=t.SortedSet.load(e.corpusTokens),n.pipeline=t.Pipeline.load(e.pipeline),n},t.Index.prototype.field=function(t,e){var e=e||{},n={name:t,boost:e.boost||1};return this._fields.push(n),this},t.Index.prototype.ref=function(t){return this._ref=t,this},t.Index.prototype.add=function(e,n){var i={},r=new t.SortedSet,o=e[this._ref],n=void 0===n?!0:n;this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n.name]));i[n.name]=o,t.SortedSet.prototype.add.apply(r,o)},this),this.documentStore.set(o,r),t.SortedSet.prototype.add.apply(this.corpusTokens,r.toArray());for(var s=0;s<r.length;s++){var a=r.elements[s],h=this._fields.reduce(function(t,e){var n=i[e.name].length;if(!n)return t;var r=i[e.name].filter(function(t){return t===a}).length;return t+r/n*e.boost},0);this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(t.tokenizer(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),p=Object.keys(f),d=p.length,v=0;d>v;v++)l.add(f[p[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),p=new RegExp(u),d=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,m=/^(.+?)eed$/,g=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),x=new RegExp("^"+r+i+"[^aeiouwxy]$"),k=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,_=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,O=/^(.+?)e$/,P=/ll$/,N=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=d,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=m,a=g,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=p,a.test(i)&&(n=i,a=S,h=w,u=x,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=k,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=_,a=F,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=O,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=N,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=P,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n<t.length;n++){if(!e[t.charAt(n)])return!1;e=e[t.charAt(n)]}return!0},t.TokenStore.prototype.getNode=function(t){if(!t)return{};for(var e=this.root,n=0;n<t.length;n++){if(!e[t.charAt(n)])return{};e=e[t.charAt(n)]}return e},t.TokenStore.prototype.get=function(t,e){return this.getNode(t,e).docs||{}},t.TokenStore.prototype.count=function(t,e){return Object.keys(this.get(t,e)).length},t.TokenStore.prototype.remove=function(t,e){if(t){for(var n=this.root,i=0;i<t.length;i++){if(!(t.charAt(i)in n))return;n=n[t.charAt(i)]}delete n.docs[e]}},t.TokenStore.prototype.expand=function(t,e){var n=this.getNode(t),i=n.docs||{},e=e||[];return Object.keys(i).length&&e.push(t),Object.keys(n).forEach(function(n){"docs"!==n&&e.concat(this.expand(t+n,e))},this),e},t.TokenStore.prototype.toJSON=function(){return{root:this.root,length:this.length}},function(t,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():t.lunr=e()}(this,function(){return t})}(); | |
// Transport | |
( function( root, factory ) { | |
if ( typeof define === 'function' && define.amd ) { | |
define( factory ); | |
} else if ( typeof exports === 'object' ) { | |
module.exports = factory; | |
} else { | |
root.apparition = factory( root ); | |
} | |
})( this, function( root ) { | |
'use strict'; | |
// Define main plugin variables | |
var searchForm = document.querySelector( '.search-form' ), | |
resultsCont = document.querySelector( '.search-results' ), | |
reqId = new XMLHttpRequest(), | |
feedLink = '/rss/', | |
postArray = [], | |
postID = 0, | |
searchField, | |
lastPostId, | |
searchIdx; | |
// AJAX into first page of RSS feed | |
reqId.open( 'GET', feedLink, true ); | |
reqId.onreadystatechange = function() { | |
if ( this.readyState === 4 ) { | |
if ( this.status >= 200 && this.status < 400 ) { | |
// And grab the last post ID | |
lastPostId = parseXML( this.responseText ).querySelector( 'item > guid' ).textContent; | |
// If posts were never indexed or the stored version is out of date… | |
if ( localStorage.getItem( 'lunr-index' ) === null || localStorage.getItem( 'session-id' ) !== lastPostId ) { | |
// Rebuild our search index | |
searchIdx = lunr( function() { | |
this.field( 'title', { boost: 10 } ); | |
this.field( 'desc' ); | |
this.field( 'link' ); | |
this.field( 'category' ); | |
this.field( 'date' ); | |
this.ref( 'id' ); | |
}); | |
// And trigger the indexing loop | |
getFeed(); | |
// Otherwise… | |
} else { | |
// Load up and parse stored post data | |
var storedIndex = JSON.parse( localStorage.getItem( 'lunr-index' ) ), | |
storedArray = JSON.parse( localStorage.getItem( 'post-array' ) ); | |
// Load indexed posts into lunr | |
searchIdx = lunr.Index.load( storedIndex ); | |
// Overwrite post array | |
postArray = storedArray; | |
} | |
// Only run if search form is present | |
if ( searchForm ) { | |
searchField = searchForm.querySelector( 'input[type="search"]' ); | |
// Attach our listener | |
searchForm.addEventListener( 'submit', submitHandler, false ); | |
// If current URL has search params | |
if ( getUrlParameters( 's' ) ) { | |
// Run param-based submission | |
paramHandler(); | |
} | |
// Or if the user navigates away, run param-based submission | |
window.addEventListener( 'popstate', paramHandler, false ); | |
} | |
} else { | |
// If AJAX call fails, here's your lovely error message | |
console.log( 'Error - data could not be retrieved.' ); | |
} | |
} | |
}; | |
reqId.send(); | |
reqId = null; | |
// Assemble RSS feed | |
function getFeed( pageNum, prevID ) { | |
// Define local variables | |
var page = pageNum || 1, | |
prev = prevID || '', | |
reqFeed = new XMLHttpRequest(); | |
// AJAX loop through RSS pages | |
reqFeed.open( 'GET', feedLink + page, true ); | |
reqFeed.onreadystatechange = function() { | |
if ( this.readyState === 4 ) { | |
if ( this.status >= 200 && this.status < 400 ) { | |
// Find the current page ID | |
var pageInfo = parseXML( this.responseText ), | |
currPage = pageInfo.querySelector( 'item > guid' ).textContent; | |
// Grab post data and index it | |
getPosts( pageInfo ); | |
// And if it doesn't match the previous page ID… | |
if ( currPage != prev ) { | |
// And loop through to the next page | |
getFeed( page + 1, currPage ); | |
// Otherwise… | |
} else { | |
// Remove old localStorage items | |
localStorage.removeItem( 'lunr-index' ); | |
localStorage.removeItem( 'post-array' ); | |
localStorage.removeItem( 'session-id' ); | |
// Transform our search index into JSON… | |
var indexStore = JSON.stringify( searchIdx ), | |
arrayStore = JSON.stringify( postArray ); | |
// And throw them in localStorage | |
localStorage.setItem( 'lunr-index', indexStore ); | |
localStorage.setItem( 'post-array', arrayStore ); | |
localStorage.setItem( 'session-id', lastPostId ); | |
} | |
} else { | |
// If AJAX call fails, here's your lovely error message | |
console.log( 'Error - data could not be retrieved.' ); | |
} | |
} | |
}; | |
reqFeed.send(); | |
reqFeed = null; | |
} | |
// Assemble blog posts | |
function getPosts( data ) { | |
// Define local variables | |
var items = data.querySelectorAll( 'item' ); | |
// For each item… | |
for ( var itemIndex = 0; itemIndex < items.length; itemIndex++ ) { | |
// Define its variables and build post object | |
var item = items[ itemIndex ], | |
itemCat = item.querySelector( 'category' ), | |
post = { | |
id : postID, | |
title : item.querySelector( 'title' ).textContent, | |
desc : item.querySelector( 'description' ).textContent.replace( /(<([^>]+)>)/ig, '' ).replace( /(\r\n|\n|\r)/gm, '' ), | |
date : item.querySelector( 'pubDate' ).textContent, | |
link : item.querySelector( 'link' ).textContent | |
}; | |
// Account for empty post categories | |
if ( itemCat ) { | |
post.category = itemCat.textContent; | |
} else { | |
post.category = 'Default'; | |
} | |
// Update post ID counter | |
postID++; | |
// Add the items to our index | |
searchIdx.add( post ); | |
postArray.push( post ); | |
} | |
} | |
// Build search result list items | |
function listResults( listItem ) { | |
// Define and create our search results | |
var dateObj = new Date( listItem.date ), | |
months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], | |
postDate = months[ dateObj.getMonth() ] + ' ' + dateObj.getDate() + ', ' + dateObj.getFullYear(), | |
template = '<a href="' + listItem.link + '">' + listItem.title + '</a> <span class="post-date"><time datetime="' + dateObj.toISOString() + '">' + postDate + '</time></span><br>', | |
itemLink = makeNode( template ); | |
// Then add them to the results container | |
resultsCont.appendChild( itemLink ); | |
} | |
// Get search parameters | |
function getUrlParameters( term ) { | |
var match = new RegExp( '[?&]' + term + '=([^&]*)' ).exec( window.location.search ); | |
return match && decodeURIComponent( match[ 1 ].replace( /\+/g, ' ' ) ); | |
} | |
// Submission handler | |
function submitHandler( event ) { | |
// Prevent default behavior | |
event.preventDefault(); | |
// Submit search | |
searchSubmit(); | |
// Update the browser history | |
if ( history.pushState ) { | |
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?s=' + searchField.value.toLowerCase(); | |
window.history.pushState( { path: newurl }, '', newurl ); | |
} | |
} | |
// Param-based submission handler | |
function paramHandler() { | |
// Replace search field value with query params | |
searchField.value = getUrlParameters( 's' ); | |
// Submit search | |
window.setTimeout( searchSubmit, 250 ); | |
} | |
// Universal search submit | |
function searchSubmit() { | |
// Clear out previous search results | |
document.querySelector( '.search-results' ).innerHTML = ''; | |
// Cache search results | |
var results = searchIdx.search( searchField.value.toLowerCase() ); | |
// If there are results, list ’em | |
if ( results.length ) { | |
// Loop through those results | |
for ( var resultsIndex = 0; resultsIndex < results.length; resultsIndex++ ) { | |
// And list the results | |
listResults( postArray[ results[ resultsIndex ].ref ] ); | |
} | |
// Otherwise, give them our generic “sorry” message | |
} else { | |
resultsCont.textContent = 'Sorry, we didn’t find anything. Try again.'; | |
} | |
} | |
// Node from string function | |
function makeNode( string ) { | |
var frag = document.createDocumentFragment(), | |
temp = document.createElement( 'div' ); | |
temp.innerHTML = string; | |
while ( temp.firstChild ) { frag.appendChild( temp.firstChild ); } | |
return frag; | |
} | |
// Parse XML Function | |
function parseXML( string ) { | |
var parser, xmlDoc; | |
if ( window.DOMParser ) { | |
parser = new DOMParser(); | |
xmlDoc = parser.parseFromString( string, 'text/xml' ); | |
} else { | |
xmlDoc = new ActiveXObject( 'Microsoft.XMLDOM' ); | |
xmlDoc.async = false; | |
xmlDoc.loadXML( string ); | |
} | |
return xmlDoc; | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment