diff --git a/web_search_with_and/README.rst b/web_search_with_and/README.rst index 820ad6344..84d27b3bb 100644 --- a/web_search_with_and/README.rst +++ b/web_search_with_and/README.rst @@ -23,7 +23,7 @@ Use AND conditions on omnibar search :target: https://runbot.odoo-community.org/runbot/162/13.0 :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| When searching for records on same field Odoo joins multiple queries with OR. For example: @@ -79,6 +79,7 @@ Contributors * Francesco Apruzzese * Numigi (tm) and all its contributors (https://bit.ly/numigiens) * Souheil Bejaoui +* Pedro Guirao Maintainers ~~~~~~~~~~~ diff --git a/web_search_with_and/__manifest__.py b/web_search_with_and/__manifest__.py index e7166bdf5..53c101755 100644 --- a/web_search_with_and/__manifest__.py +++ b/web_search_with_and/__manifest__.py @@ -4,11 +4,11 @@ { "name": "Use AND conditions on omnibar search", - "version": "13.0.1.0.0", - "author": "Versada UAB, ACSONE SA/NV, Odoo Community Association (OCA)", + "version": "14.0.1.0.0", + "author": "Versada UAB, ACSONE SA/NV, Serincloud, Odoo Community Association (OCA)", "license": "AGPL-3", "category": "web", "website": "https://github.com/OCA/web", "depends": ["web"], - "data": ["data/data.xml"], + "data": ["views/assets.xml"], } diff --git a/web_search_with_and/readme/CONTRIBUTORS.rst b/web_search_with_and/readme/CONTRIBUTORS.rst index de9ce208d..fad3aabbb 100644 --- a/web_search_with_and/readme/CONTRIBUTORS.rst +++ b/web_search_with_and/readme/CONTRIBUTORS.rst @@ -3,3 +3,4 @@ * Francesco Apruzzese * Numigi (tm) and all its contributors (https://bit.ly/numigiens) * Souheil Bejaoui +* Pedro Guirao diff --git a/web_search_with_and/static/src/js/control_panel_model_extension.js b/web_search_with_and/static/src/js/control_panel_model_extension.js new file mode 100644 index 000000000..67f2d7db5 --- /dev/null +++ b/web_search_with_and/static/src/js/control_panel_model_extension.js @@ -0,0 +1,55 @@ +odoo.define( + "web_search_with_and/static/src/js/control_panel_model_extension.js", + function (require) { + "use strict"; + + const {patch} = require("web.utils"); + const components = { + ControlPanelModelExtension: require("web/static/src/js/control_panel/control_panel_model_extension.js"), + }; + + patch( + components.ControlPanelModelExtension, + "web_search_with_and/static/src/js/control_panel_model_extension.js", + { + addAutoCompletionValues({ + filterId, + label, + value, + operator, + isShiftKey, + }) { + const queryElem = this.state.query.find( + (queryElem) => + queryElem.filterId === filterId && + queryElem.value === value && + queryElem.operator === operator + ); + if (!queryElem) { + if (isShiftKey) { + const groupId = Math.random(); + this.state.query.push({ + filterId, + groupId, + label, + value, + operator, + }); + } else { + const {groupId} = this.state.filters[filterId]; + this.state.query.push({ + filterId, + groupId, + label, + value, + operator, + }); + } + } else { + queryElem.label = label; + } + }, + } + ); + } +); diff --git a/web_search_with_and/static/src/js/search.js b/web_search_with_and/static/src/js/search.js deleted file mode 100644 index d543694ca..000000000 --- a/web_search_with_and/static/src/js/search.js +++ /dev/null @@ -1,39 +0,0 @@ -odoo.define("web_search_with_and", function (require) { - "use strict"; - - var searchBarAutocompleteRegistry = require("web.search_bar_autocomplete_sources_registry"); - var SearchBar = require("web.SearchBar"); - - SearchBar.include({ - // Override the base method to detect a "shift" event - _onAutoCompleteSelected: function (e, ui) { - var values = ui.item.facet.values; - if ( - e.shiftKey && - values && - values.length && - String(values[0].value).trim() !== "" - ) { - // In case of an "AND" search a new facet is added regarding of - // the previous facets - e.preventDefault(); - var filter = ui.item.facet.filter; - var field = this.fields[filter.attrs.name]; - var Obj = searchBarAutocompleteRegistry.getAny([ - filter.attrs.widget, - field.type, - ]); - var obj = new Obj(this, filter, field, this.actionContext); - var new_filter = Object.assign({}, ui.item.facet.filter, { - domain: obj.getDomain(values), - autoCompleteValues: values, - }); - this.trigger_up("new_filters", { - filters: [new_filter], - }); - } else { - return this._super.apply(this, arguments); - } - }, - }); -}); diff --git a/web_search_with_and/static/src/js/search_bar.js b/web_search_with_and/static/src/js/search_bar.js new file mode 100644 index 000000000..a12912057 --- /dev/null +++ b/web_search_with_and/static/src/js/search_bar.js @@ -0,0 +1,139 @@ +odoo.define("web_search_with_and/static/src/js/search_bar.js", function (require) { + "use strict"; + + const {patch} = require("web.utils"); + const components = { + SearchBar: require("web.SearchBar"), + }; + + patch(components.SearchBar, "web_search_with_and/static/src/js/search_bar.js", { + /** + * @private + * @param {Object} source + */ + _selectSource(source) { + // Inactive sources are: + // - Selection sources + // - "no result" items + if (source.active) { + const labelValue = source.label || this.state.inputValue; + console.log( + "------------- addAutoCompletionValues11 -------------", + source, + this.isShiftKey + ); + this.model.dispatch("addAutoCompletionValues", { + filterId: source.filterId, + value: + "value" in source + ? source.value + : this._parseWithSource(labelValue, source), + label: labelValue, + operator: source.filterOperator || source.operator, + isShiftKey: this.isShiftKey, + }); + } + this._closeAutoComplete(); + }, + + /** + * @private + * @param {KeyboardEvent} ev + */ + _onSearchKeydown(ev) { + if (ev.isComposing) { + // This case happens with an IME for example: we let it handle all key events. + return; + } + if (ev.shiftKey) { + this.isShiftKey = true; + } else { + this.isShiftKey = false; + } + const currentItem = this.state.sources[this.state.focusedItem] || {}; + switch (ev.key) { + case "ArrowDown": + ev.preventDefault(); + if (Object.keys(this.state.sources).length) { + let nextIndex = this.state.focusedItem + 1; + if (nextIndex >= this.state.sources.length) { + nextIndex = 0; + } + this.state.focusedItem = nextIndex; + } else { + this.env.bus.trigger("focus-view"); + } + break; + case "ArrowLeft": + if (currentItem.expanded) { + // Priority 1: fold expanded item. + ev.preventDefault(); + this._expandSource(currentItem, false); + } else if (currentItem.parent) { + // Priority 2: focus parent item. + ev.preventDefault(); + this.state.focusedItem = this.state.sources.indexOf( + currentItem.parent + ); + // Priority 3: Do nothing (navigation inside text). + } else if (ev.target.selectionStart === 0) { + // Priority 4: navigate to rightmost facet. + this._focusFacet(this.model.get("facets").length - 1); + } + break; + case "ArrowRight": + if (ev.target.selectionStart === this.state.inputValue.length) { + // Priority 1: Do nothing (navigation inside text). + if (currentItem.expand) { + // Priority 2: go to first child or expand item. + ev.preventDefault(); + if (currentItem.expanded) { + this.state.focusedItem++; + } else { + this._expandSource(currentItem, true); + } + } else if ( + ev.target.selectionStart === this.state.inputValue.length + ) { + // Priority 3: navigate to leftmost facet. + this._focusFacet(0); + } + } + break; + case "ArrowUp": + ev.preventDefault(); + let previousIndex = this.state.focusedItem - 1; + if (previousIndex < 0) { + previousIndex = this.state.sources.length - 1; + } + this.state.focusedItem = previousIndex; + break; + case "Backspace": + if (!this.state.inputValue.length) { + const facets = this.model.get("facets"); + if (facets.length) { + this._onFacetRemove(facets[facets.length - 1]); + } + } + break; + case "Enter": + if (!this.state.inputValue.length) { + this.model.dispatch("search"); + break; + } + /* Falls through */ + case "Tab": + if (this.state.inputValue.length) { + ev.preventDefault(); // Keep the focus inside the search bar + this._selectSource(currentItem); + } + break; + case "Escape": + if (this.state.sources.length) { + this._closeAutoComplete(); + } + break; + } + }, + }); +}); diff --git a/web_search_with_and/data/data.xml b/web_search_with_and/views/assets.xml similarity index 51% rename from web_search_with_and/data/data.xml rename to web_search_with_and/views/assets.xml index d64ec27f4..c34251868 100644 --- a/web_search_with_and/data/data.xml +++ b/web_search_with_and/views/assets.xml @@ -1,5 +1,6 @@ - + +