You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1069 lines
33 KiB

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