Dashboard sipadu mbip
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

aui-live-search-debug.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. AUI.add('aui-live-search', function(A) {
  2. /**
  3. * The LiveSearch Utility allow real-time filtering for DOM elements based on
  4. * a input query.
  5. *
  6. * @module aui-live-search
  7. */
  8. var L = A.Lang,
  9. isString = L.isString,
  10. isObject = L.isObject,
  11. isFunction = L.isFunction,
  12. isValue = L.isValue,
  13. trim = L.trim,
  14. BLANK = '',
  15. DATA = 'data',
  16. DELAY = 'delay',
  17. HIDE = 'hide',
  18. INDEX = 'index',
  19. INPUT = 'input',
  20. LIVE_SEARCH = 'live-search',
  21. MATCH_REGEX = 'matchRegex',
  22. NODES = 'nodes',
  23. SEARCH_VALUE = 'searchValue',
  24. SHOW = 'show',
  25. STAR = '*',
  26. UI_SRC = A.Widget.UI_SRC,
  27. ENTER = 'ENTER',
  28. isNodeList = function(v) {
  29. return (v instanceof A.NodeList);
  30. };
  31. /**
  32. * <p><img src="assets/images/aui-live-search/main.png"/></p>
  33. *
  34. * A base class for LiveSearch, providing:
  35. * <ul>
  36. * <li>Real-time filtering for DOM elements based on a input query</li>
  37. * </ul>
  38. *
  39. * Quick Example:<br/>
  40. *
  41. * <pre><code>var instance = new A.LiveSearch({
  42. * input: '#input',
  43. * nodes: '#search .entry'
  44. * });
  45. * </code></pre>
  46. *
  47. * Check the list of <a href="LiveSearch.html#configattributes">Configuration Attributes</a> available for
  48. * LiveSearch.
  49. *
  50. * @param config {Object} Object literal specifying widget configuration properties.
  51. *
  52. * @class LiveSearch
  53. * @constructor
  54. * @extends Base
  55. */
  56. var LiveSearch = A.Component.create(
  57. {
  58. /**
  59. * Static property provides a string to identify the class.
  60. *
  61. * @property LiveSearch.NAME
  62. * @type String
  63. * @static
  64. */
  65. NAME: LIVE_SEARCH,
  66. /**
  67. * Static property used to define the default attribute
  68. * configuration for the LiveSearch.
  69. *
  70. * @property LiveSearch.ATTRS
  71. * @type Object
  72. * @static
  73. */
  74. ATTRS: {
  75. /**
  76. * <p>Function to extract the content from the node for the indexing. The
  77. * default uses the <code>node.html()</code>. In case if you need to
  78. * index the id of the nodes, here goes one example:</p>
  79. *
  80. * Example indexing the id of the node instead of the HTML:
  81. *
  82. * <pre><code>function(node) {
  83. * return node.attr('id');
  84. * }
  85. * </code></pre>
  86. *
  87. * @attribute data
  88. * @default function(node) { return node.html(); }
  89. * @type function
  90. */
  91. data: {
  92. value: function(node) {
  93. return node.html();
  94. },
  95. validator: isFunction
  96. },
  97. /**
  98. * Number of milliseconds the filter will be applied to the node list
  99. * after the user stop typing.
  100. *
  101. * @attribute delay
  102. * @default 250
  103. * @type Number
  104. */
  105. delay: {
  106. value: 250
  107. },
  108. /**
  109. * Function to be executed to hide the node when the data of that node
  110. * not matches with the filter.
  111. *
  112. * @attribute hide
  113. * @default function(node) { return node.hide(); }
  114. * @type function
  115. */
  116. hide: {
  117. value: function(node) {
  118. return node.hide();
  119. },
  120. validator: isFunction
  121. },
  122. /**
  123. * Index for the nodes content.
  124. *
  125. * @attribute index
  126. * @default []
  127. * @type Array
  128. */
  129. index: {
  130. value: [],
  131. validator: isObject
  132. },
  133. /**
  134. * The <code>value</code> of this input node is used to filter the
  135. * results.
  136. *
  137. * @attribute input
  138. * @type Node | String
  139. */
  140. input: {
  141. setter: A.one
  142. },
  143. /**
  144. * The input <code>value</code> need to matches with this RegExp to be
  145. * accept as a filter (i.e., in order to accept only digits you
  146. * could use /\d+/g).
  147. *
  148. * @attribute matchRegex
  149. * @default (.)*
  150. * @type RegExp
  151. */
  152. matchRegex: {
  153. validator: function(v) {
  154. return (v instanceof RegExp);
  155. },
  156. value: /(.)*/g
  157. },
  158. /**
  159. * Nodes to be indexed for the filtering.
  160. *
  161. * @attribute nodes
  162. * @type Node | NodeList
  163. */
  164. nodes: {
  165. setter: '_setNodes'
  166. },
  167. /**
  168. * The text value to search for
  169. *
  170. * @attribute searchValue
  171. * @type String
  172. */
  173. searchValue: {
  174. getter: '_getSearchValue',
  175. setter: String,
  176. value: ''
  177. },
  178. /**
  179. * Function to be executed to show the node when the data of that node
  180. * matches with the filter.
  181. *
  182. * @attribute show
  183. * @default function(node) { return node.show(); }
  184. * @type function
  185. */
  186. show: {
  187. value: function(node) {
  188. return node.show();
  189. },
  190. validator: isFunction
  191. }
  192. },
  193. EXTENDS: A.Base,
  194. prototype: {
  195. /**
  196. * Stores the normalized query value given from
  197. * <a href="LiveSearch.html#config__normalizeQuery">_normalizeQuery</a>.
  198. *
  199. * @property normalizedQuery
  200. * @type String
  201. * @protected
  202. */
  203. normalizedQuery: BLANK,
  204. /**
  205. * Stores the query value.
  206. *
  207. * @property query
  208. * @type String
  209. * @protected
  210. */
  211. query: BLANK,
  212. /**
  213. * Handles the <a href="YUI.html#method_later">later</a> Object.
  214. *
  215. * @property timer
  216. * @type Object
  217. * @protected
  218. */
  219. timer: null,
  220. /**
  221. * Construction logic executed during LiveSearch instantiation. Lifecycle.
  222. *
  223. * @method initializer
  224. * @protected
  225. */
  226. initializer: function() {
  227. var instance = this;
  228. instance.refreshIndex();
  229. instance._fireSearchTask = A.debounce(instance._fireSearchFn, instance.get(DELAY), instance);
  230. instance.bindUI();
  231. },
  232. /**
  233. * Bind the events on the LiveSearch UI. Lifecycle.
  234. *
  235. * @method bindUI
  236. * @protected
  237. */
  238. bindUI: function() {
  239. var instance = this;
  240. var input = instance.get(INPUT);
  241. input.on('keyup', instance._inputKeyUp, instance);
  242. instance.after('searchValueChange', instance._afterSearchValueChange);
  243. instance.publish(
  244. 'search',
  245. {
  246. defaultFn: instance._defSearchFn
  247. }
  248. );
  249. },
  250. /**
  251. * Descructor lifecycle implementation for the LiveSearch class.
  252. * Purges events attached to the node (and all child nodes).
  253. *
  254. * @method destroy
  255. * @protected
  256. */
  257. destroy: function() {
  258. var instance = this;
  259. var input = instance.get(INPUT);
  260. input.detach('keyup');
  261. },
  262. /**
  263. * Filter the <a href="LiveSearch.html#config_nodes">nodes</a> based on
  264. * the input value.
  265. *
  266. * @method filter
  267. * @param {String} query Query to filter results
  268. * @return {Array} Matched results.
  269. */
  270. filter: function(query) {
  271. var instance = this;
  272. var results = [];
  273. var nodes = instance.get(NODES);
  274. var index = instance.get(INDEX);
  275. instance.query = query;
  276. instance.normalizedQuery = instance._normalizeQuery(query);
  277. var regex = new RegExp(
  278. instance.normalizedQuery
  279. );
  280. A.each(index, function(content, index) {
  281. var node = nodes.item(index);
  282. results.push({
  283. content: content,
  284. match: regex.test(content),
  285. node: node
  286. });
  287. });
  288. return results;
  289. },
  290. /**
  291. * Refreshes the <a href="LiveSearch.html#config_index">index</a>.
  292. *
  293. * @method refreshIndex
  294. */
  295. refreshIndex: function() {
  296. var instance = this;
  297. var indexBuffer = [];
  298. var nodes = instance.get(NODES);
  299. nodes.refresh();
  300. var dataFn = instance.get(DATA);
  301. nodes.each(
  302. function(item, index, collection) {
  303. var content = dataFn.call(instance, item);
  304. indexBuffer.push(trim(content).toLowerCase());
  305. }
  306. );
  307. instance.set(INDEX, indexBuffer);
  308. },
  309. /**
  310. * Searches for the user supplied value.
  311. *
  312. * @method search
  313. * @param {String|Number} value The text to search for
  314. */
  315. search: function(value) {
  316. var instance = this;
  317. return instance.set(
  318. SEARCH_VALUE,
  319. value,
  320. {
  321. SRC: UI_SRC
  322. }
  323. );
  324. },
  325. /**
  326. * Fires after the value of the
  327. * <a href="LiveSearch.html#config_searchValue">searchValue</a> attribute changes.
  328. *
  329. * @method _afterSearchValueChange
  330. * @param {EventFacade} event
  331. * @protected
  332. */
  333. _afterSearchValueChange: function(event) {
  334. var instance = this;
  335. if (event.SRC == UI_SRC) {
  336. instance.get(INPUT).val(event.newVal);
  337. }
  338. },
  339. /**
  340. * Default method that handles the search event.
  341. *
  342. * @method _defSearchFn
  343. * @param {EventFacade} event search event facade
  344. * @protected
  345. */
  346. _defSearchFn: function(event) {
  347. var instance = this;
  348. var value = instance.get(SEARCH_VALUE);
  349. var results = instance.filter(value);
  350. A.Array.each(results, instance._iterateResults, instance);
  351. var liveSearch = A.namespace.call(event, 'liveSearch');
  352. liveSearch.results = results;
  353. },
  354. /**
  355. * Implementation for the debounced task to fire the search event.
  356. *
  357. * @method search
  358. * @param {EventFacade} event the input key event object
  359. * @protected
  360. */
  361. _fireSearchFn: function(event) {
  362. var instance = this;
  363. instance.set(SEARCH_VALUE, event.currentTarget.val());
  364. instance.fire(
  365. 'search',
  366. {
  367. liveSearch: {
  368. inputEvent: event
  369. }
  370. }
  371. );
  372. },
  373. /**
  374. * Getter method for the
  375. * <a href="LiveSearch.html#config_searchValue">searchValue</a> attribute.
  376. *
  377. * @method _getSearchValue
  378. * @param {String} value
  379. * @protected
  380. */
  381. _getSearchValue: function(value) {
  382. var instance = this;
  383. if (!isValue(value)) {
  384. value = instance.get(INPUT).val();
  385. }
  386. return value;
  387. },
  388. /**
  389. * Iterator for the result set that determines
  390. * whether to show or hide the result nodes.
  391. *
  392. * @method _iterateResults
  393. * @param {Object} item The current result item
  394. * @param {Number} index The current index of the result collection
  395. * @param {Array} result The results array being iterated
  396. * @protected
  397. */
  398. _iterateResults: function(item, index, collection) {
  399. var instance = this;
  400. var fnType = HIDE;
  401. if (item.match) {
  402. fnType = SHOW;
  403. }
  404. instance.get(fnType).call(instance, item.node);
  405. },
  406. /**
  407. * Normalize the input query. With <code>trim</code>,
  408. * <code>matchRegex</code> and replace '*' to '' (on a regex empty match
  409. * with everything like *).
  410. *
  411. * @method _normalizeQuery
  412. * @param {String} query Query to filter results
  413. * @protected
  414. * @return {String}
  415. */
  416. _normalizeQuery: function(query) {
  417. var instance = this;
  418. var matchRegex = instance.get(MATCH_REGEX);
  419. // trim the user query and lowercase it
  420. query = L.trim( query.toLowerCase() );
  421. // match with the matchRegex
  422. query = query.match(matchRegex).join(BLANK);
  423. // replace on the query '*' to '', on a regex empty match with everything like *
  424. query = query.replace(STAR, BLANK);
  425. query = A.Lang.String.escapeRegEx(query);
  426. return query;
  427. },
  428. /**
  429. * Fires the keyup event on
  430. * <a href="LiveSearch.html#config_input">input</a>.
  431. *
  432. * @method _inputKeyUp
  433. * @param {EventFacade} event keyup event facade
  434. * @protected
  435. */
  436. _inputKeyUp: function(event) {
  437. var instance = this;
  438. if (event.isKey(ENTER)) {
  439. event.halt();
  440. }
  441. instance._fireSearchTask(event);
  442. },
  443. /**
  444. * Setter for <a href="LiveSearch.html#config_nodes">nodes</a>.
  445. *
  446. * @method _setNodes
  447. * @param {Node | NodeList | String} v
  448. * @protected
  449. * @return {Node | NodeList | String}
  450. */
  451. _setNodes: function(v) {
  452. var instance = this;
  453. if (!isNodeList(v)) {
  454. if (isString(v)) {
  455. v = A.all(v);
  456. }
  457. else {
  458. v = new A.NodeList([v]);
  459. }
  460. }
  461. return v;
  462. }
  463. }
  464. }
  465. );
  466. A.LiveSearch = LiveSearch;
  467. }, '@VERSION@' ,{requires:['aui-base'], skinnable:false});