1/** 2 * Copyright (c) 2014 Dave Ross <[email protected]> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 7 * persons to whom the Software is furnished to do so, subject to the following conditions: 8 * 9 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 10 * Software. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 13 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 15 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 **/ 17 18/////////////////////// 19// LiveSearch 20/////////////////////// 21 22var LiveSearch = { 23 searchBoxes : '', 24 activeRequests : [], 25 callbacks : [], 26 27 addCallback : function(eventName, callback) { 28 if(this.callbacks[eventName] === undefined) { 29 this.callbacks[eventName] = []; 30 } 31 32 return this.callbacks[eventName].push(callback); 33 }, 34 35 invokeCallbacks : function(eventName, params) { 36 var callbackIndex; 37 if(this.callbacks[eventName] !== undefined) { 38 for(callbackIndex in this.callbacks[eventName]) { 39 params = this.callbacks[eventName][callbackIndex](params); 40 } 41 } 42 } 43}; 44 45/** 46 * Initialization for the live search plugin. 47 * Sets up the key handler and creates the search results list. 48 */ 49LiveSearch.init = function() { 50 51 // jQuery("body").append('<ul class="search_results dwls_search_results"></ul>'); 52 // this.resultsElement = jQuery('ul').filter('.dwls_search_results'); 53 54 // Add the keypress handler 55 // Using keyup because keypress doesn't recognize the backspace key 56 // and that's kind of important. 57 LiveSearch.searchBoxes = jQuery("input").filter("[name='s']").not('.no-livesearch'); 58 LiveSearch.searchBoxes.keyup(LiveSearch.handleKeypress); 59 LiveSearch.searchBoxes.focus(LiveSearch.hideResults); 60 61 if(!LiveSearch.searchBoxes.outerHeight) { 62 alert(DavesWordPressLiveSearchConfig.outdatedJQuery); 63 } 64 65 // Prevent browsers from doing autocomplete on the search field 66 LiveSearch.searchBoxes.parents('form').attr('autocomplete', 'off'); 67 LiveSearch.searchBoxes.each( function() { 68 this.autocomplete = 'off'; 69 } ); 70 71 // Hide the search results when the search box loses focus 72 jQuery("html").click(LiveSearch.hideResults); 73 LiveSearch.searchBoxes.click(function(e) {e.stopPropagation();}); 74 75 LiveSearch.compiledResultTemplate = _.template(DavesWordPressLiveSearchConfig.resultTemplate); 76 77 jQuery(window).resize(function() { 78 LiveSearch.positionResults(this); 79 }); 80 81} 82 83LiveSearch.positionResults = function() { 84 85 var topOffset; 86 var searchBox = jQuery('input:focus').first(); 87 var resultsElement = jQuery('#dwls_search_results'); 88 89 if(resultsElement && searchBox.length > 0) { 90 91 // Position the ul right under the search box 92 var searchBoxPosition = searchBox.offset(), 93 getStyle = (searchBox.closest('.style-light').length) ? 'style-light' : 'style-dark', 94 getBgStyle = (searchBox.closest('.style-light').length) ? 'style-light-bg' : 'style-dark-bg'; 95 resultsElement.addClass(getBgStyle); 96 resultsElement.wrap( "<div id='uncode-search-result' class='"+getStyle+"'></div>" ); 97 searchBoxPosition.left += parseInt(DavesWordPressLiveSearchConfig.xOffset, 10); 98 searchBoxPosition.top += searchBox.outerHeight(false) + parseInt(DavesWordPressLiveSearchConfig.yOffset, 10); 99 searchBoxPosition.top -= parseInt(jQuery('html').css('margin-top'), 10); 100 searchBoxPosition.top -= parseInt(jQuery('html').css('padding-top'), 10); 101 resultsElement.css('left', searchBoxPosition.left); 102 resultsElement.css('top', searchBoxPosition.top); 103 resultsElement.css('width', jQuery('.search-container-inner').width()); 104 resultsElement.css('display', 'block'); 105 106 // switch(DavesWordPressLiveSearchConfig.resultsDirection) 107 // { 108 // case 'up': 109 // topOffset = searchBoxPosition.top - resultsElement.height(); 110 // break;
111 // case 'down': 112 // topOffset = searchBoxPosition.top + LiveSearch.searchBoxes.outerHeight(); 113 // break; 114 // default: 115 // topOffset = searchBoxPosition.top + LiveSearch.searchBoxes.outerHeight(); 116 // } 117 118 resultsElement.css('top', topOffset + 'px'); 119 120 } 121}; 122 123/** 124 * Process the search results that came back from the AJAX call 125 */ 126LiveSearch.handleAJAXResults = function(e) { 127 128 var renderedResult = ''; 129 LiveSearch.activeRequests.pop(); 130 131 if(e) { 132 resultsSearchTerm = e.searchTerms; 133 if(resultsSearchTerm != jQuery('input:focus').first().val()) { 134 135 if(LiveSearch.activeRequests.length === 0) { 136 LiveSearch.removeIndicator(); 137 } 138 139 return; 140 } 141 142 var resultsShownFor = jQuery('#dwls_search_results').children("input[name=query]").val(); 143 if(resultsShownFor !== "" && resultsSearchTerm == resultsShownFor) 144 { 145 if(LiveSearch.activeRequests.length === 0) { 146 LiveSearch.removeIndicator(); 147 } 148 149 return; 150 } 151 152 // var searchResultsList = jQuery("ul").filter(".dwls_search_results"); 153 // searchResultsList.empty(); 154 // searchResultsList.append(''); 155 156 if(e.results.length === 0) { 157 // Hide the search results, no results to show 158 LiveSearch.hideResults(); 159 } 160 else { 161 // Render the result template 162 renderedResult = LiveSearch.compiledResultTemplate({ 163 'searchResults': e.results, 164 'e': e, 165 'resultsSearchTerm': resultsSearchTerm 166 }); 167 168 169 // if(searchResult.show_more !== undefined && searchResult.show_more && DavesWordPressLiveSearchConfig.showMoreResultsLink == "true") { 170 // // "more" link 171 // renderedResult += '<div class="clearfix search_footer"><a href="' + DavesWordPressLiveSearchConfig.blogURL + '/?s=' + resultsSearchTerm + '">' + DavesWordPressLiveSearchConfig.viewMoreText + '</a></div>'; 172 // } 173 var existingResultsElement = jQuery('#dwls_search_results'); 174 if(existingResultsElement.length > 0) { 175 jQuery('#dwls_search_results').replaceWith(renderedResult); 176 } 177 else { 178 jQuery('body').append(renderedResult); 179 } 180 LiveSearch.positionResults(); 181 182 // I'm not comfortable changing the HTML for the results list yet 183 // so I'm using this click handler to make clicking the result li act the 184 // same as clicking the title link 185 jQuery('#dwls_search_results').bind('click.dwls', function() { 186 window.location.href = jQuery(this).find('a.daves-wordpress-live-search_title').attr('href'); 187 }); 188 } 189 190 if(LiveSearch.activeRequests.length === 0) { 191 LiveSearch.removeIndicator(); 192 } 193 } 194}; 195 196/** 197 * Keypress handler. Sets up a 0 sec. timeout which then 198 * kicks off the actual query.s 199 */ 200LiveSearch.handleKeypress = function(e) { 201 var delayTime = 0; 202 var term = LiveSearch.searchBoxes.val(); 203 setTimeout( function() {LiveSearch.runQuery(term);}, delayTime); 204}; 205 206/** 207 * Do the AJAX request for search results, or hide the search results 208 * if the search box is empty. 209 */ 210LiveSearch.runQuery = function(terms) { 211 var searchBox = jQuery('input:focus'); 212 var srch = searchBox.val(); 213 var fieldIndex; 214 var req; 215 216 if(srch != undefined && (srch === "" || srch.length < DavesWordPressLiveSearchConfig.minCharsToSearch)) { 217 // Nothing entered. Hide the autocomplete. 218 LiveSearch.hideResults(); 219 LiveSearch.removeIndicator(); 220 } 221 else { 222 // Do an autocomplete lookup 223 LiveSearch.displayIndicator(); 224 225 // Clear out the old requests in the queue 226 while(LiveSearch.activeRequests.length > 0) 227 { 228 req = LiveSearch.activeRequests.pop(); 229 req.abort(); 230 } 231 232 // Marshall the parameters into an object 233 var parameters = {}; 234 var fields = searchBox.parents('form').find('input:not(:submit),select,textarea'); 235 for(fieldIndex in fields) { 236 if(fields.hasOwnProperty(fieldIndex) && /* test for integer */ fieldIndex % 1 === 0) { 237 var field = jQuery(fields[fieldIndex]); 238 parameters[field.attr('name')] = field.val(); 239 } 240 } 241 242 // For wp_ajax 243 parameters.action = "dwls_search"; 244 245 // Do the AJAX call 246 req = jQuery.get( DavesWordPressLiveSearchConfig.ajaxURL, parameters, LiveSearch.handleAJAXResults, "json"); 247 req.fail = LiveSearch.ajaxFailHandler; 248 249 // Add this request to the queue 250 LiveSearch.activeRequests.push(req); 251 } 252}; 253 254LiveSearch.ajaxFailHandler = function(data) { 255 256 console.log("Dave's WordPress Live Search: There was an error retrieving or parsing search results"); 257 console.log("The data returned was:"); 258 console.log(data); 259 260}; 261 262LiveSearch.hideResults = function() { 263 var visibleResults = jQuery("#uncode-search-result"); 264 265 if(visibleResults.length > 0) { 266 LiveSearch.invokeCallbacks('BeforeHideResults'); 267 switch(DavesWordPressLiveSearchConfig.resultsDirection) 268 { 269 case 'up': 270 visibleResults.fadeOut('normal', function() { 271 visibleResults.remove(); 272 LiveSearch.invokeCallbacks('AfterHideResults'); 273 }); 274 break; 275 case 'down': 276 visibleResults.slideUp('normal', function() { 277 visibleResults.remove(); 278 LiveSearch.invokeCallbacks('AfterHideResults'); 279 }); 280 break; 281 default: 282 visibleResults.slideUp('normal', function() { 283 visibleResults.remove(); 284 LiveSearch.invokeCallbacks('AfterHideResults'); 285 }); 286 } 287 } 288}; 289 290/** 291 * Display the "spinning wheel" AJAX activity indicator 292 */ 293LiveSearch.displayIndicator = function() { 294
295 if(jQuery(".search_results_activity_indicator").length === 0) { 296 var searchBox = jQuery('.uncode-live-search input'); 297 var searchBoxPosition = searchBox.offset(); 298 jQuery('.uncode-live-search i').css('opacity',0); 299 if (searchBoxPosition != undefined) { 300 var getStyle = (searchBox.closest('.style-light').length) ? 'style-light' : 'style-dark'; 301 jQuery("body").append('<span id="search_results_activity_indicator" class="search_results_activity_indicator '+getStyle+'" />'); 302 303 jQuery(".search_results_activity_indicator").css('position', 'absolute').css('z-index', 9999); 304 305 var getAdminBar = parseInt(jQuery('html').css('margin-top'), 10); 306 getAdminBar += parseInt(jQuery('html').css('padding-top'), 10); 307 var indicatorY = (searchBoxPosition.top + ((searchBox.outerHeight() - searchBox.innerHeight()) / 2) + 12 - getAdminBar + 'px'); 308 309 jQuery(".search_results_activity_indicator").css('top', indicatorY); 310 311 var indicatorX = (searchBoxPosition.left + searchBox.outerWidth() - (jQuery(".search_results_activity_indicator").width())) - 20 + 'px'; 312 313 jQuery(".search_results_activity_indicator").css('left', indicatorX); 314 } 315 316 } 317 318}; 319 320/** 321 * Hide the "spinning wheel" AJAX activity indicator 322 */ 323LiveSearch.removeIndicator = function() { 324 jQuery('.uncode-live-search i').css('opacity',1); 325 jQuery(".search_results_activity_indicator").remove(); 326}; 327 328/////////////////// 329// Initialization 330/////////////////// 331 332jQuery(function() { 333 LiveSearch.init(); 334});
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.