mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] blockdom: properly handle references
Before this commit, there were situations where the reference numbers were not properly set, which caused the blocks generated to crash because the algorithm could not get correct references.
This commit is contained in:
committed by
Samuel Degueldre
parent
e946967867
commit
18fb67eaad
@@ -113,7 +113,7 @@ interface IntermediateTree {
|
|||||||
nextSibling: IntermediateTree | null;
|
nextSibling: IntermediateTree | null;
|
||||||
el: Node;
|
el: Node;
|
||||||
info: DynamicInfo[];
|
info: DynamicInfo[];
|
||||||
forceRef?: boolean;
|
isRef?: boolean;
|
||||||
refIdx?: number;
|
refIdx?: number;
|
||||||
refN: number;
|
refN: number;
|
||||||
currentNS: string | null;
|
currentNS: string | null;
|
||||||
@@ -127,7 +127,6 @@ function buildTree(
|
|||||||
switch (node.nodeType) {
|
switch (node.nodeType) {
|
||||||
case Node.ELEMENT_NODE: {
|
case Node.ELEMENT_NODE: {
|
||||||
// HTMLElement
|
// HTMLElement
|
||||||
let isActive = false;
|
|
||||||
let currentNS = parent && parent.currentNS;
|
let currentNS = parent && parent.currentNS;
|
||||||
const tagName = (node as Element).tagName;
|
const tagName = (node as Element).tagName;
|
||||||
let el: Node | undefined = undefined;
|
let el: Node | undefined = undefined;
|
||||||
@@ -136,14 +135,14 @@ function buildTree(
|
|||||||
const index = parseInt(tagName.slice(11), 10);
|
const index = parseInt(tagName.slice(11), 10);
|
||||||
info.push({ type: "text", idx: index });
|
info.push({ type: "text", idx: index });
|
||||||
el = document.createTextNode("");
|
el = document.createTextNode("");
|
||||||
isActive = true;
|
|
||||||
}
|
}
|
||||||
if (tagName.startsWith("block-child-")) {
|
if (tagName.startsWith("block-child-")) {
|
||||||
domParentTree!.forceRef = true;
|
if (!domParentTree!.isRef) {
|
||||||
|
addRef(domParentTree!);
|
||||||
|
}
|
||||||
const index = parseInt(tagName.slice(12), 10);
|
const index = parseInt(tagName.slice(12), 10);
|
||||||
info.push({ type: "child", idx: index });
|
info.push({ type: "child", idx: index });
|
||||||
el = document.createTextNode("");
|
el = document.createTextNode("");
|
||||||
isActive = true;
|
|
||||||
}
|
}
|
||||||
const attrs = (node as Element).attributes;
|
const attrs = (node as Element).attributes;
|
||||||
const ns = attrs.getNamedItem("block-ns");
|
const ns = attrs.getNamedItem("block-ns");
|
||||||
@@ -161,7 +160,6 @@ function buildTree(
|
|||||||
const attrName = attrs[i].name;
|
const attrName = attrs[i].name;
|
||||||
const attrValue = attrs[i].value;
|
const attrValue = attrs[i].value;
|
||||||
if (attrName.startsWith("block-handler-")) {
|
if (attrName.startsWith("block-handler-")) {
|
||||||
isActive = true;
|
|
||||||
const idx = parseInt(attrName.slice(14), 10);
|
const idx = parseInt(attrName.slice(14), 10);
|
||||||
info.push({
|
info.push({
|
||||||
type: "handler",
|
type: "handler",
|
||||||
@@ -169,7 +167,6 @@ function buildTree(
|
|||||||
event: attrValue,
|
event: attrValue,
|
||||||
});
|
});
|
||||||
} else if (attrName.startsWith("block-attribute-")) {
|
} else if (attrName.startsWith("block-attribute-")) {
|
||||||
isActive = true;
|
|
||||||
const idx = parseInt(attrName.slice(16), 10);
|
const idx = parseInt(attrName.slice(16), 10);
|
||||||
info.push({
|
info.push({
|
||||||
type: "attribute",
|
type: "attribute",
|
||||||
@@ -178,13 +175,11 @@ function buildTree(
|
|||||||
tag: tagName,
|
tag: tagName,
|
||||||
});
|
});
|
||||||
} else if (attrName === "block-attributes") {
|
} else if (attrName === "block-attributes") {
|
||||||
isActive = true;
|
|
||||||
info.push({
|
info.push({
|
||||||
type: "attributes",
|
type: "attributes",
|
||||||
idx: parseInt(attrValue, 10),
|
idx: parseInt(attrValue, 10),
|
||||||
});
|
});
|
||||||
} else if (attrName === "block-ref") {
|
} else if (attrName === "block-ref") {
|
||||||
isActive = true;
|
|
||||||
info.push({
|
info.push({
|
||||||
type: "ref",
|
type: "ref",
|
||||||
idx: parseInt(attrValue, 10),
|
idx: parseInt(attrValue, 10),
|
||||||
@@ -201,7 +196,7 @@ function buildTree(
|
|||||||
nextSibling: null,
|
nextSibling: null,
|
||||||
el,
|
el,
|
||||||
info,
|
info,
|
||||||
refN: isActive ? 1 : 0,
|
refN: 0,
|
||||||
currentNS,
|
currentNS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -215,8 +210,6 @@ function buildTree(
|
|||||||
const tagName = (childNode as Element).tagName;
|
const tagName = (childNode as Element).tagName;
|
||||||
const index = parseInt(tagName.slice(12), 10);
|
const index = parseInt(tagName.slice(12), 10);
|
||||||
info.push({ idx: index, type: "child", isOnlyChild: true });
|
info.push({ idx: index, type: "child", isOnlyChild: true });
|
||||||
isActive = true;
|
|
||||||
tree.refN = 1;
|
|
||||||
} else {
|
} else {
|
||||||
tree.firstChild = buildTree(node.firstChild, tree, tree);
|
tree.firstChild = buildTree(node.firstChild, tree, tree);
|
||||||
el.appendChild(tree.firstChild.el);
|
el.appendChild(tree.firstChild.el);
|
||||||
@@ -229,11 +222,8 @@ function buildTree(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isActive) {
|
if (tree.info.length) {
|
||||||
let cur: IntermediateTree | null = tree;
|
addRef(tree);
|
||||||
while ((cur = cur.parent)) {
|
|
||||||
cur.refN++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
@@ -258,6 +248,13 @@ function buildTree(
|
|||||||
throw new Error("boom");
|
throw new Error("boom");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addRef(tree: IntermediateTree) {
|
||||||
|
tree.isRef = true;
|
||||||
|
do {
|
||||||
|
tree.refN++;
|
||||||
|
} while ((tree = tree.parent as any));
|
||||||
|
}
|
||||||
|
|
||||||
function parentTree(tree: IntermediateTree): IntermediateTree | null {
|
function parentTree(tree: IntermediateTree): IntermediateTree | null {
|
||||||
let parent = tree.parent;
|
let parent = tree.parent;
|
||||||
while (parent && parent.nextSibling === tree) {
|
while (parent && parent.nextSibling === tree) {
|
||||||
@@ -304,21 +301,15 @@ interface BlockCtx {
|
|||||||
cbRefs: number[];
|
cbRefs: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildContext(
|
function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx {
|
||||||
tree: IntermediateTree,
|
|
||||||
ctx?: BlockCtx,
|
|
||||||
fromIdx?: number,
|
|
||||||
toIdx?: number
|
|
||||||
): BlockCtx {
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
const children = new Array(tree.info.filter((v) => v.type === "child").length);
|
const children = new Array(tree.info.filter((v) => v.type === "child").length);
|
||||||
ctx = { collectors: [], locations: [], children, cbRefs: [], refN: tree.refN };
|
ctx = { collectors: [], locations: [], children, cbRefs: [], refN: tree.refN };
|
||||||
fromIdx = 0;
|
fromIdx = 0;
|
||||||
toIdx = tree.refN - 1;
|
|
||||||
}
|
}
|
||||||
if (tree.refN) {
|
if (tree.refN) {
|
||||||
const initialIdx = fromIdx!;
|
const initialIdx = fromIdx!;
|
||||||
const isRef = tree.forceRef || tree.info.length > 0;
|
const isRef = tree.isRef;
|
||||||
const firstChild = tree.firstChild ? tree.firstChild.refN : 0;
|
const firstChild = tree.firstChild ? tree.firstChild.refN : 0;
|
||||||
const nextSibling = tree.nextSibling ? tree.nextSibling.refN : 0;
|
const nextSibling = tree.nextSibling ? tree.nextSibling.refN : 0;
|
||||||
|
|
||||||
@@ -336,13 +327,13 @@ function buildContext(
|
|||||||
if (nextSibling) {
|
if (nextSibling) {
|
||||||
const idx = fromIdx! + firstChild;
|
const idx = fromIdx! + firstChild;
|
||||||
ctx.collectors.push({ idx, prevIdx: initialIdx, getVal: nodeGetNextSibling });
|
ctx.collectors.push({ idx, prevIdx: initialIdx, getVal: nodeGetNextSibling });
|
||||||
buildContext(tree.nextSibling!, ctx, idx, toIdx);
|
buildContext(tree.nextSibling!, ctx, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// left
|
// left
|
||||||
if (firstChild) {
|
if (firstChild) {
|
||||||
ctx.collectors.push({ idx: fromIdx!, prevIdx: initialIdx, getVal: nodeGetFirstChild });
|
ctx.collectors.push({ idx: fromIdx!, prevIdx: initialIdx, getVal: nodeGetFirstChild });
|
||||||
buildContext(tree.firstChild!, ctx, fromIdx!, toIdx! - nextSibling);
|
buildContext(tree.firstChild!, ctx, fromIdx!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,22 @@ describe("misc", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<p>() => 3tostring</p>");
|
expect(fixture.innerHTML).toBe("<p>() => 3tostring</p>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("block with 2 subblocks: variation", async () => {
|
||||||
|
const block = createBlock("<a><b><c><block-child-0/>2</c></b><block-child-1/></a>");
|
||||||
|
const tree = block([], [text("1"), text("3")]);
|
||||||
|
mount(tree, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<a><b><c>12</c></b>3</a>");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("block with 2 subblocks: another variation", async () => {
|
||||||
|
const block = createBlock(
|
||||||
|
`<a block-attribute-0="hello"><b><c><block-child-0/>2</c></b><block-child-1/></a>`
|
||||||
|
);
|
||||||
|
const tree = block(["world"], [text("1"), text("3")]);
|
||||||
|
mount(tree, fixture);
|
||||||
|
expect(fixture.innerHTML).toBe(`<a hello="world"><b><c>12</c></b>3</a>`);
|
||||||
|
});
|
||||||
|
|
||||||
// test.skip("reusing a block skips patching process", async () => {
|
// test.skip("reusing a block skips patching process", async () => {
|
||||||
// const block = createBlock('<div><block-text-0/></div>');
|
// const block = createBlock('<div><block-text-0/></div>');
|
||||||
// const foo = block(["foo"]);
|
// const foo = block(["foo"]);
|
||||||
|
|||||||
Reference in New Issue
Block a user