2
0

globalSearch.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import { TAPi18n } from '/imports/i18n';
  2. import { CardSearchPagedComponent } from '../../lib/cardSearch';
  3. import Boards from '../../../models/boards';
  4. import { Query, QueryErrors } from '../../../config/query-classes';
  5. // const subManager = new SubsManager();
  6. BlazeComponent.extendComponent({
  7. events() {
  8. return [
  9. {
  10. 'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
  11. },
  12. ];
  13. },
  14. }).register('globalSearchHeaderBar');
  15. Template.globalSearch.helpers({
  16. userId() {
  17. return Meteor.userId();
  18. },
  19. });
  20. class GlobalSearchComponent extends CardSearchPagedComponent {
  21. onCreated() {
  22. super.onCreated();
  23. this.myLists = new ReactiveVar([]);
  24. this.myLabelNames = new ReactiveVar([]);
  25. this.myBoardNames = new ReactiveVar([]);
  26. this.parsingErrors = new QueryErrors();
  27. this.queryParams = null;
  28. Meteor.call('myLists', (err, data) => {
  29. if (!err) {
  30. this.myLists.set(data);
  31. }
  32. });
  33. Meteor.call('myLabelNames', (err, data) => {
  34. if (!err) {
  35. this.myLabelNames.set(data);
  36. }
  37. });
  38. Meteor.call('myBoardNames', (err, data) => {
  39. if (!err) {
  40. this.myBoardNames.set(data);
  41. }
  42. });
  43. }
  44. onRendered() {
  45. Meteor.subscribe('setting');
  46. // eslint-disable-next-line no-console
  47. //console.log('lang:', TAPi18n.getLanguage());
  48. if (Session.get('globalQuery')) {
  49. this.searchAllBoards(Session.get('globalQuery'));
  50. }
  51. }
  52. resetSearch() {
  53. super.resetSearch();
  54. this.parsingErrors = new QueryErrors();
  55. }
  56. errorMessages() {
  57. if (this.parsingErrors.hasErrors()) {
  58. return this.parsingErrors.errorMessages();
  59. }
  60. return this.queryErrorMessages();
  61. }
  62. parsingErrorMessages() {
  63. this.parsingErrors.errorMessages();
  64. }
  65. searchAllBoards(queryText) {
  66. queryText = queryText.trim();
  67. // eslint-disable-next-line no-console
  68. //console.log('queryText:', queryText);
  69. this.query.set(queryText);
  70. this.resetSearch();
  71. if (!queryText) {
  72. return;
  73. }
  74. this.searching.set(true);
  75. const query = new Query();
  76. query.buildParams(queryText);
  77. // eslint-disable-next-line no-console
  78. // console.log('params:', query.getParams());
  79. this.queryParams = query.getQueryParams().getParams();
  80. if (query.hasErrors()) {
  81. this.searching.set(false);
  82. this.queryErrors = query.errors();
  83. this.hasResults.set(true);
  84. this.hasQueryErrors.set(true);
  85. return;
  86. }
  87. this.runGlobalSearch(query.getQueryParams());
  88. }
  89. searchInstructions() {
  90. const tags = {
  91. operator_board: TAPi18n.__('operator-board'),
  92. operator_list: TAPi18n.__('operator-list'),
  93. operator_swimlane: TAPi18n.__('operator-swimlane'),
  94. operator_comment: TAPi18n.__('operator-comment'),
  95. operator_label: TAPi18n.__('operator-label'),
  96. operator_label_abbrev: TAPi18n.__('operator-label-abbrev'),
  97. operator_user: TAPi18n.__('operator-user'),
  98. operator_user_abbrev: TAPi18n.__('operator-user-abbrev'),
  99. operator_member: TAPi18n.__('operator-member'),
  100. operator_member_abbrev: TAPi18n.__('operator-member-abbrev'),
  101. operator_assignee: TAPi18n.__('operator-assignee'),
  102. operator_assignee_abbrev: TAPi18n.__('operator-assignee-abbrev'),
  103. operator_creator: TAPi18n.__('operator-creator'),
  104. operator_due: TAPi18n.__('operator-due'),
  105. operator_created: TAPi18n.__('operator-created'),
  106. operator_modified: TAPi18n.__('operator-modified'),
  107. operator_status: TAPi18n.__('operator-status'),
  108. operator_has: TAPi18n.__('operator-has'),
  109. operator_sort: TAPi18n.__('operator-sort'),
  110. operator_limit: TAPi18n.__('operator-limit'),
  111. operator_debug: TAPi18n.__('operator-debug'),
  112. operator_org: TAPi18n.__('operator-org'),
  113. operator_team: TAPi18n.__('operator-team'),
  114. predicate_overdue: TAPi18n.__('predicate-overdue'),
  115. predicate_archived: TAPi18n.__('predicate-archived'),
  116. predicate_all: TAPi18n.__('predicate-all'),
  117. predicate_ended: TAPi18n.__('predicate-ended'),
  118. predicate_week: TAPi18n.__('predicate-week'),
  119. predicate_month: TAPi18n.__('predicate-month'),
  120. predicate_quarter: TAPi18n.__('predicate-quarter'),
  121. predicate_year: TAPi18n.__('predicate-year'),
  122. predicate_attachment: TAPi18n.__('predicate-attachment'),
  123. predicate_description: TAPi18n.__('predicate-description'),
  124. predicate_checklist: TAPi18n.__('predicate-checklist'),
  125. predicate_public: TAPi18n.__('predicate-public'),
  126. predicate_private: TAPi18n.__('predicate-private'),
  127. predicate_due: TAPi18n.__('predicate-due'),
  128. predicate_created: TAPi18n.__('predicate-created'),
  129. predicate_modified: TAPi18n.__('predicate-modified'),
  130. predicate_start: TAPi18n.__('predicate-start'),
  131. predicate_end: TAPi18n.__('predicate-end'),
  132. predicate_assignee: TAPi18n.__('predicate-assignee'),
  133. predicate_member: TAPi18n.__('predicate-member'),
  134. predicate_selector: TAPi18n.__('predicate-selector'),
  135. predicate_projection: TAPi18n.__('predicate-projection'),
  136. };
  137. let text = '';
  138. [
  139. ['# ', 'globalSearch-instructions-heading'],
  140. ['\n', 'globalSearch-instructions-description'],
  141. ['\n\n', 'globalSearch-instructions-operators'],
  142. ['\n- ', 'globalSearch-instructions-operator-board'],
  143. ['\n- ', 'globalSearch-instructions-operator-list'],
  144. ['\n- ', 'globalSearch-instructions-operator-swimlane'],
  145. ['\n- ', 'globalSearch-instructions-operator-comment'],
  146. ['\n- ', 'globalSearch-instructions-operator-label'],
  147. ['\n- ', 'globalSearch-instructions-operator-hash'],
  148. ['\n- ', 'globalSearch-instructions-operator-user'],
  149. ['\n- ', 'globalSearch-instructions-operator-at'],
  150. ['\n- ', 'globalSearch-instructions-operator-member'],
  151. ['\n- ', 'globalSearch-instructions-operator-assignee'],
  152. ['\n- ', 'globalSearch-instructions-operator-creator'],
  153. ['\n- ', 'globalSearch-instructions-operator-org'],
  154. ['\n- ', 'globalSearch-instructions-operator-team'],
  155. ['\n- ', 'globalSearch-instructions-operator-due'],
  156. ['\n- ', 'globalSearch-instructions-operator-created'],
  157. ['\n- ', 'globalSearch-instructions-operator-modified'],
  158. ['\n- ', 'globalSearch-instructions-operator-status'],
  159. ['\n - ', 'globalSearch-instructions-status-archived'],
  160. ['\n - ', 'globalSearch-instructions-status-public'],
  161. ['\n - ', 'globalSearch-instructions-status-private'],
  162. ['\n - ', 'globalSearch-instructions-status-all'],
  163. ['\n - ', 'globalSearch-instructions-status-ended'],
  164. ['\n- ', 'globalSearch-instructions-operator-has'],
  165. ['\n- ', 'globalSearch-instructions-operator-sort'],
  166. ['\n- ', 'globalSearch-instructions-operator-limit'],
  167. ['\n## ', 'heading-notes'],
  168. ['\n- ', 'globalSearch-instructions-notes-1'],
  169. ['\n- ', 'globalSearch-instructions-notes-2'],
  170. ['\n- ', 'globalSearch-instructions-notes-3'],
  171. ['\n- ', 'globalSearch-instructions-notes-3-2'],
  172. ['\n- ', 'globalSearch-instructions-notes-4'],
  173. ['\n- ', 'globalSearch-instructions-notes-5'],
  174. ].forEach(([prefix, instruction]) => {
  175. text += `${prefix}${TAPi18n.__(instruction, tags)}`
  176. // Replace *<text>* with `<text>` so markdown shows correctly
  177. .replace(/\*\</, '`<')
  178. .replace(/\>\*/, '\>\`')
  179. });
  180. return text;
  181. }
  182. labelColors() {
  183. return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map(
  184. color => {
  185. return { color, name: TAPi18n.__(`color-${color}`) };
  186. },
  187. );
  188. }
  189. events() {
  190. return super.events().concat([
  191. {
  192. 'submit .js-search-query-form'(evt) {
  193. evt.preventDefault();
  194. this.searchAllBoards(evt.target.searchQuery.value);
  195. },
  196. 'click .js-label-color'(evt) {
  197. evt.preventDefault();
  198. const input = document.getElementById('global-search-input');
  199. this.query.set(
  200. `${input.value} ${TAPi18n.__('operator-label')}:"${
  201. evt.currentTarget.textContent
  202. }"`,
  203. );
  204. document.getElementById('global-search-input').focus();
  205. },
  206. 'click .js-copy-debug-selector'(evt) {
  207. /* Get the text field */
  208. const selector = document.getElementById("debug-selector");
  209. try {
  210. navigator.clipboard.writeText(selector.textContent);
  211. alert("Selector copied to clipboard");
  212. } catch(err) {
  213. alert("Error copying text: " + err);
  214. }
  215. },
  216. 'click .js-copy-debug-projection'(evt) {
  217. /* Get the text field */
  218. const projection = document.getElementById("debug-projection");
  219. try {
  220. navigator.clipboard.writeText(projection.textContent);
  221. alert("Projection copied to clipboard");
  222. } catch(err) {
  223. alert("Error copying text: " + err);
  224. }
  225. },
  226. 'click .js-board-title'(evt) {
  227. evt.preventDefault();
  228. const input = document.getElementById('global-search-input');
  229. this.query.set(
  230. `${input.value} ${TAPi18n.__('operator-board')}:"${
  231. evt.currentTarget.textContent
  232. }"`,
  233. );
  234. document.getElementById('global-search-input').focus();
  235. },
  236. 'click .js-list-title'(evt) {
  237. evt.preventDefault();
  238. const input = document.getElementById('global-search-input');
  239. this.query.set(
  240. `${input.value} ${TAPi18n.__('operator-list')}:"${
  241. evt.currentTarget.textContent
  242. }"`,
  243. );
  244. document.getElementById('global-search-input').focus();
  245. },
  246. 'click .js-label-name'(evt) {
  247. evt.preventDefault();
  248. const input = document.getElementById('global-search-input');
  249. this.query.set(
  250. `${input.value} ${TAPi18n.__('operator-label')}:"${
  251. evt.currentTarget.textContent
  252. }"`,
  253. );
  254. document.getElementById('global-search-input').focus();
  255. },
  256. 'click .js-new-search'(evt) {
  257. evt.preventDefault();
  258. const input = document.getElementById('global-search-input');
  259. input.value = '';
  260. this.query.set('');
  261. this.hasResults.set(false);
  262. },
  263. },
  264. ]);
  265. }
  266. }
  267. GlobalSearchComponent.register('globalSearch');