Skip to content

Commit

Permalink
fix(core): fix composing issues for virtual host components
Browse files Browse the repository at this point in the history
  • Loading branch information
Tidyzq committed Sep 27, 2023
1 parent 9730cf8 commit e289a97
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 29 deletions.
49 changes: 23 additions & 26 deletions glass-easel/src/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -787,22 +787,23 @@ export class Element implements NodeCast {
if (ret) return ret
}
}
if (!parent._$virtual) return null
const containingSlot = parent.containingSlot
if (containingSlot === null) return null
if (containingSlot !== undefined) {
return Element._$findFirstNonVirtualChild(containingSlot, parent.slotIndex! + 1)
}
let cur: Element = parent
if (parent instanceof ShadowRoot) {
cur = parent.getHostNode()
if (!cur._$virtual) return null
}
const p = cur.parentNode
if (p) {
return Element._$findFirstNonVirtualChild(p, cur.parentIndex + 1)
const recvParent = (parent: Element): Node | null => {
if (!parent._$virtual) return null
const containingSlot = parent.containingSlot
if (containingSlot === null) return null
if (containingSlot !== undefined) {
return Element._$findFirstNonVirtualChild(containingSlot, parent.slotIndex! + 1)
}
if (parent instanceof ShadowRoot) {
return recvParent(parent.getHostNode())
}
const p = parent.parentNode
if (p) {
return Element._$findFirstNonVirtualChild(p, parent.parentIndex + 1)
}
return null
}
return null
return recvParent(parent)
}

