From 0bef662b809bded0c62454eae47e78d4fe12f489 Mon Sep 17 00:00:00 2001 From: Bruno Boi Date: Mon, 4 Jul 2022 09:55:42 +0000 Subject: [PATCH] [REF] web: viewCompiler factorize string interpolation handling Before this commit The view compiler and the kanban compiler both have code to handle string interpolation. After this commit The code is reworked and factorized in a single place. Part-of: odoo/odoo#94952 --- .../src/views/kanban/kanban_compiler.js | 10 ++---- addons/web/static/src/views/view_compiler.js | 33 ++++++++++++++----- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/addons/web/static/src/views/kanban/kanban_compiler.js b/addons/web/static/src/views/kanban/kanban_compiler.js index 23419b88fbc..7524d4ac4f2 100644 --- a/addons/web/static/src/views/kanban/kanban_compiler.js +++ b/addons/web/static/src/views/kanban/kanban_compiler.js @@ -8,7 +8,7 @@ import { getTag, } from "@web/core/utils/xml"; import { toStringExpression } from "@web/views/utils"; -import { ViewCompiler } from "@web/views/view_compiler"; +import { toInterpolatedStringExpression, ViewCompiler } from "@web/views/view_compiler"; /** * @typedef {Object} DropdownDef @@ -18,8 +18,6 @@ import { ViewCompiler } from "@web/views/view_compiler"; * @property {("dropdown" | "toggler" | "menu")[]} parts */ -const INTERP_REGEXP = /\{\{.*?\}\}|#\{.*?\}/g; - const ACTION_TYPES = ["action", "object"]; const SPECIAL_TYPES = [...ACTION_TYPES, "edit", "open", "delete", "url", "set_cover"]; @@ -262,11 +260,7 @@ export class KanbanCompiler extends ViewCompiler { const attrsParts = Object.entries(attrs).map(([key, value]) => { if (key.startsWith("t-attf-")) { key = key.slice(7); - value = value.replace( - INTERP_REGEXP, - (s) => "${" + s.slice(2, s[0] === "{" ? -2 : -1) + "}" - ); - value = toStringExpression(value); + value = toInterpolatedStringExpression(value); } else if (key.startsWith("t-att-")) { key = key.slice(6); value = `"" + (${value})`; diff --git a/addons/web/static/src/views/view_compiler.js b/addons/web/static/src/views/view_compiler.js index 88600efe1c7..75e94f2e4a7 100644 --- a/addons/web/static/src/views/view_compiler.js +++ b/addons/web/static/src/views/view_compiler.js @@ -35,6 +35,28 @@ const BUTTON_CLICK_PARAMS = [ "debounce", ]; const BUTTON_STRING_PROPS = ["string", "size", "title", "icon"]; +const INTERP_REGEXP = /(\{\{|#\{)(.*?)(\}{1,2})/g; + +/** + * @param {string} str + * @returns {string} the interpolated string to be injected into a component's node props. + */ +export function toInterpolatedStringExpression(str) { + const matches = str.matchAll(INTERP_REGEXP); + const parts = []; + let searchString = str; + for (const [match, head, expr] of matches) { + const index = searchString.indexOf(head); + const left = searchString.slice(0, index); + if (left) { + parts.push(toStringExpression(left)); + } + parts.push(`(${expr})`); + searchString = searchString.slice(index + match.length); + } + parts.push(toStringExpression(searchString)); + return parts.join("+"); +} /** * @param {Element} el @@ -72,15 +94,8 @@ export function assignOwlDirectives(target, ...sources) { for (const { name, value } of source.attributes) { if (name.startsWith("t-attf-")) { const propName = name.slice(7); - const tAttf = value - .split("}}") - .map((leftAndExpr) => { - const [left, expr] = leftAndExpr.split("{{"); - const part = toStringExpression(left); - return expr ? part + `+${expr}+` : part; - }) - .join(""); - target.setAttribute(propName, tAttf); + const interpolatedExpression = toInterpolatedStringExpression(value); + target.setAttribute(propName, interpolatedExpression); } else if (name.startsWith("t-att-")) { const propName = name.slice(6); target.setAttribute(propName, value);