mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
[MIG] web_field_tooltip: Migration to 16.0
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import {Component, markup} from "@odoo/owl";
|
||||
|
||||
import {FormViewDialog} from "@web/views/view_dialogs/form_view_dialog";
|
||||
import {session} from "@web/session";
|
||||
import {usePopover} from "@web/core/popover/popover_hook";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
|
||||
export class FieldTooltipPopover extends Component {}
|
||||
FieldTooltipPopover.template = "web_field_tooltip.FieldTooltipPopover";
|
||||
|
||||
export class FieldTooltip extends Component {
|
||||
setup() {
|
||||
this.popover = usePopover();
|
||||
this.tooltipPopover = null;
|
||||
this.hasFieldTooltip = this.props.hasFieldTooltip;
|
||||
this.canManageTooltip = session.can_manage_tooltips;
|
||||
this.showAddHelper =
|
||||
session.can_manage_tooltips && session.tooltip_show_add_helper;
|
||||
this.fieldTooltip = this.props.field.field_tooltip;
|
||||
|
||||
if (session.can_manage_tooltips) {
|
||||
this.dialogService = useService("dialog");
|
||||
}
|
||||
}
|
||||
|
||||
get tooltipInfo() {
|
||||
const props = this.props;
|
||||
return {
|
||||
title: props.field.string,
|
||||
help: markup(this.tooltipText),
|
||||
};
|
||||
}
|
||||
|
||||
get tooltipText() {
|
||||
return this.fieldTooltip.tooltip_text;
|
||||
}
|
||||
|
||||
onClickTooltip(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!this.canManageTooltip) {
|
||||
return;
|
||||
}
|
||||
const tooltipId = (this.fieldTooltip && this.fieldTooltip.id) || false;
|
||||
this.dialogService.add(FormViewDialog, {
|
||||
resModel: "ir.model.fields.tooltip",
|
||||
resId: tooltipId,
|
||||
context: {
|
||||
default_model: this.props.resModel,
|
||||
default_field_name: this.props.fieldName,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMouseEnter(ev) {
|
||||
if (!this.hasFieldTooltip) {
|
||||
return;
|
||||
}
|
||||
this.closeTooltip();
|
||||
this.tooltipPopover = this.popover.add(
|
||||
ev.currentTarget,
|
||||
FieldTooltipPopover,
|
||||
this.tooltipInfo,
|
||||
{
|
||||
closeOnClickAway: true,
|
||||
position: "top",
|
||||
title: "title",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onMouseLeave() {
|
||||
this.closeTooltip();
|
||||
}
|
||||
|
||||
closeTooltip() {
|
||||
if (this.tooltipPopover) {
|
||||
this.tooltipPopover();
|
||||
this.tooltipPopover = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldTooltip.template = "web_field_tooltip.FieldTooltip";
|
||||
@@ -0,0 +1,35 @@
|
||||
sup.field-tooltip {
|
||||
.tooltip-icon {
|
||||
background: none;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
margin-left: 0px;
|
||||
|
||||
&[has-tooltip] {
|
||||
color: #666666 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-div {
|
||||
min-width: 100px;
|
||||
min-height: 30px;
|
||||
|
||||
> * {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.popover-title {
|
||||
font-weight: bold;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
|
||||
<t t-name="web_field_tooltip.FieldTooltip" owl="1">
|
||||
<sup
|
||||
class="field-tooltip"
|
||||
t-on-click="(ev) => this.onClickTooltip(ev)"
|
||||
t-on-mouseenter="(ev) => this.onMouseEnter(ev)"
|
||||
t-on-mouseleave="(ev) => this.onMouseLeave(ev)"
|
||||
>
|
||||
<a
|
||||
class="fa fa fa-question-circle tooltip-icon text-info"
|
||||
t-att-has-tooltip="props.hasFieldTooltip"
|
||||
/>
|
||||
</sup>
|
||||
</t>
|
||||
|
||||
<t t-name="web_field_tooltip.FieldTooltipPopover" owl="1">
|
||||
<div class="popup-div">
|
||||
<div class="popover-title">
|
||||
<span t-esc="props.title" />
|
||||
</div>
|
||||
<p class="popover-content">
|
||||
<t t-out="props.help or ''" />
|
||||
</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -1,23 +0,0 @@
|
||||
sup.field-tooltip {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
sup.field-tooltip:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tooltip-icon {
|
||||
color: #666666;
|
||||
background: none;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
font-size: 12px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.popover-footer {
|
||||
margin: 0;
|
||||
padding: 8px 14px;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* Copyright 2023 ACSONE SA/NV
|
||||
Copyright 2019 TODAY Serpent Consulting Services Pvt. Ltd.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
||||
odoo.define("web_field_tooltip.controller", function(require) {
|
||||
"use strict";
|
||||
|
||||
const FormController = require("web.FormController");
|
||||
const ListController = require("web.ListController");
|
||||
const tooltips = require("web_field_tooltip.FieldTooltip");
|
||||
|
||||
const core = require("web.core");
|
||||
const session = require("web.session");
|
||||
const _t = core._t;
|
||||
|
||||
ListController.include(
|
||||
Object.assign({}, tooltips.TooltipController, {
|
||||
custom_events: _.extend({}, ListController.prototype.custom_events, {
|
||||
add_tooltip: "_onAddTooltip",
|
||||
edit_tooltip: "_onEditTooltip",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
FormController.include(
|
||||
Object.assign({}, tooltips.TooltipController, {
|
||||
custom_events: _.extend({}, FormController.prototype.custom_events, {
|
||||
add_tooltip: "_onAddTooltip",
|
||||
edit_tooltip: "_onEditTooltip",
|
||||
}),
|
||||
|
||||
renderSidebar: function($node) {
|
||||
this._super($node);
|
||||
if (this.sidebar && session.can_manage_tooltips) {
|
||||
this.sidebar.items.other.push({
|
||||
label: _t("Manage Tooltips"),
|
||||
callback: this.on_manage_tooltips,
|
||||
});
|
||||
}
|
||||
},
|
||||
on_manage_tooltips: function() {
|
||||
const self = this;
|
||||
return self.do_action({
|
||||
type: "ir.actions.act_window",
|
||||
name: _t("Manage Tooltips"),
|
||||
res_model: "ir.model.fields.tooltip",
|
||||
target: "current",
|
||||
views: [
|
||||
[false, "list"],
|
||||
[false, "form"],
|
||||
],
|
||||
view_mode: "list",
|
||||
domain: [["model", "=", self.modelName]],
|
||||
context: {tooltip_model: self.modelName},
|
||||
});
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,61 +0,0 @@
|
||||
/* Copyright 2023 ACSONE SA/NV
|
||||
Copyright 2019 TODAY Serpent Consulting Services Pvt. Ltd.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
||||
odoo.define("web_field_tooltip.renderer", function(require) {
|
||||
"use strict";
|
||||
|
||||
const FormRenderer = require("web.FormRenderer");
|
||||
const ListRenderer = require("web.ListRenderer");
|
||||
const tooltips = require("web_field_tooltip.FieldTooltip");
|
||||
|
||||
FormRenderer.include(
|
||||
Object.assign({}, tooltips.TooltipRenderer, {
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.tooltips = undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_renderTagLabel: function(node) {
|
||||
const self = this;
|
||||
const $result = this._super.apply(this, arguments);
|
||||
const fieldName =
|
||||
node.tag === "label" ? node.attrs.for : node.attrs.name;
|
||||
if (!fieldName) {
|
||||
return $result;
|
||||
}
|
||||
self.add_tooltip($result, node);
|
||||
|
||||
return $result;
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
ListRenderer.include(
|
||||
Object.assign({}, tooltips.TooltipRenderer, {
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.tooltips = undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_renderHeaderCell: function(node) {
|
||||
const self = this;
|
||||
const $result = this._super.apply(this, arguments);
|
||||
const fieldName =
|
||||
node.tag === "label" ? node.attrs.for : node.attrs.name;
|
||||
if (!fieldName) {
|
||||
return $result;
|
||||
}
|
||||
self.add_tooltip($result, node);
|
||||
|
||||
return $result;
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,189 +0,0 @@
|
||||
/* Copyright 2023 ACSONE SA/NV
|
||||
Copyright 2019 TODAY Serpent Consulting Services Pvt. Ltd.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
||||
odoo.define("web_field_tooltip.FieldTooltip", function(require) {
|
||||
"use strict";
|
||||
|
||||
const core = require("web.core");
|
||||
const dialogs = require("web.view_dialogs");
|
||||
const field_utils = require("web.field_utils");
|
||||
const rpc = require("web.rpc");
|
||||
const session = require("web.session");
|
||||
const _t = core._t;
|
||||
|
||||
const TooltipRenderer = {
|
||||
add_tooltip: function($result, node) {
|
||||
const self = this;
|
||||
const tooltip_title = $result.text();
|
||||
|
||||
const fieldName = node.tag === "label" ? node.attrs.for : node.attrs.name;
|
||||
if (!fieldName) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Check if there's any tooltip that must be rendered for the given view
|
||||
if (!self.tooltips) {
|
||||
self.load_tooltips();
|
||||
}
|
||||
|
||||
self.$tooltip_promise.then(function() {
|
||||
let $tooltip = null;
|
||||
let allow_add_tooltip_helper =
|
||||
session.tooltip_show_add_helper && session.can_manage_tooltips;
|
||||
_.each(self.tooltips, function(tooltip) {
|
||||
if (tooltip.field_name === fieldName) {
|
||||
$tooltip = self.get_tooltip_elem(
|
||||
fieldName,
|
||||
tooltip_title,
|
||||
tooltip
|
||||
);
|
||||
$result.append($tooltip);
|
||||
allow_add_tooltip_helper = false;
|
||||
}
|
||||
});
|
||||
if (allow_add_tooltip_helper) {
|
||||
$result.append(self.get_add_tooltip_elem(fieldName));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
load_tooltips: function() {
|
||||
const self = this;
|
||||
self.$tooltip_promise = rpc
|
||||
.query({
|
||||
model: "ir.model.fields.tooltip",
|
||||
method: "search_read",
|
||||
domain: [["model", "=", self.state.model]],
|
||||
})
|
||||
.then(function(result) {
|
||||
self.tooltips = result;
|
||||
});
|
||||
},
|
||||
|
||||
get_add_tooltip_elem: function(fieldName) {
|
||||
const self = this;
|
||||
const $after_elem = $("<a>", {
|
||||
class: "fa fa fa-question-circle tooltip-icon text-info",
|
||||
});
|
||||
|
||||
$after_elem.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.trigger_up("add_tooltip", {
|
||||
context: {
|
||||
default_model: self.state.model,
|
||||
default_field_name: fieldName,
|
||||
},
|
||||
});
|
||||
});
|
||||
const $sup = $("<sup/>", {
|
||||
class: "field-tooltip",
|
||||
});
|
||||
$sup.append($after_elem);
|
||||
return $sup;
|
||||
},
|
||||
|
||||
get_tooltip_elem: function(fieldName, tooltip_title, tooltip) {
|
||||
const self = this;
|
||||
const $after_elem = $("<a>", {
|
||||
class: "fa fa fa-question-circle tooltip-icon",
|
||||
tabIndex: 0,
|
||||
});
|
||||
|
||||
const $popup_div = $("<div/>", {
|
||||
class: "popup-div",
|
||||
});
|
||||
|
||||
const $popup_text = $("<p>", {
|
||||
html: tooltip.tooltip_text,
|
||||
});
|
||||
|
||||
$popup_div.append($popup_text);
|
||||
|
||||
if (session.can_manage_tooltips) {
|
||||
const $popup_last_edit = $("<p>", {
|
||||
class: "popover-footer",
|
||||
html:
|
||||
_t("Last Updated by: ") +
|
||||
field_utils.format.many2one(tooltip.write_uid),
|
||||
});
|
||||
|
||||
const $edit_button = $("<button>", {
|
||||
title: _t("Edit the tooltip"),
|
||||
class: "fa fa-edit tooltip-icon",
|
||||
});
|
||||
|
||||
$edit_button.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.trigger_up("edit_tooltip", {
|
||||
res_id: tooltip.id,
|
||||
});
|
||||
});
|
||||
|
||||
$popup_last_edit.append($edit_button);
|
||||
$popup_div.append($popup_last_edit);
|
||||
}
|
||||
|
||||
const options = {
|
||||
content: $popup_div,
|
||||
html: true,
|
||||
placement: "top",
|
||||
title: tooltip_title,
|
||||
trigger: "focus",
|
||||
delay: {
|
||||
show: 0,
|
||||
hide: 0,
|
||||
},
|
||||
};
|
||||
$after_elem.popover(options);
|
||||
$after_elem.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$after_elem.popover("show");
|
||||
});
|
||||
const $sup = $("<sup/>", {
|
||||
class: "field-tooltip",
|
||||
});
|
||||
$sup.append($after_elem);
|
||||
return $sup;
|
||||
},
|
||||
};
|
||||
|
||||
const TooltipController = {
|
||||
_onAddTooltip: function(params) {
|
||||
const self = this;
|
||||
new dialogs.FormViewDialog(self, {
|
||||
res_model: "ir.model.fields.tooltip",
|
||||
context: _.extend(session.user_context, params.data.context),
|
||||
title: _t("Add a tooltip"),
|
||||
disable_multiple_selection: true,
|
||||
}).open();
|
||||
},
|
||||
_onEditTooltip: function(params) {
|
||||
const self = this;
|
||||
const tooltipId = params.data.res_id;
|
||||
new dialogs.FormViewDialog(self, {
|
||||
res_model: "ir.model.fields.tooltip",
|
||||
res_id: tooltipId,
|
||||
context: session.user_context,
|
||||
title: _t("Edit a tooltip"),
|
||||
disable_multiple_selection: false,
|
||||
deletable: true,
|
||||
on_remove: function() {
|
||||
rpc.query({
|
||||
model: "ir.model.fields.tooltip",
|
||||
method: "unlink",
|
||||
args: [tooltipId],
|
||||
});
|
||||
},
|
||||
}).open();
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
TooltipRenderer: TooltipRenderer,
|
||||
TooltipController: TooltipController,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {FormController} from "@web/views/form/form_controller";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
import {session} from "@web/session";
|
||||
|
||||
patch(FormController.prototype, "web_field_tooltip", {
|
||||
getActionMenuItems() {
|
||||
const menuItems = this._super(...arguments);
|
||||
const otherMenuItems = menuItems.other;
|
||||
if (session.can_manage_tooltips) {
|
||||
otherMenuItems.push({
|
||||
key: "manage_tooltips",
|
||||
description: this.env._t("Manage tooltips"),
|
||||
callback: () => this.manageTooltips(),
|
||||
});
|
||||
}
|
||||
return menuItems;
|
||||
},
|
||||
|
||||
manageTooltips() {
|
||||
const model = this.props.resModel;
|
||||
this.env.services.action.doAction(
|
||||
"web_field_tooltip.ir_model_fields_tooltip_act_window",
|
||||
{
|
||||
additionalContext: {
|
||||
search_default_model: model,
|
||||
default_model: model,
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
34
web_field_tooltip/static/src/views/form/form_label.esm.js
Normal file
34
web_field_tooltip/static/src/views/form/form_label.esm.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {FieldTooltip} from "../../components/field_tooltip/field_tooltip.esm";
|
||||
|
||||
import {FormLabel} from "@web/views/form/form_label";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
import {session} from "@web/session";
|
||||
|
||||
patch(FormLabel.prototype, "web_field_tooltip", {
|
||||
get showTooltipAddHelper() {
|
||||
return session.tooltip_show_add_helper;
|
||||
},
|
||||
|
||||
get hasFieldTooltip() {
|
||||
const props = this.props;
|
||||
return Boolean(props.record.fields[props.fieldName].field_tooltip);
|
||||
},
|
||||
|
||||
get getFieldTooltipProps() {
|
||||
const props = this.props;
|
||||
const record = props.record;
|
||||
return {
|
||||
hasFieldTooltip: this.hasFieldTooltip,
|
||||
resModel: record.resModel,
|
||||
field: record.fields[props.fieldName],
|
||||
fieldName: props.fieldName,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
FormLabel.components = Object.assign({}, FormLabel.components, {
|
||||
FieldTooltip,
|
||||
});
|
||||
17
web_field_tooltip/static/src/views/form/form_label.xml
Normal file
17
web_field_tooltip/static/src/views/form/form_label.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t
|
||||
t-name="web_field_tooltip.FormLabel"
|
||||
t-inherit="web.FormLabel"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//sup" position="before">
|
||||
<t t-if="hasFieldTooltip or showTooltipAddHelper">
|
||||
<FieldTooltip t-props="getFieldTooltipProps" />
|
||||
</t>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
36
web_field_tooltip/static/src/views/list/list_renderer.esm.js
Normal file
36
web_field_tooltip/static/src/views/list/list_renderer.esm.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {FieldTooltip} from "../../components/field_tooltip/field_tooltip.esm";
|
||||
|
||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||
import {patch} from "@web/core/utils/patch";
|
||||
|
||||
import {session} from "@web/session";
|
||||
|
||||
patch(ListRenderer.prototype, "web_field_tooltip", {
|
||||
showTooltipAddHelper() {
|
||||
return session.tooltip_show_add_helper;
|
||||
},
|
||||
|
||||
hasFieldTooltip(column) {
|
||||
const fieldName = column.name;
|
||||
const fields = this.props.list.fields;
|
||||
return Boolean(fields[fieldName].field_tooltip);
|
||||
},
|
||||
|
||||
getFieldTooltipProps(column) {
|
||||
const props = this.props;
|
||||
const fieldName = column.name;
|
||||
const fields = props.list.fields;
|
||||
return {
|
||||
hasFieldTooltip: this.hasFieldTooltip(column),
|
||||
resModel: props.list.resModel,
|
||||
field: fields[fieldName],
|
||||
fieldName: fieldName,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
ListRenderer.components = Object.assign({}, ListRenderer.components, {
|
||||
FieldTooltip,
|
||||
});
|
||||
28
web_field_tooltip/static/src/views/list/list_renderer.xml
Normal file
28
web_field_tooltip/static/src/views/list/list_renderer.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t
|
||||
t-name="web_field_tooltip.ListRenderer"
|
||||
t-inherit="web.ListRenderer"
|
||||
t-inherit-mode="extension"
|
||||
owl="1"
|
||||
>
|
||||
<xpath
|
||||
expr="//t[@t-foreach='state.columns']//span[@t-esc='column.label']"
|
||||
position="after"
|
||||
>
|
||||
<div class="d-block min-w-0 text-truncate flex-grow-1">
|
||||
<t t-if="hasFieldTooltip(column) or showTooltipAddHelper()">
|
||||
<FieldTooltip t-props="getFieldTooltipProps(column)" />
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath
|
||||
expr="//t[@t-foreach='state.columns']//span[@t-esc='column.label']"
|
||||
position="attributes"
|
||||
>
|
||||
<attribute name="class">d-block min-w-0 text-truncate</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
Reference in New Issue
Block a user