/**
Expand All @@ -825,6 +826,7 @@ export class Element implements NodeCast {
if (element instanceof ShadowRoot) {
cur = element.getHostNode()
if (!cur._$virtual) return null
return Element._$findFirstNonVirtualChild(cur, cur.parentIndex + 1)
}
const p = cur.parentNode
if (p) {
Expand Down Expand Up @@ -1830,6 +1832,9 @@ export class Element implements NodeCast {
}
}

// handling child nodes list for placeholder
placeholder.childNodes = []

// change the parent
placeholder.parentNode = null
placeholder.parentIndex = -1
Expand Down Expand Up @@ -1876,12 +1881,7 @@ export class Element implements NodeCast {
}
;(frag as backend.Element).release()
} else {
if (placeholder.isVirtual()) {
// virtual placeholder does not need to remove
Element.insertChildComposed(parent, replacer, undefined, false, posIndex)
} else {
Element.insertChildComposed(parent, replacer, placeholder, true, posIndex)
}
Element.insertChildComposed(parent, replacer, placeholder, true, posIndex)
for (let i = 0; i < replacedChildren.length; i += 1) {
const child = replacedChildren[i]!
Element.insertChildComposed(replacer, child, undefined, false, i)
Expand All @@ -1906,18 +1906,15 @@ export class Element implements NodeCast {
parent._$mutationObserverTarget?.attachChild(replacer)

// handling child nodes list for replacer
replacer.childNodes.push(...placeholder.childNodes)
replacer.childNodes.push(...replacedChildren)
for (
let i = replacer.childNodes.length - placeholder.childNodes.length;
let i = replacer.childNodes.length - replacedChildren.length;
i < replacer.childNodes.length;
i += 1
) {
replacer.childNodes[i]!.parentIndex = i
}

// handling child nodes list for placeholder
placeholder.childNodes = []

// update id and slot cache if needed
parent.ownerShadowRoot?._$markIdCacheDirty()

Expand Down
41 changes: 40 additions & 1 deletion glass-easel/tests/core/placeholder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,46 @@ const testCases = (testBackend: glassEasel.GeneralBackendContext) => {
expect(domHtml(elem)).toBe('<child><div>21</div></child>')
matchElementWithDom(elem)
})

test('replacing virtual host component', () => {
const placeholder = componentSpace.defineComponent({
options: {
virtualHost: true,
},
template: tmpl('<div>placeholder</div>'),
})
const card = componentSpace.defineComponent({
template: tmpl(`<div><slot></slot></div>`),
})
const def = componentSpace.defineComponent({
is: 'placeholder/ttt/parent',
using: {
child: 'child',
placeholder: placeholder.general(),
card,
},
placeholders: {
child: 'placeholder',
},
template: tmpl(`
<card>
<child>content</child>
</card>
`),
})
const elem = glassEasel.Component.createWithContext('root', def.general(), testBackend)
matchElementWithDom(elem)

componentSpace.defineComponent({
is: 'placeholder/ttt/child',
options: {
virtualHost: true,
},
template: tmpl('<div>actual</div>'),
})
matchElementWithDom(elem)
})
}

describe('placeholder (DOM backend)', () => testCases(domBackend))
describe('placeholder (composed backend)', () => testCases(composedBackend))
describe('placeholder (composed backend)', () => testCases(composedBackend))
119 changes: 117 additions & 2 deletions glass-easel/tests/legacy/virtual.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ const testCases = function (testBackend) {
var e3 = glassEasel.NativeNode.create('e3', root.shadowRoot)
var v1 = glassEasel.VirtualNode.create('v1', root.shadowRoot)
var v2 = glassEasel.VirtualNode.create('v2', root.shadowRoot)
var v3 = glassEasel.VirtualNode.create('v3', root.shadowRoot)
var t1 = glassEasel.TextNode.create('t1', root.shadowRoot)
var t2 = glassEasel.TextNode.create('t2', root.shadowRoot)
e1.appendChild(e2)
Expand All @@ -356,11 +357,17 @@ const testCases = function (testBackend) {
expect(e2.parentNode).toBe(null)
expect(e2.childNodes.length).toBe(0)

v2.selfReplaceWith(e2)
v2.selfReplaceWith(v3)
matchElementWithDom(e1)
matchElementWithDom(v2)
expect(v2.parentNode).toBe(null)
expect(v2.childNodes.length).toBe(0)

v3.selfReplaceWith(e2)
matchElementWithDom(e1)
matchElementWithDom(v3)
expect(v3.parentNode).toBe(null)
expect(v3.childNodes.length).toBe(0)
})

it('should replace component with children', function () {
Expand Down Expand Up @@ -405,6 +412,59 @@ const testCases = function (testBackend) {
})

it('should replace virtualHost component with children', function () {
regElem({
is: 'virtual-comp1',
options: { virtualHost: true },
template: '<div>virtual</div><slot />',
})
regElem({
is: 'comp1',
template: '<div>actual</div><slot />',
})
regElem({
is: 'virtual-comp2',
options: { multipleSlots: true, virtualHost: true },
template: '<slot name="a" /><div>virtual</div><slot name="b"/>',
})
regElem({
is: 'comp2',
options: { multipleSlots: true },
template: '<div><slot name="b"/>actual</div><slot name="a" />',
})
var e1 = glassEasel.NativeNode.create('e1', root.shadowRoot)
var e2 = glassEasel.NativeNode.create('e2', root.shadowRoot)
var e3 = glassEasel.NativeNode.create('e3', root.shadowRoot)
var e4 = glassEasel.NativeNode.create('e4', root.shadowRoot)
var v1 = glassEasel.VirtualNode.create('v1', root.shadowRoot)
var t1 = glassEasel.TextNode.create('t1', root.shadowRoot)
var c1 = root.shadowRoot.createComponent('comp1')
var vc1 = root.shadowRoot.createComponent('virtual-comp1')
var c2 = root.shadowRoot.createComponent('comp2')
var vc2 = root.shadowRoot.createComponent('virtual-comp2')
e1.appendChild(e2)
e2.appendChild(e3)
e2.appendChild(v1)
v1.appendChild(t1)
e2.appendChild(e4)
e4.slot = 'b'

e2.selfReplaceWith(vc1)
matchElementWithDom(e1)
expect(e2.parentNode).toBe(null)
expect(e2.childNodes.length).toBe(0)

vc1.selfReplaceWith(vc2)
matchElementWithDom(e1)
expect(vc1.parentNode).toBe(null)
expect(vc1.childNodes.length).toBe(0)

vc2.selfReplaceWith(c2)
matchElementWithDom(e1)
expect(vc2.parentNode).toBe(null)
expect(vc2.childNodes.length).toBe(0)
})

it('should replace nested virtualHost component with children', function () {
regElem({
is: 'virtual-comp1',
options: { virtualHost: true },
Expand Down Expand Up @@ -460,6 +520,21 @@ const testCases = function (testBackend) {
matchElementWithDom(e1)
expect(vc2.parentNode).toBe(null)
expect(vc2.childNodes.length).toBe(0)

c2.selfReplaceWith(vc2)
matchElementWithDom(e1)
expect(c2.parentNode).toBe(null)
expect(c2.childNodes.length).toBe(0)

vc2.selfReplaceWith(vc1)
matchElementWithDom(e1)
expect(vc2.parentNode).toBe(null)
expect(vc2.childNodes.length).toBe(0)

vc1.selfReplaceWith(vc2)
matchElementWithDom(e1)
expect(vc1.parentNode).toBe(null)
expect(vc1.childNodes.length).toBe(0)
})

it('should replace slot contents with children', function () {
Expand Down Expand Up @@ -531,7 +606,7 @@ const testCases = function (testBackend) {
matchElementWithDom(parent)
})

if (testBackend === domBackend)
if (testBackend !== shadowBackend) {
it('should handles tree manipulations', function () {
regElem({
is: 'virtual-host-c',
Expand Down Expand Up @@ -567,6 +642,46 @@ const testCases = function (testBackend) {
expect(elem.$$.childNodes.length).toBe(0)
matchElementWithDom(elem)
})
}

it('should handles wx-if update', function () {
regElem({
is: 'list-view',
options: {
virtualHost: true,
},
template: '<listview><slot /></listview>',
})
regElem({
is: 'virtual-host-b',
options: {
virtualHost: true,
},
data: {
a: false,
b: false,
},
template: '<a wx:if="{{a}}" /><b wx:if="{{b}}" />',
})
regElem({
is: 'c',
options: {},
template: '<list-view><virtual-host-b id="b" /></list-view><span />',
})
var parent = glassEasel.NativeNode.create('span', root.shadowRoot)
var elem = root.shadowRoot.createComponent('c')
parent.appendChild(elem)
matchElementWithDom(parent)

elem.$.b.setData({ a: true })
matchElementWithDom(parent)

elem.$.b.setData({ a: false, b: true })
matchElementWithDom(parent)

elem.$.b.setData({ b: false })
matchElementWithDom(parent)
})
})
}

Expand Down

0 comments on commit e289a97

Please sign in to comment.