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.

97 lines
3.1 KiB

  1. /** @odoo-module **/
  2. import { Component, useState, useExternalListener } from "@odoo/owl";
  3. import { computeAppsAndMenuItems } from "@web/webclient/menus/menu_helpers";
  4. import { useAutofocus, useService } from '@web/core/utils/hooks';
  5. import { useHotkey } from '@web/core/hotkeys/hotkey_hook';
  6. import { fuzzyLookup } from '@web/core/utils/search';
  7. import { debounce } from '@web/core/utils/timing';
  8. export class AppsSearch extends Component {
  9. setup() {
  10. super.setup();
  11. this.searchInput = useAutofocus();
  12. this.state = useState({
  13. hasResults: false,
  14. results: [],
  15. });
  16. this.menuService = useService('menu');
  17. Object.assign(this, computeAppsAndMenuItems(
  18. this.menuService.getMenuAsTree('root')
  19. ));
  20. this._onInput = debounce(this._onInput, 100);
  21. }
  22. _onInput() {
  23. const query = this.searchInput.el.value;
  24. if (query !== '') {
  25. const results = [];
  26. fuzzyLookup(
  27. query, this.apps, (menu) => {
  28. return menu.label
  29. }
  30. ).forEach((menu) => {
  31. const result = {
  32. id: menu.id,
  33. name: menu.label,
  34. xmlid: menu.xmlid,
  35. appID: menu.appID,
  36. actionID: menu.actionID,
  37. action: () => this.menuService.selectMenu(menu),
  38. href: menu.href || `#menu_id=${menu.id}&action_id=${menu.actionID}`,
  39. };
  40. if (menu.webIconData) {
  41. const prefix = (
  42. menu.webIconData.startsWith('P') ?
  43. 'data:image/svg+xml;base64,' :
  44. 'data:image/png;base64,'
  45. );
  46. result.webIconData = (
  47. menu.webIconData.startsWith('data:image') ?
  48. menu.webIconData :
  49. prefix + menu.webIconData.replace(/\s/g, '')
  50. );
  51. result.style = `background-image:url("${result.webIconData}");`
  52. }
  53. results.push(result);
  54. });
  55. fuzzyLookup(
  56. query, this.menuItems, (menu) => {
  57. return `${menu.parents} / ${menu.label}`.split('/').reverse().join('/')
  58. }
  59. ).forEach((menu) => {
  60. results.push({
  61. id: menu.id,
  62. name: `${menu.parents} / ${menu.label}`,
  63. xmlid: menu.xmlid,
  64. appID: menu.appID,
  65. actionID: menu.actionID,
  66. action: () => this.menuService.selectMenu(menu),
  67. href: menu.href || `#menu_id=${menu.id}&action_id=${menu.actionID}`,
  68. });
  69. });
  70. this.state.results = results;
  71. this.state.hasResults = true;
  72. } else {
  73. this.state.results = [];
  74. this.state.hasResults = false;
  75. }
  76. }
  77. _onKeyDown(ev) {
  78. if (ev.code === 'Escape') {
  79. ev.stopPropagation();
  80. ev.preventDefault();
  81. if (this.searchInput.el.value) {
  82. this.state.results = [];
  83. this.state.hasResults = false;
  84. this.searchInput.el.value = '';
  85. } else {
  86. this.env.bus.trigger('ACTION_MANAGER:UI-UPDATED');
  87. }
  88. }
  89. }
  90. }
  91. Object.assign(AppsSearch, {
  92. template: 'muk_web_theme.AppsSearch',
  93. });