From 3f2ffca97a5e6a75efac1f92c61f6ce1e15c4ba2 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Mon, 20 Sep 2021 07:39:35 +0000 Subject: [PATCH] [REF] web: remove compile_lib and view_widget from web These helpers and component should be moved to web_dashboard, which is the only place they are used. Also, we want to avoid setting a precedent by putting these in web. closes odoo/odoo#76912 X-original-commit: 7f4bc27702844cf9b9f010a4ab3c1ac077442ecc Related: odoo/enterprise#21042 Signed-off-by: Lucas Perais (lpe) --- .../static/src/views/compile/compile_lib.js | 282 ------------------ .../static/src/views/compile/compile_nodes.js | 88 ------ addons/web/static/src/views/view_widget.js | 52 ---- 3 files changed, 422 deletions(-) delete mode 100644 addons/web/static/src/views/compile/compile_lib.js delete mode 100644 addons/web/static/src/views/compile/compile_nodes.js delete mode 100644 addons/web/static/src/views/view_widget.js diff --git a/addons/web/static/src/views/compile/compile_lib.js b/addons/web/static/src/views/compile/compile_lib.js deleted file mode 100644 index 41c45c95548..00000000000 --- a/addons/web/static/src/views/compile/compile_lib.js +++ /dev/null @@ -1,282 +0,0 @@ -/* @odoo-module */ -import { evaluateExpr } from "@web/core/py_js/py"; - -/** - * A helper to identify nodes in an arch to allow matching between - * the parsing of an arch, and the template compilation. - * Nodes with the same tag will be assigned an incrementing number. - * Note that, consequently every node of the same tag should be added to produce - * a reliable ID. - * @return {Function} An add function to execute on each node of a given tagName - * Function.idFor: Produce an Id for the lastNode, or for the given node. - */ -export function nodeIdentifier() { - const mapping = {}; - let lastNode; - - function add(node) { - const nodeMap = mapping[node.tagName] || { - current: null, - id: 1, - }; - mapping[node.tagName] = nodeMap; - - if (node !== nodeMap.current) { - nodeMap.id++; - } - nodeMap.current = node; - lastNode = node; - } - - function idFor(node) { - node = node || lastNode; - const nodeMap = mapping[node.tagName]; - return `${node.tagName}_${nodeMap.id}`; - } - - return Object.assign(add, { - idFor(node) { - return idFor(node); - }, - }); -} - -/** - * Checks if a XML node will resolve to a component when rendered by OWL. - * @param {Element} node Should be a node of a pre-compiled template. - * @return {boolean} - */ -function isComponentNode(node) { - return ( - node.tagName.charAt(0).toUpperCase() === node.tagName.charAt(0) || - (node.tagName === "t" && "t-component" in node.attributes) - ); -} - -/** - * Helper to add onto a Component node the information of the arch node (e.g. modifiers) - * This is almost exclusively the support of legacy Widgets. - * @param {Element} node A node from an arch - * @param {Element} compiled A node of a pre-compiled template - */ -export function addLegacyNodeInfo(node, compiled) { - const modifiers = getAllModifiers(node); - if (modifiers) { - const legacyNode = { - attrs: { modifiers }, - }; - compiled.setAttribute("_legacyNode_", `"${encodeObjectForTemplate(legacyNode)}"`); - } -} - -/** - * Encodes an object into a string usable inside a pre-compiled template - * @param {Object} - * @return {string} - */ -export function encodeObjectForTemplate(obj) { - return encodeURI(JSON.stringify(obj)); -} - -/** - * Decodes a string within an attribute into an Object - * @param {string} str - * @return {Object} - */ -export function decodeObjectForTemplate(str) { - return JSON.parse(decodeURI(str)); -} - -/** - * Combines the existing value of a node attribute with new given parts. The glue - * is the string used to join the parts. - * @param {Element} node - * @param {string} attr - * @param {string | string[]} parts - * @param {string} [glue=" "] - */ -export const combineAttributes = (node, attr, parts, glue = " ") => { - const allValues = []; - if (node.hasAttribute(attr)) { - allValues.push(node.getAttribute(attr)); - } - allValues.push(...(Array.isArray(parts) ? parts : [parts])); - node.setAttribute(attr, allValues.join(glue)); -}; -/** - * there is no particular expectation of what should be a boolean - * according to a view's arch - * Sometimes it is 0 or one, True or False ; true or false - * @return {boolean} - */ -function evalIrUiViewModifier(expr) { - if (!expr) { - return false; - } - return evaluateExpr(expr, { - true: true, - false: false, - }); -} - -/** - * Gets all the Odoo's dynamic modifiers (invisible, readonly etc...) of a Node coming from an arch. - * @param {Element} node An arch's node - * @return {Object} The modifiers set on the node. - */ -export function getAllModifiers(node) { - const modifiers = node.getAttribute("modifiers"); - if (!modifiers) { - return null; - } - const parsed = JSON.parse(modifiers); - return parsed; -} - -/** - * Gets a specific modifier, either static or dynamic, on a Node. - * A static modifier is set as an attribute and is a boolean. - * A dynamuic modifier is set in the `modifiers` attribute and id a domain.` - * @param {Element} node An arch's Node. - * @param {string} modifierName - * @return {boolean|Array} - */ -export function getModifier(node, modifierName) { - /** @type {string|boolean|Array} (mod) */ - let mod = node.getAttribute(modifierName); - if (mod === null) { - const modifiers = getAllModifiers(node); - mod = modifiers && modifierName in modifiers ? modifiers[modifierName] : null; - } - - if (!Array.isArray(mod) && !(typeof mod === "boolean")) { - mod = !!evalIrUiViewModifier(mod); - } - return mod; -} - -/** - * Specifically gets the "invisible" modifier. - * @param {Element} node - * @return {boolean|Array} - */ -function getInvisible(node) { - const invisible = getModifier(node, "invisible"); - return invisible || false; -} - -/** - * An object containing various information about the current - * compilation from an Arch to a owl template. - * @typedef {Object} CompilationContext - */ - -/** - * Determine if a node in an arch will always be invisible. Usually if it is the case, - * the node will not be compiled at all - * @param {Element} node An arch's node - * @param {CompilationContext} - * @return {boolean} - */ -export function isAlwaysInvisible(node, compilationContext) { - const invisibleModifer = getInvisible(node); - return ( - !compilationContext.enableInvisible && - typeof invisibleModifer === "boolean" && - invisibleModifer - ); -} - -/** - * Appends a child node to a parent node - * @param {Element} parent - * @param {Element|Element[]} node The future children nodes - */ -export function appendTo(parent, node) { - if (!node) { - return; - } - if (Array.isArray(node) && node.length) { - parent.append(...node); - } else { - parent.append(node); - } -} - -/** - * A string representing an abject that will be evaluated by a t-attr - * eg.: `{ attr1: my_expression ? true : false, attr2: true }` - * @typedef {string} TAttrString - */ - -/** - * A string that links an attribute to an expression - * eg.: `my_attribute: my_expression ? true : false` - * @typedef {string} TAttrStringPart - */ - -/** - * Helper to push in a string representing an object - * @param {TAttrString} originalTattr - * @param {TAttrStringPart} string string to add onto the object - * @return {TAttrString} The new string. - */ -function appendToStringifiedObject(originalTattr, string) { - const re = /{(.*)}/; - const oldString = re.exec(originalTattr); - - if (oldString) { - string = `${oldString[1]}, ${string}`; - } - return `{ ${string} }`; -} - -/** - * Appends a string to an attibute (t-attr) - * @param {Element} node - * @param {string} attr The attribute's name - * @param {TAttrStringPart} string - */ -export function appendAttr(node, attr, string) { - const attrKey = `t-att-${attr}`; - const attrVal = node.getAttribute(attrKey); - node.setAttribute(attrKey, appendToStringifiedObject(attrVal, string)); -} - -/** - * Applies an arch's node invisible modifier onto a pre-compiled node - * That is, set an t-if on the pre-compiled node, evaluating to the right expression - * or, if enableInvisible is set in params, put the class o_invisible on the compiled node - * @param {Object} params - * @param {Element} params.node An arch's node - * @param {Element} params.compiled A pre-compiled node - * @param {CompilationContext} compilationContext - * @param {boolean|Array} [invisible] A node invisible modifier - * @return {Element|undefined} Return the -pre-compiled - * Element if it is not always invisible - */ -export function applyInvisibleModifier({ node, compiled }, compilationContext, invisible) { - if (invisible === undefined && node) { - invisible = getInvisible(node); - } - if (!invisible) { - return compiled; - } - if (typeof invisible === "boolean" && !compilationContext.enableInvisible) { - return; - } - - const notInvisibleExpr = `!model.evalDomain(record,${JSON.stringify(invisible)})`; - if (!compilationContext.enableInvisible) { - combineAttributes(compiled, "t-if", `${notInvisibleExpr}`, " and "); - } else { - let expr; - if (Array.isArray(invisible)) { - expr = `${notInvisibleExpr}`; - } else { - expr = invisible; - } - appendAttr(compiled, "class", `o_invisible_modifier: ${expr}`); - } - return compiled; -} diff --git a/addons/web/static/src/views/compile/compile_nodes.js b/addons/web/static/src/views/compile/compile_nodes.js deleted file mode 100644 index 445e8f2aab5..00000000000 --- a/addons/web/static/src/views/compile/compile_nodes.js +++ /dev/null @@ -1,88 +0,0 @@ -/* @odoo-module */ -import { appendTo, addLegacyNodeInfo } from "./compile_lib"; - -/** - * An object containing various information about the current - * compilation from an Arch to a owl template. - * @typedef {Object} CompilationContext - */ - -/** - * If a group node has a string, compile a title div for it - * @param {Element} node an arch's node - * @return {Element} - */ -function makeGroupTitleRow(node) { - const titleDiv = this.document.createElement("div"); - titleDiv.classList.add("o_horizontal_separator"); - titleDiv.textContent = node.getAttribute("string"); - return titleDiv; -} - -/** - * Compiles a template node for a ``arch's node. Only for first level - * @param {Object} config - * @param {Document} config.document The document from which we can create elements - * @param {Function} config.compileNode A function to compile children nodes - * @param {number} [config.outerGroupCol] the default group column - * @param {Object} params The execution parameters - * @param {Element} params.node An arch's node - * @param {CompilationContext} params.compilationContext - * @return {Element} The compiled group node - */ -export function compileGroup( - { document, compileNode, outerGroupCol }, - { node, compilationContext } -) { - outerGroupCol = outerGroupCol || 2; - - const group = document.createElement("div"); - group.setAttribute("class", "o_group"); - - if (node.hasAttribute("string")) { - appendTo(group, makeGroupTitleRow(node)); - } - - const nbCols = - "col" in node.attributes ? parseInt(node.getAttribute("col"), 10) : outerGroupCol; - const colSize = Math.max(1, Math.round(12 / nbCols)); - - compilationContext = Object.create(compilationContext); - compilationContext.groupLevel = (compilationContext.groupLevel || 1) + 1; - for (let child of node.children) { - if (child.tagName === "newline") { - appendTo(group, this.doc.createElement("br")); - continue; - } - const compiled = compileNode(child, compilationContext); - if (!compiled) { - continue; - } - const colspan = - "colspan" in child.attributes ? parseInt(node.getAttribute("colspan"), 10) : 1; - - compiled.classList.add(`o_group_col_${colSize * colspan}`); - appendTo(group, compiled); - } - return group; -} - -/** - * Compiles a template node for a ``arch's node - * @param {Object} config - * @param {Document} config.document The document from which we can create elements - * @param {Object} params The execution parameters - * @param {Element} params.node An arch's node - * @return {Element} The compiled ViewWidget node - */ -export function compileWidget({ document }, { node }) { - const viewWidget = document.createElement("ViewWidget"); - viewWidget.setAttribute("model", "model"); - viewWidget.setAttribute("widgetName", `"${node.getAttribute("name")}"`); - if ("title" in node.attributes) { - viewWidget.setAttribute("title", `"${node.getAttribute("title")}"`); - } - addLegacyNodeInfo(node, viewWidget); - - return viewWidget; -} diff --git a/addons/web/static/src/views/view_widget.js b/addons/web/static/src/views/view_widget.js deleted file mode 100644 index c6ec040e940..00000000000 --- a/addons/web/static/src/views/view_widget.js +++ /dev/null @@ -1,52 +0,0 @@ -/* @odoo-module */ -import widgetRegistry from "web.widget_registry"; -import widgetRegistryOwl from "web.widgetRegistry"; -import { registry } from "@web/core/registry"; -import { ComponentAdapter } from "web.OwlCompatibility"; -import { decodeObjectForTemplate } from "@web/views/compile/compile_lib"; - -import { useEffect } from "@web/core/utils/hooks"; - -export class ViewWidget extends owl.Component { - setup() { - this.wowlEnv = this.env; - this.renderId = 1; - useEffect(() => { - this.renderId++; - }); - const widgetName = this.props.widgetName; - const Widget = registry.category("view_widgets").get(widgetName, null); - if (!Widget) { - this.isLegacyOwl = true; - this.env = owl.Component.env; - } - this.Widget = Widget || widgetRegistryOwl.get(widgetName) || widgetRegistry.get(widgetName); - this.isLegacy = !(this.Widget instanceof owl.Component); - } - - get widgetProps() { - if (!this.isLegacyOwl) { - return this.props; - } else { - throw new Error("To implement ...."); - } - } - - get widgetArgs() { - const record = this.props.model._legacyRecord_; - const node = this.props._legacyNode_ - ? decodeObjectForTemplate(this.props._legacyNode_) - : {}; - node.name = this.props.widgetName; - if (this.props.title) { - node.attrs = Object.assign(node.attrs || {}, { title: this.props.title }); - } - return [record, node]; - } -} -ViewWidget.template = owl.tags.xml/*xml*/ ` - - - -`; -ViewWidget.components = { ComponentAdapter };