Skip to content

Commit

Permalink
fix(html): prepare codebase for render & content merge
Browse files Browse the repository at this point in the history
  • Loading branch information
smalluban committed Jun 3, 2024
1 parent 36d6e39 commit 2b0c01b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 54 deletions.
5 changes: 5 additions & 0 deletions src/localize.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,16 @@ export function msg(parts, ...args) {
return getString(parts, args).replace(EXP_REGEX, (_, index) => args[index]);
}

const PLACEHOLDER_SVG = getPlaceholder("svg");
const PLACEHOLDER_MSG = getPlaceholder("msg");

msg.html = function html(parts, ...args) {
const input = getString(parts, args);

return compile(
input.replace(EXP_REGEX, (_, index) => getPlaceholder(index)),
args,
input + PLACEHOLDER_MSG,
false,
true,
);
Expand All @@ -183,6 +187,7 @@ msg.svg = function svg(parts, ...args) {
return compile(
input.replace(EXP_REGEX, (_, index) => getPlaceholder(index)),
args,
input + PLACEHOLDER_SVG + PLACEHOLDER_MSG,
true,
true,
);
Expand Down
35 changes: 10 additions & 25 deletions src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,20 @@ export default function render(key, desc) {
},
};

let shadowOptions = undefined;
if (key === "render") {
const options = desc.options || {};

const shadowOptions = {
shadowOptions = {
mode: options.mode || "open",
delegatesFocus: options.delegatesFocus || false,
};

return {
value: (host) => {
const updateDOM = fn(host);
return () => {
const target = host.shadowRoot || host.attachShadow(shadowOptions);
updateDOM(host, target);
return target;
};
},
...rest,
};
} else {
return {
value: (host) => {
const updateDOM = fn(host);
return () => {
updateDOM(host, host);
return host;
};
},
...rest,
};
}

return {
value: (host) => {
const updateDOM = fn(host);
return () => updateDOM(host, null, shadowOptions);
},
...rest,
};
}
33 changes: 22 additions & 11 deletions src/template/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const PLACEHOLDER_REGEXP_EQUAL = new RegExp(`^${PLACEHOLDER_REGEXP_TEXT}$`);
const PLACEHOLDER_REGEXP_ALL = new RegExp(PLACEHOLDER_REGEXP_TEXT, "g");
const PLACEHOLDER_REGEXP_ONLY = /^[^A-Za-z]+$/;

function createSignature(parts) {
function createContent(parts) {
let signature = parts[0];
let tableMode = false;
for (let index = 1; index < parts.length; index += 1) {
Expand Down Expand Up @@ -190,12 +190,10 @@ function updateStyleElement(target, styles) {
}

export function compileTemplate(rawParts, isSVG, isMsg, useLayout) {
let template = globalThis.document.createElement("template");
const parts = {};

const signature = isMsg ? rawParts : createSignature(rawParts);
const content = isMsg ? rawParts : createContent(rawParts);

template.innerHTML = isSVG ? `<svg>${signature}</svg>` : signature;
let template = globalThis.document.createElement("template");
template.innerHTML = isSVG ? `<svg>${content}</svg>` : content;

if (isSVG) {
const svgRoot = template.content.firstChild;
Expand Down Expand Up @@ -235,7 +233,9 @@ export function compileTemplate(rawParts, isSVG, isMsg, useLayout) {
}

const compileWalker = createWalker(template.content);
const parts = {};
const notDefinedElements = [];

let compileIndex = 0;
let noTranslate = null;

Expand Down Expand Up @@ -443,12 +443,20 @@ export function compileTemplate(rawParts, isSVG, isMsg, useLayout) {
.map((e) => `<${e}>`)
.join(", ")} element${
notDefinedElements.length > 1 ? "s" : ""
} found in the template:\n${beautifyTemplateLog(signature, -1)}`,
} found in the template:\n${beautifyTemplateLog(content, -1)}`,
);
}

const partsKeys = Object.keys(parts);
return function updateTemplateInstance(host, target, args, { styleSheets }) {
return function updateTemplateInstance(host, target, options) {
const { args, shadowOptions, styleSheets } = options;

if (shadowOptions) {
target = host.shadowRoot || host.attachShadow(shadowOptions);
} else {
target = target || host;
}

let meta = getMeta(target);

if (template !== meta.template) {
Expand Down Expand Up @@ -522,17 +530,20 @@ export function compileTemplate(rawParts, isSVG, isMsg, useLayout) {

for (const marker of meta.markers) {
const value = args[marker.index];
const prevValue = meta.prevArgs && meta.prevArgs[marker.index];
let prevValue = undefined;

if (meta.prevArgs && value === prevValue) continue;
if (meta.prevArgs) {
prevValue = meta.prevArgs[marker.index];
if (prevValue === value) continue;
}

try {
marker.fn(host, marker.node, value, prevValue, useLayout);
} catch (error) {
console.error(
`Error while updating template expression in ${stringifyElement(
host,
)}:\n${beautifyTemplateLog(signature, marker.index)}`,
)}:\n${beautifyTemplateLog(content, marker.index)}`,
);

throw error;
Expand Down
34 changes: 18 additions & 16 deletions src/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,44 @@ import * as methods from "./methods.js";

const PLACEHOLDER = getPlaceholder();
const PLACEHOLDER_SVG = getPlaceholder("svg");
const PLACEHOLDER_MSG = getPlaceholder("msg");
const PLACEHOLDER_LAYOUT = getPlaceholder("layout");

const templates = new Map();
export function compile(parts, args, isSVG, isMsg) {
function template(host, target = host) {
let id = isMsg ? parts + PLACEHOLDER_MSG : parts.join(PLACEHOLDER);
if (isSVG) id += PLACEHOLDER_SVG;
const useLayout = template.useLayout;
if (useLayout) id += PLACEHOLDER_LAYOUT;
export function compile(parts, args, id, isSVG, isMsg) {
function fn(host, target, shadowOptions) {
id = id + fn.useLayout;

let render = templates.get(id);
if (!render) {
render = compileTemplate(parts, isSVG, isMsg, useLayout);
render = compileTemplate(parts, isSVG, isMsg, fn.useLayout);
templates.set(id, render);
}

if (template.plugins) {
template.plugins.reduce(
fn.shadowOptions = shadowOptions;

if (fn.plugins) {
fn.plugins.reduce(
(acc, plugin) => plugin(acc),
() => render(host, target, args, template),
() => render(host, target, fn),
)(host, target);
} else {
render(host, target, args, template);
render(host, target, fn);
}

return target;
}

return Object.assign(template, methods);
fn.args = args;
return Object.assign(fn, methods);
}

export function html(parts, ...args) {
return compile(parts, args, false, false);
const id = parts.join(PLACEHOLDER);
return compile(parts, args, id, false, false);
}

export function svg(parts, ...args) {
return compile(parts, args, true, false);
const id = parts.join(PLACEHOLDER) + PLACEHOLDER_SVG;
return compile(parts, args, id, true, false);
}

Object.freeze(Object.assign(html, helpers));
2 changes: 1 addition & 1 deletion src/template/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export function inject(target) {
const sheet = getCSSStyleSheet();

/* istanbul ignore else */
if (hasAdoptedStylesheets) {
if (hasAdoptedStylesheets && root.adoptedStyleSheets) {
root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];
} else {
if (root === globalThis.document) return;
Expand Down
6 changes: 5 additions & 1 deletion test/spec/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@ describe("layout:", () => {
expect(nestedHost.hasAttribute("layout")).toBe(false);
});

it("uses layout engine for nested templates", () => {
it("uses layout engine for nested templates when parent is in layout mode", () => {
html`
<template layout="row">${html`<div layout="column"></div>`}</template>
`(host, host.attachShadow({ mode: "open" }));

expect(host.shadowRoot.children[0].className).not.toBeFalsy();

const el = document.createElement("div");
html`<div layout="column"></div>`(el);
expect(el.children[0].getAttribute("layout")).toBe("column");
});

it("uses layout engine for nested array templates", () => {
Expand Down

0 comments on commit 2b0c01b

Please sign in to comment.