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.

181 lines
6.3 KiB

  1. /**********************************************************************************
  2. *
  3. * Copyright (C) 2017 MuK IT GmbH
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. **********************************************************************************/
  19. odoo.define('muk_web_theme.AppsMenu', function (require) {
  20. "use strict";
  21. var core = require('web.core');
  22. var config = require("web.config");
  23. var session = require("web.session");
  24. var AppsMenu = require("web.AppsMenu");
  25. var _t = core._t;
  26. var QWeb = core.qweb;
  27. AppsMenu.include({
  28. events: _.extend({}, AppsMenu.prototype.events, {
  29. "keydown .mk_search_input input": "_onSearchResultsNavigate",
  30. "click .mk_menu_search_result": "_onSearchResultChosen",
  31. "shown.bs.dropdown": "_onMenuShow",
  32. "hidden.bs.dropdown": "_onMenuHide",
  33. }),
  34. init: function (parent, menuData) {
  35. this._super.apply(this, arguments);
  36. for (var n in this._apps) {
  37. this._apps[n].web_icon_data = menuData.children[n].web_icon_data;
  38. }
  39. this._searchableMenus = _.reduce(
  40. menuData.children, this._findNames.bind(this), {}
  41. );
  42. this._search_def = $.Deferred();
  43. },
  44. start: function () {
  45. this._setBackgroundImage();
  46. this.$search_container = this.$(".mk_search_container");
  47. this.$search_input = this.$(".mk_search_input input");
  48. this.$search_results = this.$(".mk_search_results");
  49. return this._super.apply(this, arguments);
  50. },
  51. _findNames: function (memo, menu) {
  52. if (menu.action) {
  53. var key = menu.parent_id ? menu.parent_id[1] + "/" : "";
  54. memo[key + menu.name] = menu;
  55. }
  56. if (menu.children.length) {
  57. _.reduce(menu.children, this._findNames.bind(this), memo);
  58. }
  59. return memo;
  60. },
  61. _setBackgroundImage: function () {
  62. var url = session.url('/web/image', {
  63. model: 'res.company',
  64. id: session.company_id,
  65. field: 'background_image',
  66. });
  67. this.$('.dropdown-menu').css({
  68. "background-size": "cover",
  69. "background-image": "url(" + url + ")"
  70. });
  71. },
  72. _menuInfo: function (key) {
  73. var original = this._searchableMenus[key];
  74. return _.extend({
  75. action_id: parseInt(original.action.split(',')[1], 10),
  76. }, original);
  77. },
  78. _onMenuShow: function(event) {
  79. this._searchFocus();
  80. },
  81. _onMenuHide: function(event) {
  82. this._searchReset();
  83. },
  84. _searchFocus: function () {
  85. if (!config.device.isMobile) {
  86. this.$search_input.focus();
  87. }
  88. },
  89. _searchReset: function () {
  90. this.$search_container.removeClass("has-results");
  91. this.$search_results.empty();
  92. this.$search_input.val("");
  93. },
  94. _searchMenusSchedule: function () {
  95. this._search_def.reject();
  96. this._search_def = $.Deferred();
  97. setTimeout(this._search_def.resolve.bind(this._search_def), 50);
  98. this._search_def.done(this._searchMenus.bind(this));
  99. },
  100. _searchMenus: function () {
  101. var query = this.$search_input.val();
  102. if (query === "") {
  103. this.$search_container.removeClass("has-results");
  104. this.$search_results.empty();
  105. return;
  106. }
  107. var results = fuzzy.filter(query, _.keys(this._searchableMenus), {
  108. pre: "<b>",
  109. post: "</b>",
  110. });
  111. this.$search_container.toggleClass("has-results", Boolean(results.length));
  112. this.$search_results.html(QWeb.render("muk_web_theme.MenuSearchResults", {
  113. results: results,
  114. widget: this,
  115. }));
  116. },
  117. _onSearchResultChosen: function (event) {
  118. event.preventDefault();
  119. var $result = $(event.currentTarget),
  120. text = $result.text().trim(),
  121. data = $result.data(),
  122. suffix = ~text.indexOf("/") ? "/" : "";
  123. this.trigger_up("menu_clicked", {
  124. action_id: data.actionId,
  125. id: data.menuId,
  126. previous_menu_id: data.parentId,
  127. });
  128. var app = _.find(this._apps, function (_app) {
  129. return text.indexOf(_app.name + suffix) === 0;
  130. });
  131. core.bus.trigger("change_menu_section", app.menuID);
  132. },
  133. _onSearchResultsNavigate: function (event) {
  134. if (this.$search_results.is(":empty")) {
  135. this._searchMenusSchedule();
  136. return;
  137. }
  138. var all = this.$search_results.find(".mk_menu_search_result"),
  139. pre_focused = all.filter(".active") || $(all[0]),
  140. offset = all.index(pre_focused),
  141. key = event.key;
  142. if (key === "Tab") {
  143. event.preventDefault();
  144. key = event.shiftKey ? "ArrowUp" : "ArrowDown";
  145. }
  146. switch (key) {
  147. case "Enter":
  148. pre_focused.click();
  149. break;
  150. case "ArrowUp":
  151. offset--;
  152. break;
  153. case "ArrowDown":
  154. offset++;
  155. break;
  156. default:
  157. this._searchMenusSchedule();
  158. return;
  159. }
  160. if (offset < 0) {
  161. offset = all.length + offset;
  162. } else if (offset >= all.length) {
  163. offset -= all.length;
  164. }
  165. var new_focused = $(all[offset]);
  166. pre_focused.removeClass("active");
  167. new_focused.addClass("active");
  168. this.$search_results.scrollTo(new_focused, {
  169. offset: {
  170. top: this.$search_results.height() * -0.5,
  171. },
  172. });
  173. },
  174. });
  175. });