diff --git a/libs/blocks/fragment/fragment.js b/libs/blocks/fragment/fragment.js index dd938b4374..1d671ee17d 100644 --- a/libs/blocks/fragment/fragment.js +++ b/libs/blocks/fragment/fragment.js @@ -11,7 +11,7 @@ const removeHash = (url) => { const isCircularRef = (href) => [...Object.values(fragMap)] .some((tree) => { const node = tree.find(href); - return node ? !(node.isLeaf) : false; + return node?.isRecursive; }); const updateFragMap = (fragment, a, href) => { @@ -19,15 +19,24 @@ const updateFragMap = (fragment, a, href) => { .filter((link) => localizeLink(link.href).includes('/fragments/')); if (!fragLinks.length) return; - if (document.body.contains(a)) { // is fragment on page (not nested) + if (document.body.contains(a) && !a.parentElement?.closest('.fragment')) { // eslint-disable-next-line no-use-before-define fragMap[href] = new Tree(href); fragLinks.forEach((link) => fragMap[href].insert(href, localizeLink(removeHash(link.href)))); } else { Object.values(fragMap).forEach((tree) => { - if (tree.find(href)) { - fragLinks.forEach((link) => tree.insert(href, localizeLink(removeHash(link.href)))); - } + const hrefNode = tree.find(href); + if (!hrefNode) return; + + fragLinks.forEach((link) => { + const localizedHref = localizeLink(removeHash(link.href)); + const parentNodeSameHref = hrefNode.findParent(localizedHref); + if (parentNodeSameHref) { + parentNodeSameHref.isRecursive = true; + } else { + hrefNode.addChild(localizedHref); + } + }); }); } }; @@ -143,10 +152,19 @@ class Node { this.value = value; this.parent = parent; this.children = []; + this.isRecursive = false; + } + + addChild(key, value = key) { + const alreadyHasChild = this.children.some((n) => n.key === key); + if (!alreadyHasChild) { + this.children.push(new Node(key, value, this)); + } } - get isLeaf() { - return this.children.length === 0; + findParent(key) { + if (this.parent?.key === key) return this.parent; + return this.parent?.findParent(key); } } diff --git a/test/blocks/fragment/mocks/fragments/frag-b.plain.html b/test/blocks/fragment/mocks/fragments/frag-b.plain.html index 69f2631d42..0ce16338dc 100644 --- a/test/blocks/fragment/mocks/fragments/frag-b.plain.html +++ b/test/blocks/fragment/mocks/fragments/frag-b.plain.html @@ -1,4 +1,4 @@
Frag B, Loads Frag A
- Frag A link + Frag C link
diff --git a/test/blocks/fragment/mocks/fragments/frag-c.plain.html b/test/blocks/fragment/mocks/fragments/frag-c.plain.html new file mode 100644 index 0000000000..69f2631d42 --- /dev/null +++ b/test/blocks/fragment/mocks/fragments/frag-c.plain.html @@ -0,0 +1,4 @@ +
+
Frag B, Loads Frag A
+ Frag A link +
diff --git a/test/blocks/fragment/tree.test.js b/test/blocks/fragment/tree.test.js index d513fa6d7d..b02a0f474f 100644 --- a/test/blocks/fragment/tree.test.js +++ b/test/blocks/fragment/tree.test.js @@ -21,8 +21,30 @@ describe('Tree Data Struct', () => { t.remove('first'); expect(t.find('first')).to.be.undefined; expect(t.find('second')).to.be.equal(t.root.children[0]); + }); + + it('Will return false if it cant insert or remove a node', () => { + const t = new Tree('root'); + t.insert('root', 'first'); + t.insert('root', 'second'); + const isInserted = t.insert('doesnt-exist', 'third'); + expect(isInserted).to.be.false; + + const isRemoved = t.remove('doesnt-exist'); + expect(isRemoved).to.be.false; + }); + + it('Can add child directly from a Node', () => { + const t = new Tree('root'); + t.insert('root', 'first'); + t.insert('root', 'second'); + const firstNode = t.find('first'); + firstNode.addChild('third'); + expect(firstNode.children.length).to.be.equal(1); + expect(firstNode.children[0].key).to.be.equal('third'); - expect(t.find('second').isLeaf).to.be.true; - expect(t.root.isLeaf).to.be.false; + // adding a duplicate key should not add a new child + firstNode.addChild('third'); + expect(firstNode.children.length).to.be.equal(1); }); });