142 lines
4.8 KiB
JavaScript
142 lines
4.8 KiB
JavaScript
import { registry } from "@web/core/registry";
|
|
import { useService } from "@web/core/utils/hooks";
|
|
import { browser } from "@web/core/browser/browser";
|
|
import { evaluateExpr } from "@web/core/py_js/py";
|
|
|
|
import { useComponent, useEffect, xml } from "@odoo/owl";
|
|
|
|
export function useViewArch(arch, params = {}) {
|
|
const CATEGORY = "__processed_archs__";
|
|
|
|
arch = arch.trim();
|
|
const processedRegistry = registry.category(CATEGORY);
|
|
|
|
let processedArch;
|
|
if (!processedRegistry.contains(arch)) {
|
|
processedArch = {};
|
|
processedRegistry.add(arch, processedArch);
|
|
} else {
|
|
processedArch = processedRegistry.get(arch);
|
|
}
|
|
|
|
const { compile, extract } = params;
|
|
if (!("template" in processedArch) && compile) {
|
|
processedArch.template = xml`${compile(arch)}`;
|
|
}
|
|
if (!("extracted" in processedArch) && extract) {
|
|
processedArch.extracted = extract(arch);
|
|
}
|
|
|
|
return processedArch;
|
|
}
|
|
|
|
/**
|
|
* Allows for a component (usually a View component) to handle links with
|
|
* attribute type="action". This is used to support onboarding banners and content helpers.
|
|
*
|
|
* A @web/core/concurrency:KeepLast must be present in the owl environment to allow coordinating
|
|
* between clicks. (env.keepLast)
|
|
*
|
|
* Note that this is similar but quite different from action buttons, since action links
|
|
* are not dynamic according to the record.
|
|
* @param {Object} params
|
|
* @param {String} params.resModel The default resModel to which actions will apply
|
|
* @param {Function} [params.reload] The function to execute to reload, if a button has data-reload-on-close
|
|
*/
|
|
export function useActionLinks({ resModel, reload }) {
|
|
const component = useComponent();
|
|
const keepLast = component.env.keepLast;
|
|
|
|
const orm = useService("orm");
|
|
const { doAction } = useService("action");
|
|
|
|
async function handler(ev) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
let target = ev.target;
|
|
if (target.tagName !== "A") {
|
|
target = target.closest("a");
|
|
}
|
|
const data = target.dataset;
|
|
|
|
if (data.method !== undefined && data.model !== undefined) {
|
|
const options = {};
|
|
if (data.reloadOnClose) {
|
|
options.onClose = reload || (() => component.render());
|
|
}
|
|
const action = await keepLast.add(orm.call(data.model, data.method));
|
|
if (action !== undefined) {
|
|
keepLast.add(Promise.resolve(doAction(action, options)));
|
|
}
|
|
} else if (target.getAttribute("name")) {
|
|
const options = {};
|
|
if (data.context) {
|
|
options.additionalContext = evaluateExpr(data.context);
|
|
}
|
|
keepLast.add(doAction(target.getAttribute("name"), options));
|
|
} else {
|
|
let views;
|
|
const resId = data.resid ? parseInt(data.resid, 10) : null;
|
|
if (data.views) {
|
|
views = evaluateExpr(data.views);
|
|
} else {
|
|
views = resId
|
|
? [[false, "form"]]
|
|
: [
|
|
[false, "list"],
|
|
[false, "form"],
|
|
];
|
|
}
|
|
const action = {
|
|
name: target.getAttribute("title") || target.textContent.trim(),
|
|
type: "ir.actions.act_window",
|
|
res_model: data.model || resModel,
|
|
target: "current",
|
|
views,
|
|
domain: data.domain ? evaluateExpr(data.domain) : [],
|
|
};
|
|
if (resId) {
|
|
action.res_id = resId;
|
|
}
|
|
|
|
const options = {};
|
|
if (data.context) {
|
|
options.additionalContext = evaluateExpr(data.context);
|
|
}
|
|
keepLast.add(doAction(action, options));
|
|
}
|
|
}
|
|
|
|
return (ev) => {
|
|
const a = ev.target.closest(`a[type="action"]`);
|
|
if (a && ev.currentTarget.contains(a)) {
|
|
handler(ev);
|
|
}
|
|
};
|
|
}
|
|
|
|
export function useBounceButton(containerRef, shouldBounce) {
|
|
let timeout;
|
|
const ui = useService("ui");
|
|
useEffect(
|
|
(containerEl) => {
|
|
if (!containerEl) {
|
|
return;
|
|
}
|
|
const handler = (ev) => {
|
|
const button = ui.activeElement.querySelector("[data-bounce-button]");
|
|
if (button && shouldBounce(ev.target)) {
|
|
button.classList.add("o_catch_attention");
|
|
browser.clearTimeout(timeout);
|
|
timeout = browser.setTimeout(() => {
|
|
button.classList.remove("o_catch_attention");
|
|
}, 400);
|
|
}
|
|
};
|
|
containerEl.addEventListener("click", handler);
|
|
return () => containerEl.removeEventListener("click", handler);
|
|
},
|
|
() => [containerRef.el]
|
|
);
|
|
}
|