github.com/fanux/shipyard@v0.0.0-20161009071005-6515ce223235/controller/static/semantic/dist/components/search.js (about) 1 /*! 2 * # Semantic UI x.x - Search 3 * http://github.com/semantic-org/semantic-ui/ 4 * 5 * 6 * Copyright 2014 Contributors 7 * Released under the MIT license 8 * http://opensource.org/licenses/MIT 9 * 10 */ 11 12 ;(function ($, window, document, undefined) { 13 14 "use strict"; 15 16 $.fn.search = function(parameters) { 17 var 18 $allModules = $(this), 19 moduleSelector = $allModules.selector || '', 20 21 time = new Date().getTime(), 22 performance = [], 23 24 query = arguments[0], 25 methodInvoked = (typeof query == 'string'), 26 queryArguments = [].slice.call(arguments, 1), 27 returnedValue 28 ; 29 $(this) 30 .each(function() { 31 var 32 settings = $.extend(true, {}, $.fn.search.settings, parameters), 33 34 className = settings.className, 35 metadata = settings.metadata, 36 regExp = settings.regExp, 37 selector = settings.selector, 38 error = settings.error, 39 namespace = settings.namespace, 40 41 eventNamespace = '.' + namespace, 42 moduleNamespace = namespace + '-module', 43 44 $module = $(this), 45 $prompt = $module.find(selector.prompt), 46 $searchButton = $module.find(selector.searchButton), 47 $results = $module.find(selector.results), 48 $result = $module.find(selector.result), 49 $category = $module.find(selector.category), 50 51 element = this, 52 instance = $module.data(moduleNamespace), 53 54 module 55 ; 56 module = { 57 58 initialize: function() { 59 module.verbose('Initializing module'); 60 var 61 prompt = $prompt[0], 62 inputEvent = (prompt !== undefined && prompt.oninput !== undefined) 63 ? 'input' 64 : (prompt !== undefined && prompt.onpropertychange !== undefined) 65 ? 'propertychange' 66 : 'keyup' 67 ; 68 if(settings.automatic) { 69 $prompt 70 .on(inputEvent + eventNamespace, module.throttle) 71 .attr('autocomplete', 'off') 72 ; 73 } 74 $prompt 75 .on('focus' + eventNamespace, module.event.focus) 76 .on('blur' + eventNamespace, module.event.blur) 77 .on('keydown' + eventNamespace, module.handleKeyboard) 78 ; 79 $searchButton 80 .on('click' + eventNamespace, module.query) 81 ; 82 $results 83 .on('mousedown' + eventNamespace, module.event.result.mousedown) 84 .on('mouseup' + eventNamespace, module.event.result.mouseup) 85 .on('click' + eventNamespace, selector.result, module.event.result.click) 86 ; 87 module.instantiate(); 88 }, 89 instantiate: function() { 90 module.verbose('Storing instance of module', module); 91 instance = module; 92 $module 93 .data(moduleNamespace, module) 94 ; 95 }, 96 destroy: function() { 97 module.verbose('Destroying instance'); 98 $module 99 .removeData(moduleNamespace) 100 ; 101 $prompt 102 .off(eventNamespace) 103 ; 104 $searchButton 105 .off(eventNamespace) 106 ; 107 $results 108 .off(eventNamespace) 109 ; 110 }, 111 event: { 112 focus: function() { 113 module.set.focus(); 114 clearTimeout(module.timer); 115 module.throttle(); 116 if( module.has.minimumCharacters() ) { 117 module.showResults(); 118 } 119 }, 120 blur: function(event) { 121 var 122 pageLostFocus = (document.activeElement === this) 123 ; 124 if(!pageLostFocus && !module.resultsClicked) { 125 module.cancel.query(); 126 module.remove.focus(); 127 module.timer = setTimeout(module.hideResults, settings.hideDelay); 128 } 129 }, 130 result: { 131 mousedown: function() { 132 module.resultsClicked = true; 133 }, 134 mouseup: function() { 135 module.resultsClicked = false; 136 }, 137 click: function(event) { 138 module.debug('Search result selected'); 139 var 140 $result = $(this), 141 $title = $result.find(selector.title).eq(0), 142 $link = $result.find('a[href]').eq(0), 143 href = $link.attr('href') || false, 144 target = $link.attr('target') || false, 145 title = $title.html(), 146 name = ($title.length > 0) 147 ? $title.text() 148 : false, 149 results = module.get.results(), 150 result = module.get.result(name, results), 151 returnedValue 152 ; 153 if( $.isFunction(settings.onSelect) ) { 154 if(settings.onSelect.call(element, result, results) === false) { 155 module.debug('Custom onSelect callback cancelled default select action'); 156 return; 157 } 158 } 159 module.hideResults(); 160 if(name) { 161 module.set.value(name); 162 } 163 if(href) { 164 module.verbose('Opening search link found in result', $link); 165 if(target == '_blank' || event.ctrlKey) { 166 window.open(href); 167 } 168 else { 169 window.location.href = (href); 170 } 171 } 172 } 173 } 174 }, 175 handleKeyboard: function(event) { 176 var 177 // force selector refresh 178 $result = $module.find(selector.result), 179 $category = $module.find(selector.category), 180 currentIndex = $result.index( $result.filter('.' + className.active) ), 181 resultSize = $result.length, 182 183 keyCode = event.which, 184 keys = { 185 backspace : 8, 186 enter : 13, 187 escape : 27, 188 upArrow : 38, 189 downArrow : 40 190 }, 191 newIndex 192 ; 193 // search shortcuts 194 if(keyCode == keys.escape) { 195 module.verbose('Escape key pressed, blurring search field'); 196 $prompt 197 .trigger('blur') 198 ; 199 } 200 if( module.is.visible() ) { 201 if(keyCode == keys.enter) { 202 module.verbose('Enter key pressed, selecting active result'); 203 if( $result.filter('.' + className.active).length > 0 ) { 204 module.event.result.click.call($result.filter('.' + className.active), event); 205 event.preventDefault(); 206 return false; 207 } 208 } 209 else if(keyCode == keys.upArrow) { 210 module.verbose('Up key pressed, changing active result'); 211 newIndex = (currentIndex - 1 < 0) 212 ? currentIndex 213 : currentIndex - 1 214 ; 215 $category 216 .removeClass(className.active) 217 ; 218 $result 219 .removeClass(className.active) 220 .eq(newIndex) 221 .addClass(className.active) 222 .closest($category) 223 .addClass(className.active) 224 ; 225 event.preventDefault(); 226 } 227 else if(keyCode == keys.downArrow) { 228 module.verbose('Down key pressed, changing active result'); 229 newIndex = (currentIndex + 1 >= resultSize) 230 ? currentIndex 231 : currentIndex + 1 232 ; 233 $category 234 .removeClass(className.active) 235 ; 236 $result 237 .removeClass(className.active) 238 .eq(newIndex) 239 .addClass(className.active) 240 .closest($category) 241 .addClass(className.active) 242 ; 243 event.preventDefault(); 244 } 245 } 246 else { 247 // query shortcuts 248 if(keyCode == keys.enter) { 249 module.verbose('Enter key pressed, executing query'); 250 module.query(); 251 module.set.buttonPressed(); 252 $prompt.one('keyup', module.remove.buttonFocus); 253 } 254 } 255 }, 256 257 setup: { 258 api: function() { 259 var 260 apiSettings = { 261 on : false, 262 action : 'search', 263 onFailure : module.error 264 }, 265 searchHTML 266 ; 267 module.verbose('First request, initializing API'); 268 $module.api(apiSettings); 269 } 270 }, 271 272 can: { 273 useAPI: function() { 274 return $.fn.api !== undefined; 275 }, 276 transition: function() { 277 return settings.transition && $.fn.transition !== undefined && $module.transition('is supported'); 278 } 279 }, 280 281 is: { 282 empty: function() { 283 return ($results.html() === ''); 284 }, 285 visible: function() { 286 return ($results.filter(':visible').length > 0); 287 }, 288 focused: function() { 289 return ($prompt.filter(':focus').length > 0); 290 } 291 }, 292 293 get: { 294 value: function() { 295 return $prompt.val(); 296 }, 297 results: function() { 298 var 299 results = $module.data(metadata.results) 300 ; 301 return results; 302 }, 303 result: function(value, results) { 304 var 305 result = false 306 ; 307 value = value || module.get.value(); 308 results = results || module.get.results(); 309 if(settings.type === 'category') { 310 module.debug('Finding result that matches', value); 311 $.each(results, function(index, category) { 312 if($.isArray(category.results)) { 313 result = module.search.object(value, category.results)[0]; 314 if(result && result.length > 0) { 315 return true; 316 } 317 } 318 }); 319 } 320 else { 321 module.debug('Finding result in results object', value); 322 result = module.search.object(value, results)[0]; 323 } 324 return result; 325 }, 326 }, 327 328 set: { 329 focus: function() { 330 $module.addClass(className.focus); 331 }, 332 loading: function() { 333 $module.addClass(className.loading); 334 }, 335 value: function(value) { 336 module.verbose('Setting search input value', value); 337 $prompt.val(value); 338 module.query(); 339 }, 340 buttonPressed: function() { 341 $searchButton.addClass(className.pressed); 342 } 343 }, 344 345 remove: { 346 loading: function() { 347 $module.removeClass(className.loading); 348 }, 349 focus: function() { 350 $module.removeClass(className.focus); 351 }, 352 buttonPressed: function() { 353 $searchButton.removeClass(className.pressed); 354 } 355 }, 356 357 query: function() { 358 var 359 searchTerm = module.get.value(), 360 cache = module.read.cache(searchTerm) 361 ; 362 if(cache) { 363 module.debug('Reading result for ' + searchTerm + ' from cache'); 364 module.save.results(cache.results); 365 module.addResults(cache.html); 366 } 367 else { 368 module.debug('Querying for ' + searchTerm); 369 if($.isPlainObject(settings.source) || $.isArray(settings.source)) { 370 module.search.local(searchTerm); 371 } 372 else if( module.can.useAPI() ) { 373 if(settings.apiSettings) { 374 module.debug('Searching with specified API settings', settings.apiSettings); 375 module.search.remote(searchTerm); 376 } 377 else if($.api.settings.api.search !== undefined) { 378 module.debug('Searching with default search API endpoint'); 379 module.search.remote(searchTerm); 380 } 381 else { 382 module.error(error.noEndpoint); 383 } 384 } 385 else { 386 module.error(error.source); 387 } 388 settings.onSearchQuery.call(element, searchTerm); 389 } 390 }, 391 392 search: { 393 local: function(searchTerm) { 394 var 395 searchResults = module.search.object(searchTerm, settings.content), 396 searchHTML 397 ; 398 module.set.loading(); 399 module.save.results(searchResults); 400 module.debug('Returned local search results', searchResults); 401 402 searchHTML = module.generateResults({ 403 results: searchResults 404 }); 405 module.remove.loading(); 406 module.write.cache(searchTerm, { 407 html : searchHTML, 408 results : searchResults 409 }); 410 module.addResults(searchHTML); 411 }, 412 remote: function(searchTerm) { 413 var 414 apiSettings = { 415 onSuccess : function(response) { 416 module.parse.response.call(element, response, searchTerm); 417 }, 418 urlData: { 419 query: searchTerm 420 } 421 } 422 ; 423 if( !$module.api('get request') ) { 424 module.setup.api(); 425 } 426 $.extend(true, apiSettings, settings.apiSettings); 427 module.debug('Executing search', apiSettings); 428 module.cancel.query(); 429 $module 430 .api('setting', apiSettings) 431 .api('query') 432 ; 433 }, 434 object: function(searchTerm, source) { 435 var 436 results = [], 437 fullTextResults = [], 438 searchFields = $.isArray(settings.searchFields) 439 ? settings.searchFields 440 : [settings.searchFields], 441 searchExp = searchTerm.replace(regExp.escape, '\\$&'), 442 searchRegExp = new RegExp(regExp.exact + searchExp, 'i') 443 ; 444 445 source = source || settings.source; 446 447 // exit conditions on no source 448 if(source === undefined) { 449 module.error(error.source); 450 return []; 451 } 452 453 // iterate through search fields in array order 454 $.each(searchFields, function(index, field) { 455 $.each(source, function(label, content) { 456 var 457 fieldExists = (typeof content[field] == 'string'), 458 notAlreadyResult = ($.inArray(content, results) == -1 && $.inArray(content, fullTextResults) == -1) 459 ; 460 if(fieldExists && notAlreadyResult) { 461 if( content[field].match(searchRegExp) ) { 462 results.push(content); 463 } 464 else if(settings.searchFullText && module.fuzzySearch(searchTerm, content[field]) ) { 465 fullTextResults.push(content); 466 } 467 } 468 }); 469 }); 470 return $.merge(results, fullTextResults); 471 } 472 }, 473 474 fuzzySearch: function(query, term) { 475 var 476 termLength = term.length, 477 queryLength = query.length 478 ; 479 query = query.toLowerCase(); 480 term = term.toLowerCase(); 481 if(queryLength > termLength) { 482 return false; 483 } 484 if(queryLength === termLength) { 485 return (query === term); 486 } 487 search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) { 488 var 489 queryCharacter = query.charCodeAt(characterIndex) 490 ; 491 while(nextCharacterIndex < termLength) { 492 if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) { 493 continue search; 494 } 495 } 496 return false; 497 } 498 return true; 499 }, 500 501 parse: { 502 response: function(response, searchTerm) { 503 var 504 searchHTML = module.generateResults(response) 505 ; 506 module.verbose('Parsing server response', response); 507 if(response !== undefined) { 508 if(searchTerm !== undefined && response.results !== undefined) { 509 module.write.cache(searchTerm, { 510 html : searchHTML, 511 results : response.results 512 }); 513 module.save.results(response.results); 514 module.addResults(searchHTML); 515 } 516 } 517 } 518 }, 519 520 throttle: function() { 521 clearTimeout(module.timer); 522 if(module.has.minimumCharacters()) { 523 module.timer = setTimeout(module.query, settings.searchDelay); 524 } 525 else { 526 module.hideResults(); 527 } 528 }, 529 530 cancel: { 531 query: function() { 532 if( module.can.useAPI() ) { 533 $module.api('abort'); 534 } 535 } 536 }, 537 538 has: { 539 minimumCharacters: function() { 540 var 541 searchTerm = module.get.value(), 542 numCharacters = searchTerm.length 543 ; 544 return (numCharacters >= settings.minCharacters); 545 } 546 }, 547 548 read: { 549 cache: function(name) { 550 var 551 cache = $module.data(metadata.cache) 552 ; 553 if(settings.cache) { 554 module.verbose('Checking cache for generated html for query', name); 555 return (typeof cache == 'object') && (cache[name] !== undefined) 556 ? cache[name] 557 : false 558 ; 559 } 560 return false; 561 } 562 }, 563 564 save: { 565 results: function(results) { 566 module.verbose('Saving current search results to metadata', results); 567 $module.data(metadata.results, results); 568 } 569 }, 570 571 write: { 572 cache: function(name, value) { 573 var 574 cache = ($module.data(metadata.cache) !== undefined) 575 ? $module.data(metadata.cache) 576 : {} 577 ; 578 if(settings.cache) { 579 module.verbose('Writing generated html to cache', name, value); 580 cache[name] = value; 581 $module 582 .data(metadata.cache, cache) 583 ; 584 } 585 } 586 }, 587 588 addResults: function(html) { 589 if( $.isFunction(settings.onResultsAdd) ) { 590 if( settings.onResultsAdd.call($results, html) === false ) { 591 module.debug('onResultsAdd callback cancelled default action'); 592 return false; 593 } 594 } 595 $results 596 .html(html) 597 ; 598 module.showResults(); 599 }, 600 601 showResults: function() { 602 if( !module.is.visible() && module.is.focused() && !module.is.empty() ) { 603 if( module.can.transition() ) { 604 module.debug('Showing results with css animations'); 605 $results 606 .transition({ 607 animation : settings.transition + ' in', 608 duration : settings.duration, 609 queue : true 610 }) 611 ; 612 } 613 else { 614 module.debug('Showing results with javascript'); 615 $results 616 .stop() 617 .fadeIn(settings.duration, settings.easing) 618 ; 619 } 620 settings.onResultsOpen.call($results); 621 } 622 }, 623 hideResults: function() { 624 if( module.is.visible() ) { 625 if( module.can.transition() ) { 626 module.debug('Hiding results with css animations'); 627 $results 628 .transition({ 629 animation : settings.transition + ' out', 630 duration : settings.duration, 631 queue : true 632 }) 633 ; 634 } 635 else { 636 module.debug('Hiding results with javascript'); 637 $results 638 .stop() 639 .fadeOut(settings.duration, settings.easing) 640 ; 641 } 642 settings.onResultsClose.call($results); 643 } 644 }, 645 646 generateResults: function(response) { 647 module.debug('Generating html from response', response); 648 var 649 template = settings.templates[settings.type], 650 isProperObject = ($.isPlainObject(response.results) && !$.isEmptyObject(response.results)), 651 isProperArray = ($.isArray(response.results) && response.results.length > 0), 652 html = '' 653 ; 654 if(isProperObject || isProperArray ) { 655 if(settings.maxResults > 0) { 656 if(isProperObject) { 657 if(settings.type == 'standard') { 658 module.error(error.maxResults); 659 } 660 } 661 else { 662 response.results = response.results.slice(0, settings.maxResults); 663 } 664 } 665 if($.isFunction(template)) { 666 html = template(response); 667 } 668 else { 669 module.error(error.noTemplate, false); 670 } 671 } 672 else { 673 html = module.displayMessage(error.noResults, 'empty'); 674 } 675 settings.onResults.call(element, response); 676 return html; 677 }, 678 679 displayMessage: function(text, type) { 680 type = type || 'standard'; 681 module.debug('Displaying message', text, type); 682 module.addResults( settings.templates.message(text, type) ); 683 return settings.templates.message(text, type); 684 }, 685 686 setting: function(name, value) { 687 if( $.isPlainObject(name) ) { 688 $.extend(true, settings, name); 689 } 690 else if(value !== undefined) { 691 settings[name] = value; 692 } 693 else { 694 return settings[name]; 695 } 696 }, 697 internal: function(name, value) { 698 if( $.isPlainObject(name) ) { 699 $.extend(true, module, name); 700 } 701 else if(value !== undefined) { 702 module[name] = value; 703 } 704 else { 705 return module[name]; 706 } 707 }, 708 debug: function() { 709 if(settings.debug) { 710 if(settings.performance) { 711 module.performance.log(arguments); 712 } 713 else { 714 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); 715 module.debug.apply(console, arguments); 716 } 717 } 718 }, 719 verbose: function() { 720 if(settings.verbose && settings.debug) { 721 if(settings.performance) { 722 module.performance.log(arguments); 723 } 724 else { 725 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); 726 module.verbose.apply(console, arguments); 727 } 728 } 729 }, 730 error: function() { 731 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); 732 module.error.apply(console, arguments); 733 }, 734 performance: { 735 log: function(message) { 736 var 737 currentTime, 738 executionTime, 739 previousTime 740 ; 741 if(settings.performance) { 742 currentTime = new Date().getTime(); 743 previousTime = time || currentTime; 744 executionTime = currentTime - previousTime; 745 time = currentTime; 746 performance.push({ 747 'Name' : message[0], 748 'Arguments' : [].slice.call(message, 1) || '', 749 'Element' : element, 750 'Execution Time' : executionTime 751 }); 752 } 753 clearTimeout(module.performance.timer); 754 module.performance.timer = setTimeout(module.performance.display, 100); 755 }, 756 display: function() { 757 var 758 title = settings.name + ':', 759 totalTime = 0 760 ; 761 time = false; 762 clearTimeout(module.performance.timer); 763 $.each(performance, function(index, data) { 764 totalTime += data['Execution Time']; 765 }); 766 title += ' ' + totalTime + 'ms'; 767 if(moduleSelector) { 768 title += ' \'' + moduleSelector + '\''; 769 } 770 if($allModules.length > 1) { 771 title += ' ' + '(' + $allModules.length + ')'; 772 } 773 if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { 774 console.groupCollapsed(title); 775 if(console.table) { 776 console.table(performance); 777 } 778 else { 779 $.each(performance, function(index, data) { 780 console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); 781 }); 782 } 783 console.groupEnd(); 784 } 785 performance = []; 786 } 787 }, 788 invoke: function(query, passedArguments, context) { 789 var 790 object = instance, 791 maxDepth, 792 found, 793 response 794 ; 795 passedArguments = passedArguments || queryArguments; 796 context = element || context; 797 if(typeof query == 'string' && object !== undefined) { 798 query = query.split(/[\. ]/); 799 maxDepth = query.length - 1; 800 $.each(query, function(depth, value) { 801 var camelCaseValue = (depth != maxDepth) 802 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) 803 : query 804 ; 805 if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { 806 object = object[camelCaseValue]; 807 } 808 else if( object[camelCaseValue] !== undefined ) { 809 found = object[camelCaseValue]; 810 return false; 811 } 812 else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { 813 object = object[value]; 814 } 815 else if( object[value] !== undefined ) { 816 found = object[value]; 817 return false; 818 } 819 else { 820 return false; 821 } 822 }); 823 } 824 if( $.isFunction( found ) ) { 825 response = found.apply(context, passedArguments); 826 } 827 else if(found !== undefined) { 828 response = found; 829 } 830 if($.isArray(returnedValue)) { 831 returnedValue.push(response); 832 } 833 else if(returnedValue !== undefined) { 834 returnedValue = [returnedValue, response]; 835 } 836 else if(response !== undefined) { 837 returnedValue = response; 838 } 839 return found; 840 } 841 }; 842 if(methodInvoked) { 843 if(instance === undefined) { 844 module.initialize(); 845 } 846 module.invoke(query); 847 } 848 else { 849 if(instance !== undefined) { 850 instance.invoke('destroy'); 851 } 852 module.initialize(); 853 } 854 855 }) 856 ; 857 858 return (returnedValue !== undefined) 859 ? returnedValue 860 : this 861 ; 862 }; 863 864 $.fn.search.settings = { 865 866 name : 'Search Module', 867 namespace : 'search', 868 869 debug : false, 870 verbose : true, 871 performance : true, 872 873 type : 'standard', 874 minCharacters : 1, 875 876 // api config 877 apiSettings : false, 878 879 source : false, 880 searchFields : [ 881 'title', 882 'description' 883 ], 884 searchFullText : true, 885 886 automatic : 'true', 887 hideDelay : 0, 888 searchDelay : 100, 889 maxResults : 7, 890 cache : true, 891 892 transition : 'scale', 893 duration : 300, 894 easing : 'easeOutExpo', 895 896 onSelect : false, 897 onResultsAdd : false, 898 899 onSearchQuery : function(){}, 900 onResults : function(response){}, 901 902 onResultsOpen : function(){}, 903 onResultsClose : function(){}, 904 905 className: { 906 active : 'active', 907 empty : 'empty', 908 focus : 'focus', 909 loading : 'loading', 910 pressed : 'down' 911 }, 912 913 error : { 914 source : 'Cannot search. No source used, and Semantic API module was not included', 915 noResults : 'Your search returned no results', 916 logging : 'Error in debug logging, exiting.', 917 noEndpoint : 'No search endpoint was specified', 918 noTemplate : 'A valid template name was not specified.', 919 serverError : 'There was an issue with querying the server.', 920 maxResults : 'Results must be an array to use maxResults setting', 921 method : 'The method you called is not defined.' 922 }, 923 924 metadata: { 925 cache : 'cache', 926 results : 'results' 927 }, 928 929 regExp: { 930 escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, 931 exact : '(?:\s|^)' 932 }, 933 934 selector : { 935 prompt : '.prompt', 936 searchButton : '.search.button', 937 results : '.results', 938 category : '.category', 939 result : '.result', 940 title : '.title, .name' 941 }, 942 943 templates: { 944 escape: function(string) { 945 var 946 badChars = /[&<>"'`]/g, 947 shouldEscape = /[&<>"'`]/, 948 escape = { 949 "&": "&", 950 "<": "<", 951 ">": ">", 952 '"': """, 953 "'": "'", 954 "`": "`" 955 }, 956 escapedChar = function(chr) { 957 return escape[chr]; 958 } 959 ; 960 if(shouldEscape.test(string)) { 961 return string.replace(badChars, escapedChar); 962 } 963 return string; 964 }, 965 message: function(message, type) { 966 var 967 html = '' 968 ; 969 if(message !== undefined && type !== undefined) { 970 html += '' 971 + '<div class="message ' + type + '">' 972 ; 973 // message type 974 if(type == 'empty') { 975 html += '' 976 + '<div class="header">No Results</div class="header">' 977 + '<div class="description">' + message + '</div class="description">' 978 ; 979 } 980 else { 981 html += ' <div class="description">' + message + '</div>'; 982 } 983 html += '</div>'; 984 } 985 return html; 986 }, 987 category: function(response) { 988 var 989 html = '', 990 escape = $.fn.search.settings.templates.escape 991 ; 992 if(response.results !== undefined) { 993 // each category 994 $.each(response.results, function(index, category) { 995 if(category.results !== undefined && category.results.length > 0) { 996 html += '' 997 + '<div class="category">' 998 + '<div class="name">' + category.name + '</div>' 999 ; 1000 // each item inside category 1001 $.each(category.results, function(index, result) { 1002 html += '<div class="result">'; 1003 if(result.url) { 1004 html += '<a href="' + result.url + '"></a>'; 1005 } 1006 if(result.image !== undefined) { 1007 result.image = escape(result.image); 1008 html += '' 1009 + '<div class="image">' 1010 + ' <img src="' + result.image + '" alt="">' 1011 + '</div>' 1012 ; 1013 } 1014 html += '<div class="content">'; 1015 if(result.price !== undefined) { 1016 result.price = escape(result.price); 1017 html += '<div class="price">' + result.price + '</div>'; 1018 } 1019 if(result.title !== undefined) { 1020 result.title = escape(result.title); 1021 html += '<div class="title">' + result.title + '</div>'; 1022 } 1023 if(result.description !== undefined) { 1024 html += '<div class="description">' + result.description + '</div>'; 1025 } 1026 html += '' 1027 + '</div>' 1028 + '</div>' 1029 ; 1030 }); 1031 html += '' 1032 + '</div>' 1033 ; 1034 } 1035 }); 1036 if(response.action) { 1037 html += '' 1038 + '<a href="' + response.action.url + '" class="action">' 1039 + response.action.text 1040 + '</a>'; 1041 } 1042 return html; 1043 } 1044 return false; 1045 }, 1046 standard: function(response) { 1047 var 1048 html = '' 1049 ; 1050 if(response.results !== undefined) { 1051 1052 // each result 1053 $.each(response.results, function(index, result) { 1054 if(result.url) { 1055 html += '<a class="result" href="' + result.url + '">'; 1056 } 1057 else { 1058 html += '<a class="result">'; 1059 } 1060 if(result.image !== undefined) { 1061 html += '' 1062 + '<div class="image">' 1063 + ' <img src="' + result.image + '">' 1064 + '</div>' 1065 ; 1066 } 1067 html += '<div class="content">'; 1068 if(result.price !== undefined) { 1069 html += '<div class="price">' + result.price + '</div>'; 1070 } 1071 if(result.title !== undefined) { 1072 html += '<div class="title">' + result.title + '</div>'; 1073 } 1074 if(result.description !== undefined) { 1075 html += '<div class="description">' + result.description + '</div>'; 1076 } 1077 html += '' 1078 + '</div>' 1079 ; 1080 html += '</a>'; 1081 }); 1082 1083 if(response.action) { 1084 html += '' 1085 + '<a href="' + response.action.url + '" class="action">' 1086 + response.action.text 1087 + '</a>'; 1088 } 1089 return html; 1090 } 1091 return false; 1092 } 1093 } 1094 }; 1095 1096 })( jQuery, window , document );