/** * A simple JSON search * Requires jQuery (v 1.7+) * * @author Mat Hayward - Erskine Design * Scott Lahteine - Thinkyhead * @version 0.1-MF */ "use strict"; // // Declare a jekyllSearch singleton // var jekyllSearch = (function(){ var q, qmatch, jsonFeedUrl = '/feeds/feed.json', $searchForm, $searchInput, $searchButton, $resultTemplate, $resultsPlaceholder, $results, $foundContainer, $foundTerm, $foundCount, allowEmpty = false, showLoader = false, loadingClass = 'is--loading', self, searchTimer, odd = false, section_head = { gcode:"G-code", basics:"Getting Started", config:"Configuration", feat:"Features", devel:"Development", setting:"Settings" }; const ignore_pattern = /\b(a(ll|nd|re(n't)?)|but|can('t|not)?|d(id|oes)(n't)?|end|for|ha(d|s|ve)(n't)?|it'?s|odd|use[ds]?|even|from|man?y|more|much|some|this|tha[nt]|th[eo]se|the([mny]|ir|re|y're)?|(was|were)(n't)?|wh(at|en|ere|ich|o|y)|will|won't|other|people|(al)?though|users|your?|one|two)\b/g; // Return the public interface return { /** * Get query string parameter - taken from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript * @param {String} name * @return {String} parameter value */ getParameterByName: function(name) { var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); }, /** * Inject content into template using placeholder * @param {String} originalContent * @param {String} injection * @param {String} placeholder * @return {String} injected content */ injectContent: function(originalContent, injection, placeholder) { if (injection === undefined) injection = ''; var regex = new RegExp(placeholder, 'g'); return originalContent.replace(regex, injection); }, init: function() { self = this; if (document.location.href.indexOf('meta/search/') == -1) { setTimeout(function(){ $('#searchbox>form').css('display','inline-block'); }, 800); return; } $searchForm = $("[data-search-form]"); $searchInput = $("[data-search-input]"); $searchButton = $("[data-search-button]"); $resultTemplate = $("#search-result"); $resultsPlaceholder = $("[data-search-results]"); $foundContainer = $("[data-search-found]"); $foundTerm = $("[data-search-found-term]"); $foundCount = $("[data-search-found-count]"); // hide items found string $foundContainer.hide(); /** * Initiate search functionality. * Show results based on (q)uerystring if present. * Bind search function to form submission. */ // Get search results if q parameter is set in querystring if (self.getParameterByName('q')) { var newq = decodeURIComponent(self.getParameterByName('q')); $searchInput.val(newq); self.execSearch(newq, newq); } //$searchForm.on('submit',function(e){ return false; }); // Get search results on submission of form // TODO: Update results on change, after a pause $searchInput.change(self.onSearchChanged) .keydown(function(e){ var k = e.keyCode; if (k == 10 || k == 13) return self.onSearchChanged(e); }) .keyup(function(e){ var k = e.keyCode; if (k >= 32 || k == 8) self.onSearchKeyUp(); }); $searchButton.click(function(e) { self.onSearchChanged(e); }); self.searchFromField(); }, searchFieldString: function() { return $searchInput.val().trim(); }, searchPattern: function(str) { const patt = str.toLowerCase().replace(ignore_pattern, '').trim().replace(/\s+/g, '.+'); return new RegExp(patt); }, searchFromField: function() { var newq = self.searchFieldString(), newm = self.searchPattern(newq); self.execSearch(newq, newm); }, onSearchChanged: function(e) { e.preventDefault(); var newq = self.searchFieldString(); if (newq.length >= 3 || newq.match(/^[gm]\d+/i)) self.searchFromField(); return false; }, onSearchKeyUp: function() { if (searchTimer) { clearTimeout(searchTimer); searchTimer = 0; } var newq = self.searchFieldString(); if (newq.length >= 3 || newq.match(/^[gm]\d+/i)) searchTimer = setTimeout(self.searchFromField, 800); }, fixResultsPos: function() { $resultsPlaceholder.css('padding-top', ($("#search .overlay").height() + 6) + 'px'); $(window).scrollTop(0); }, /** * Execute search * @return null */ execSearch: function(newq, newm) { if (newq != '' || allowEmpty) { q = newq; qmatch = newm; if (showLoader) self.toggleLoadingClass(); self.getSearchResults(self.resultsProcessor()); var loc = window.location; history.replaceState({}, "marlinfw.org Search", loc.origin + '/meta/search/' + "?q=" + newq); } }, /** * Toggle loading class on results and found string * @return null */ toggleLoadingClass: function() { $resultsPlaceholder.toggleClass(loadingClass); $foundContainer.toggleClass(loadingClass); }, /** * Get Search results from JSON * @param {Function} callbackFunction * @return null */ getSearchResults: function(callbackFunction) { $.get(jsonFeedUrl, callbackFunction, 'json'); }, /** * Process search result data * @return null */ resultsProcessor: function() { var results = []; return function(data) { //console.log("Processor data", data); var resultsCount = 0, results = '', lastclass = ''; $.each(data, function(index, item) { // check if search term is in content or title const comp = (item.name + " " + item.title + ' ' + item.content + item.excerpt).toLowerCase(); if (comp.match(qmatch)) { if (item.class != lastclass) { lastclass = item.class; var fancy = section_head[item.class]; results += '

' + (fancy ? fancy : item.class) + '

'; } var result = self.populateResultContent($resultTemplate.html(), item); resultsCount++; results += result; } }); if (showLoader) self.toggleLoadingClass(); self.populateResultsString(resultsCount); self.showSearchResults(results); } }, /** * Add search results to placeholder * @param {String} results * @return null */ showSearchResults: function(results) { // Add results HTML to placeholder $resultsPlaceholder.html(results); self.fixResultsPos(); }, /** * Add results content to item template * @param {String} html * @param {object} item * @return {String} Populated HTML */ populateResultContent: function(html, item) { html = self.injectContent(html, item.title, '##Title##'); html = self.injectContent(html, item.link, '##Url##'); html = self.injectContent(html, item.excerpt, '##Excerpt##'); var extra_tags = ''; if (item.exp !== undefined) extra_tags += ''; if (item.since !== undefined) extra_tags += '' + item.since + ''; if (item.group !== undefined) extra_tags += '' + item.group + ''; if (item.requires !== undefined) $.each(item.requires.split(","), function() { extra_tags += '' + this + ''; }); html = self.injectContent(html, extra_tags, '##CustomHTML##'); var c = item.class ? item.class : ''; html = self.injectContent(html, 'item ' + (odd ? 'odd ' : '') + c, '##DivClass##'); if (item.date) html = self.injectContent(html, item.date, '##Date##'); else html = self.injectContent(html, '', '

##Date##

'); odd = !odd; return html; }, /** * Populates results string * @param {String} count * @return null */ populateResultsString: function(count) { $foundTerm.text(q); $foundCount.text(count); $foundContainer.show(); } }; // return public interface })();