module_filter.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. (function ($) {
  2. Drupal.ModuleFilter = {};
  3. Drupal.ModuleFilter.explode = function(string) {
  4. var queryArray = string.match(/([a-zA-Z]+\:(\w+|"[^"]+")*)|\w+|"[^"]+"/g);
  5. if (!queryArray) {
  6. queryArray = new Array();
  7. }
  8. var i = queryArray.length;
  9. while (i--) {
  10. queryArray[i] = queryArray[i].replace(/"/g, "");
  11. }
  12. return queryArray;
  13. };
  14. Drupal.ModuleFilter.getState = function(key) {
  15. if (!Drupal.ModuleFilter.state) {
  16. Drupal.ModuleFilter.state = {};
  17. var cookie = $.cookie('DrupalModuleFilter');
  18. var query = cookie ? cookie.split('&') : [];
  19. if (query) {
  20. for (var i in query) {
  21. // Extra check to avoid js errors in Chrome, IE and Safari when
  22. // combined with JS like twitter's widget.js.
  23. // See http://drupal.org/node/798764.
  24. if (typeof(query[i]) == 'string' && query[i].indexOf('=') != -1) {
  25. var values = query[i].split('=');
  26. if (values.length === 2) {
  27. Drupal.ModuleFilter.state[values[0]] = values[1];
  28. }
  29. }
  30. }
  31. }
  32. }
  33. return Drupal.ModuleFilter.state[key] ? Drupal.ModuleFilter.state[key] : false;
  34. };
  35. Drupal.ModuleFilter.setState = function(key, value) {
  36. var existing = Drupal.ModuleFilter.getState(key);
  37. if (existing != value) {
  38. Drupal.ModuleFilter.state[key] = value;
  39. var query = [];
  40. for (var i in Drupal.ModuleFilter.state) {
  41. query.push(i + '=' + Drupal.ModuleFilter.state[i]);
  42. }
  43. $.cookie('DrupalModuleFilter', query.join('&'), { expires: 7, path: '/' });
  44. }
  45. };
  46. Drupal.ModuleFilter.Filter = function(element, selector, options) {
  47. var self = this;
  48. this.element = element;
  49. this.text = $(this.element).val();
  50. this.settings = Drupal.settings.moduleFilter;
  51. this.selector = selector;
  52. this.options = $.extend({
  53. delay: 500,
  54. striping: false,
  55. childSelector: null,
  56. empty: Drupal.t('No results'),
  57. rules: new Array()
  58. }, options);
  59. if (this.options.wrapper == undefined) {
  60. this.options.wrapper = $(self.selector).parent();
  61. }
  62. // Add clear button.
  63. this.element.after('<div class="module-filter-clear"><a href="#" class="js-hide">' + Drupal.t('clear') + '</a></div>');
  64. if (this.text) {
  65. $('.module-filter-clear a', this.element.parent()).removeClass('js-hide');
  66. }
  67. $('.module-filter-clear a', this.element.parent()).click(function() {
  68. self.element.val('');
  69. self.text = '';
  70. delete self.queries;
  71. self.applyFilter();
  72. self.element.focus();
  73. $(this).addClass('js-hide');
  74. return false;
  75. });
  76. this.updateQueries = function() {
  77. var queryStrings = Drupal.ModuleFilter.explode(self.text);
  78. self.queries = new Array();
  79. for (var i in queryStrings) {
  80. var query = { operator: 'text', string: queryStrings[i] };
  81. if (self.operators != undefined) {
  82. // Check if an operator is possibly used.
  83. if (queryStrings[i].indexOf(':') > 0) {
  84. // Determine operator used.
  85. var args = queryStrings[i].split(':', 2);
  86. var operator = args.shift();
  87. if (self.operators[operator] != undefined) {
  88. query.operator = operator;
  89. query.string = args.shift();
  90. }
  91. }
  92. }
  93. query.string = query.string.toLowerCase();
  94. self.queries.push(query);
  95. }
  96. if (self.queries.length <= 0) {
  97. // Add a blank string query.
  98. self.queries.push({ operator: 'text', string: '' });
  99. }
  100. };
  101. this.applyFilter = function() {
  102. self.results = new Array();
  103. self.updateQueries();
  104. if (self.index == undefined) {
  105. self.buildIndex();
  106. }
  107. self.element.trigger('moduleFilter:start');
  108. $.each(self.index, function(key, item) {
  109. var $item = item.element;
  110. for (var i in self.queries) {
  111. var query = self.queries[i];
  112. if (query.operator == 'text') {
  113. if (item.text.indexOf(query.string) < 0) {
  114. continue;
  115. }
  116. }
  117. else {
  118. var func = self.operators[query.operator];
  119. if (!(func(query.string, self, item))) {
  120. continue;
  121. }
  122. }
  123. var rulesResult = self.processRules(item);
  124. if (rulesResult !== false) {
  125. return true;
  126. }
  127. }
  128. $item.addClass('js-hide');
  129. });
  130. self.element.trigger('moduleFilter:finish', { results: self.results });
  131. if (self.options.striping) {
  132. self.stripe();
  133. }
  134. if (self.results.length > 0) {
  135. self.options.wrapper.find('.module-filter-no-results').remove();
  136. }
  137. else {
  138. if (!self.options.wrapper.find('.module-filter-no-results').length) {
  139. self.options.wrapper.append($('<p class="module-filter-no-results"/>').text(self.options.empty));
  140. };
  141. }
  142. };
  143. self.element.keyup(function(e) {
  144. switch (e.which) {
  145. case 13:
  146. if (self.timeOut) {
  147. clearTimeout(self.timeOut);
  148. }
  149. self.applyFilter();
  150. break;
  151. default:
  152. if (self.text != $(this).val()) {
  153. if (self.timeOut) {
  154. clearTimeout(self.timeOut);
  155. }
  156. self.text = $(this).val();
  157. if (self.text) {
  158. self.element.parent().find('.module-filter-clear a').removeClass('js-hide');
  159. }
  160. else {
  161. self.element.parent().find('.module-filter-clear a').addClass('js-hide');
  162. }
  163. self.element.trigger('moduleFilter:keyup');
  164. self.timeOut = setTimeout(self.applyFilter, self.options.delay);
  165. }
  166. break;
  167. }
  168. });
  169. self.element.keypress(function(e) {
  170. if (e.which == 13) e.preventDefault();
  171. });
  172. };
  173. Drupal.ModuleFilter.Filter.prototype.buildIndex = function() {
  174. var self = this;
  175. var index = new Array();
  176. $(this.selector).each(function(i) {
  177. var text = (self.options.childSelector) ? $(self.options.childSelector, this).text() : $(this).text();
  178. var item = {
  179. key: i,
  180. element: $(this),
  181. text: text.toLowerCase()
  182. };
  183. for (var j in self.options.buildIndex) {
  184. var func = self.options.buildIndex[j];
  185. item = $.extend(func(self, item), item);
  186. }
  187. $(this).data('indexKey', i);
  188. index.push(item);
  189. delete item;
  190. });
  191. this.index = index;
  192. };
  193. Drupal.ModuleFilter.Filter.prototype.processRules = function(item) {
  194. var self = this;
  195. var $item = item.element;
  196. var rulesResult = true;
  197. if (self.options.rules.length > 0) {
  198. for (var i in self.options.rules) {
  199. var func = self.options.rules[i];
  200. rulesResult = func(self, item);
  201. if (rulesResult === false) {
  202. break;
  203. }
  204. }
  205. }
  206. if (rulesResult !== false) {
  207. $item.removeClass('js-hide');
  208. self.results.push(item);
  209. }
  210. return rulesResult;
  211. };
  212. Drupal.ModuleFilter.Filter.prototype.stripe = function() {
  213. var self = this;
  214. var flip = { even: 'odd', odd: 'even' };
  215. var stripe = 'odd';
  216. $.each(self.index, function(key, item) {
  217. if (!item.element.hasClass('js-hide')) {
  218. item.element.removeClass('odd even')
  219. .addClass(stripe);
  220. stripe = flip[stripe];
  221. }
  222. });
  223. };
  224. $.fn.moduleFilter = function(selector, options) {
  225. var filterInput = this;
  226. filterInput.parents('.module-filter-inputs-wrapper').show();
  227. if (Drupal.settings.moduleFilter.setFocus) {
  228. filterInput.focus();
  229. }
  230. if (Drupal.settings.moduleFilter.expandedDescription) {
  231. $('#system-modules td.description .inner.expand').addClass('expanded');
  232. }
  233. filterInput.data('moduleFilter', new Drupal.ModuleFilter.Filter(this, selector, options));
  234. };
  235. })(jQuery);