summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorJulien Mougenot <jum@odoo.com>2020-06-10 13:05:07 +0000
committerJulien Mougenot <jum@odoo.com>2020-06-10 14:45:56 +0000
commit4f116a0f9be26b91d95e019cda1aa620faf6d620 (patch)
tree4faa0657c75638db47bfc72567f1b28f0c11a5b8 /addons/web/static
parenteacbec1e03b1f25e71875fb7caed646a53af67ed (diff)
[REF] web: clean 'M2O._search'
closes odoo/odoo#52347 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js185
1 files changed, 105 insertions, 80 deletions
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index f9a220c6b8f..660d6e43a7f 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -27,7 +27,9 @@ var KanbanRecord = require('web.KanbanRecord');
var KanbanRenderer = require('web.KanbanRenderer');
var ListRenderer = require('web.ListRenderer');
const { ComponentWrapper, WidgetAdapterMixin } = require('web.OwlCompatibility');
+const { sprintf } = require("web.utils");
+const { escape } = owl.utils;
var _t = core._t;
var _lt = core._lt;
var qweb = core.qweb;
@@ -543,91 +545,114 @@ var FieldMany2One = AbstractField.extend({
this.m2o_value = this._formatValue(this.value);
},
/**
- * Executes a name_search and process its result.
- *
- * @private
- * @param {string} search_val
- * @returns {Promise}
- */
- _search: function (search_val) {
- var self = this;
- var def = new Promise(function (resolve, reject) {
- var context = self.record.getContext(self.recordParams);
- var domain = self.record.getDomain(self.recordParams);
-
- // Add the additionalContext
- _.extend(context, self.additionalContext);
+ * Executes a 'name_search' and returns a list of formatted objects meant to
+ * be displayed in the autocomplete widget dropdown. These items are either:
+ * - a formatted version of a 'name_search' result
+ * - an option meant to display additional information or perform an action
+ *
+ * @private
+ * @param {string} [searchValue=""]
+ * @returns {Promise<{
+ * label: string,
+ * id?: number,
+ * name?: string,
+ * value?: string,
+ * classname?: string,
+ * action?: () => Promise<any>,
+ * }[]>}
+ */
+ _search: async function (searchValue = "") {
+ const value = searchValue.trim();
+ const domain = this.record.getDomain(this.recordParams);
+ const context = Object.assign(
+ this.record.getContext(this.recordParams),
+ this.additionalContext
+ );
- var blacklisted_ids = self._getSearchBlacklist();
- if (blacklisted_ids.length > 0) {
- domain.push(['id', 'not in', blacklisted_ids]);
+ // Exclude black-listed ids from the domain
+ const blackListedIds = this._getSearchBlacklist();
+ if (blackListedIds.length) {
+ domain.push(['id', 'not in', blackListedIds]);
+ }
+
+ const nameSearch = this._rpc({
+ model: this.field.relation,
+ method: "name_search",
+ kwargs: {
+ name: value,
+ args: domain,
+ operator: "ilike",
+ limit: this.limit + 1,
+ context,
}
+ });
+ const results = await this.orderer.add(nameSearch);
+
+ // Format results to fit the options dropdown
+ let values = results.map((result) => {
+ const [id, fullName] = result;
+ const displayName = this._getDisplayName(fullName).trim();
+ result[1] = displayName;
+ return {
+ id,
+ label: escape(displayName) || data.noDisplayContent,
+ value: displayName,
+ name: displayName,
+ };
+ });
- self._rpc({
- model: self.field.relation,
- method: "name_search",
- kwargs: {
- name: search_val,
- args: domain,
- operator: "ilike",
- limit: self.limit + 1,
- context: context,
- }}).then(function (result) {
- // possible selections for the m2o
- var values = _.map(result, function (x) {
- x[1] = self._getDisplayName(x[1]);
- return {
- label: _.str.escapeHTML(x[1].trim()) || data.noDisplayContent,
- value: x[1],
- name: x[1],
- id: x[0],
- };
+ // Add "Search more..." option if results count is higher than the limit
+ if (this.limit < values.length) {
+ values = this._manageSearchMore(values, value, domain, context);
+ }
+ if (!this.can_create) {
+ return values;
+ }
+
+ // Additional options...
+ const canQuickCreate = !this.nodeOptions.no_quick_create;
+ const canCreateEdit = !this.nodeOptions.no_create_edit;
+ if (value.length) {
+ // "Quick create" option
+ const nameExists = results.some((result) => result[1] === value);
+ if (canQuickCreate && !nameExists) {
+ values.push({
+ label: sprintf(
+ _t(`Create "<strong>%s</strong>"`),
+ escape(value)
+ ),
+ action: () => this._quickCreate(value),
+ classname: 'o_m2o_dropdown_option'
});
-
- // search more... if more results than limit
- if (values.length > self.limit) {
- values = self._manageSearchMore(values, search_val, domain, context);
- }
- // quick create
- var raw_result = _.map(result, function (x) { return x[1]; });
- if (self.can_create && !self.nodeOptions.no_quick_create &&
- search_val.length > 0 && !_.contains(raw_result, search_val)) {
- values.push({
- label: _.str.sprintf(_t('Create "<strong>%s</strong>"'),
- $('<span />').text(search_val).html()),
- action: self._quickCreate.bind(self, search_val),
- classname: 'o_m2o_dropdown_option'
- });
- }
- // create and edit ...
- if (self.can_create && !self.nodeOptions.no_create_edit && search_val.length > 0) {
- var createAndEditAction = function () {
- // Clear the value in case the user clicks on discard
- self.$('input').val('');
- return self._searchCreatePopup("form", false, self._createContext(search_val));
- };
- values.push({
- label: _t("Create and Edit..."),
- action: createAndEditAction,
- classname: 'o_m2o_dropdown_option',
- });
- } else if (values.length === 0) {
- values.push({
- label: _t("No results to show..."),
- });
- }
- if (!self.value && !search_val.length && self.can_create
- && (!self.nodeOptions.no_quick_create || !self.nodeOptions.no_create_edit)) {
- values.push({
- label: _t("Start typing..."),
- classname: 'o_m2o_start_typing',
- });
- }
- resolve(values);
+ }
+ // "Create and Edit" option
+ if (canCreateEdit) {
+ const valueContext = this._createContext(value);
+ values.push({
+ label: _t("Create and Edit..."),
+ action: () => {
+ // Input value is cleared and the form popup opens
+ this.el.querySelector(':scope input').value = "";
+ return this._searchCreatePopup('form', false, valueContext);
+ },
+ classname: 'o_m2o_dropdown_option',
+ });
+ }
+ // "No results" option
+ if (!values.length) {
+ values.push({
+ label: _t("No results to show..."),
+ });
+ }
+ } else if (!this.value && (canQuickCreate || canCreateEdit)) {
+ // "Start typing" option
+ values.push({
+ label: _t("Start typing..."),
+ classname: 'o_m2o_start_typing',
});
- });
- this.orderer.add(def);
- return def;
+ }
+
+ return values;
},
/**
* all search/create popup handling