[ADD] web_widget_many2one_simple

This commit is contained in:
Alexandre D. Díaz
2020-12-28 19:28:28 +01:00
committed by OCA-git-bot
parent 64f34f7c73
commit 575daf2e68
13 changed files with 1067 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
.o_field_widget {
// Flex fields (inline)
&.o_field_many2one_simple {
display: inline-flex;
> span,
> button {
flex: 0 0 auto;
}
.o_external_button {
padding: 0;
margin-left: 2px;
font-size: 19px;
color: #7c7bad;
border: none;
&:hover {
background-color: transparent;
}
}
}
}

View File

@@ -0,0 +1,340 @@
odoo.define("web_widget_many2one_simple.FieldMany2OneSimple", function(require) {
"use strict";
const core = require("web.core");
const Dialog = require("web.Dialog");
const dialogs = require("web.view_dialogs");
const AbstractField = require("web.AbstractField");
const field_registry = require("web.field_registry");
const _t = core._t;
const _lt = core._lt;
const FieldMany2OneSimple = AbstractField.extend({
description: _lt("Many2one Simple"),
supportedFieldTypes: ["many2one"],
template: "web_widget_many2one_simple.FieldMany2OneSimple",
custom_events: _.extend({}, AbstractField.prototype.custom_events, {
quick_create: "_onQuickCreate",
field_changed: "_onFieldChanged",
}),
events: _.extend({}, AbstractField.prototype.events, {
"focusout input": "_onInputFocusout",
"keyup input": "_onInputKeyup",
"click .o_external_button": "_onExternalButtonClick",
click: "_onClick",
}),
/**
* @override
*/
init: function(parent, name, record, options) {
this._super.apply(this, arguments);
this.can_create =
("can_create" in this.attrs
? JSON.parse(this.attrs.can_create)
: true) && !this.nodeOptions.no_create;
this.can_write =
"can_write" in this.attrs ? JSON.parse(this.attrs.can_write) : true;
this.regex =
!this.nodeOptions.no_regex && "regex" in this.attrs
? new RegExp(this.attrs.regex)
: undefined;
this.nodeOptions = _.defaults(this.nodeOptions, {
search: {
field: "id",
oper: "=",
},
});
this.noOpen =
"noOpen" in (options || {}) ? options.noOpen : this.nodeOptions.no_open;
this.search =
"search" in (options || {}) ? options.search : this.nodeOptions.search;
},
/**
* @override
*/
start: function() {
this.$input = this.$("input");
this.$external_button = this.$(".o_external_button");
return this._super.apply(this, arguments);
},
/**
* @param {Object} value (format: {id: ..., display_name: ...})
* @returns {Promise}
*/
reinitialize: function(value) {
this.isDirty = false;
return this._setValue(value).then(() => {
const formatted_value = this._formatValue(this.value);
this.$input.val(formatted_value);
});
},
/**
* @returns {Promise}
*/
_search: function() {
if (!this.isDirty) {
return Promise.resolve();
}
const search_value = this.$input.val();
if (search_value === "") {
this.reinitialize(false);
return Promise.resolve(false);
}
if (this.regex && !this.regex.test(search_value)) {
this._showErrorMessage(_t("The given search criteria is not valid."));
this.reinitialize(false);
return Promise.resolve(false);
}
const context = this.record.getContext(
_.extend({}, this.recordParams, {
additionalContext: this.attrs.context || {},
})
);
context.many2one_simple = true;
const domain = this.record.getDomain(this.recordParams);
return this._rpc({
model: this.field.relation,
method: "search_read",
fields: ["display_name"],
domain: _.union(domain, this._getDomain()),
limit: 1,
kwargs: {context: context},
}).then(results => {
if (_.isEmpty(results)) {
if (this.can_create) {
const create_context = _.extend({}, this.attrs.context);
if (this.search.field !== "id") {
create_context[
"default_" + this.search.field
] = this.$input.val();
}
this._createPopup("form", create_context);
} else {
this._showErrorMessage(
_t("Can't found any record with the given criteria.")
);
}
this.reinitialize(false);
} else {
this.reinitialize(results[0]);
}
});
},
/**
* @private
*/
_renderEdit: function() {
const value = this._formatValue(this.value);
this.$input.val(value);
this._updateExternalButton();
},
/**
* @private
*/
_renderReadonly: function() {
const value = this._formatValue(this.value);
const escapedValue = _.escape((value || "").trim());
const mapvalue = escapedValue
.split("\n")
.map(function(line) {
return "<span>" + line + "</span>";
})
.join("<br/>");
this.$el.html(mapvalue);
if (!this.noOpen && this.value) {
this.$el.attr(
"href",
_.str.sprintf(
"#id=%s&model=%s",
this.value.res_id,
this.field.relation
)
);
this.$el.addClass("o_form_uri");
}
},
/**
* Show a message to the user
*
* @private
* @param {String} error
*/
_showErrorMessage: function(error) {
Dialog.alert(this, error, {
title: _t("Many2One Simple"),
});
},
/**
* Prepares and returns options for SelectCreateDialog
*
* @private
* @param {String} view
* @param {Object} context
* @returns {Object}
*/
_getCreatePopupOptions: function(view, context) {
return {
res_model: this.field.relation,
domain: this.record.getDomain({fieldName: this.name}),
context: _.extend(
{},
this.record.getContext(this.recordParams),
context || {}
),
dynamicFilters: [],
title: _t("Create: ") + this.string,
initial_view: view,
disable_multiple_selection: true,
no_create: !this.can_create,
kanban_view_ref: this.attrs.kanban_view_ref,
on_selected: records => this.reinitialize(records[0]),
on_closed: () => this.activate(),
};
},
/**
* Create popup handling
*
* @private
* @param {any} view
* @param {any} context
* @returns {DialogClass}
*/
_createPopup: function(view, context) {
const options = this._getCreatePopupOptions(view, context);
return new dialogs.SelectCreateDialog(
this,
_.extend({}, this.nodeOptions, options)
).open();
},
/**
* Construct the domain used to found the related record
*
* @private
* @returns {Array}
*/
_getDomain: function() {
return [[this.search.field, this.search.oper, this.$input.val()]];
},
/**
* @private
* @param {OdooEvent} event 'field_changed' event
*/
_onFieldChanged: function(event) {
this.$input.val(event.data.changes[this.name].display_name);
},
/**
* @private
*/
_onExternalButtonClick: function() {
if (!this.value) {
this.activate();
return;
}
const context = this.record.getContext(
_.extend({}, this.recordParams, {
additionalContext: this.attrs.context || {},
})
);
this._rpc({
model: this.field.relation,
method: "get_formview_id",
args: [[this.value.res_id]],
context: context,
}).then(view_id => {
new dialogs.FormViewDialog(this, {
res_model: this.field.relation,
res_id: this.value.res_id,
context: context,
title: _t("Open: ") + this.string,
view_id: view_id,
readonly: !this.can_write,
on_saved: (record, changed) => {
if (changed) {
const _setValue = this._setValue.bind(
this,
this.value.data,
{
forceChange: true,
}
);
this.trigger_up("reload", {
db_id: this.value.id,
onSuccess: _setValue,
onFailure: _setValue,
});
}
},
}).open();
});
},
/**
* @private
* @param {MouseEvent} event
*/
_onClick: function(event) {
if (this.mode === "readonly" && !this.noOpen) {
event.preventDefault();
event.stopPropagation();
this._rpc({
model: this.field.relation,
method: "get_formview_action",
args: [[this.value.res_id]],
context: this.record.getContext(this.recordParams),
}).then(action => {
this.trigger_up("do_action", {action: action});
});
}
},
/**
* @private
*/
_onInputFocusout: function() {
this._search();
},
/**
* @private
*
* @param {OdooEvent} ev
*/
_onInputKeyup: function(ev) {
if (ev.which === $.ui.keyCode.ENTER || ev.which === $.ui.keyCode.TAB) {
this._search();
} else {
this.isDirty = true;
}
},
/**
* @private
*/
_updateExternalButton: function() {
const has_external_button = !this.noOpen && !this.floating && this.isSet();
this.$external_button.toggle(has_external_button);
},
});
field_registry.add("many2one_simple", FieldMany2OneSimple);
return FieldMany2OneSimple;
});

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates id="template" xml:space="preserve">
<t t-name="web_widget_many2one_simple.FieldMany2OneSimple">
<t t-if="widget.mode === 'readonly'">
<a
t-if="!widget.noOpen"
t-att-tabindex="widget.attrs.tabindex"
class="o_form_uri"
href="#"
/>
<span t-if="widget.noOpen" />
</t>
<div
t-if="widget.mode === 'edit'"
class="o_field_widget o_field_many2one_simple"
aria-atomic="true"
>
<input
type="text"
class="o_input"
t-att-barcode_events="widget.nodeOptions.barcode_events"
t-att-tabindex="widget.attrs.tabindex"
t-att-autofocus="widget.attrs.autofocus"
t-att-placeholder="widget.attrs.placeholder"
t-att-id="widget.idForLabel"
/>
<button
type="button"
t-if="!widget.noOpen"
class="fa fa-external-link btn btn-secondary o_external_button"
tabindex="-1"
draggable="false"
aria-label="External link"
title="External link"
/>
</div>
</t>
</templates>