-
Notifications
You must be signed in to change notification settings - Fork 767
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(slot): fix appendChild when using slot polyfill
Closes #1686
- Loading branch information
1 parent
4070312
commit e8b4c59
Showing
14 changed files
with
240 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import * as d from '../declarations'; | ||
import { BUILD } from '@build-conditionals'; | ||
import { supportsShadowDom } from '@platform'; | ||
|
||
|
||
export const cloneNodeFix = (HostElementPrototype: any) => { | ||
const orgCloneNode = HostElementPrototype.cloneNode; | ||
|
||
HostElementPrototype.cloneNode = function(deep?: boolean) { | ||
const srcNode = this; | ||
const isShadowDom = BUILD.shadowDom ? srcNode.shadowRoot && supportsShadowDom : false; | ||
const clonedNode = orgCloneNode.call(srcNode, isShadowDom ? deep : false) as Node; | ||
if (BUILD.slot && !isShadowDom && deep) { | ||
let i = 0; | ||
let slotted; | ||
for (; i < srcNode.childNodes.length; i++) { | ||
slotted = (srcNode.childNodes[i] as any)['s-nr']; | ||
if (slotted) { | ||
if (BUILD.appendChildSlotFix && (clonedNode as any).__appendChild) { | ||
(clonedNode as any).__appendChild(slotted.cloneNode(true)); | ||
} else { | ||
clonedNode.appendChild(slotted.cloneNode(true)); | ||
} | ||
} | ||
} | ||
} | ||
return clonedNode; | ||
}; | ||
}; | ||
|
||
export const appendChildSlotFix = (HostElementPrototype: any) => { | ||
|
||
HostElementPrototype.__appendChild = HostElementPrototype.appendChild; | ||
HostElementPrototype.appendChild = function(this: d.RenderNode, newChild: d.RenderNode) { | ||
const slotName = newChild['s-sn'] = getSlotName(newChild); | ||
const slotNode = getHostSlotNode(this, slotName); | ||
if (slotNode) { | ||
const slotChildNodes = getHostSlotChildNodes(slotNode, slotName); | ||
const appendAfter = slotChildNodes[slotChildNodes.length - 1]; | ||
return appendAfter.parentNode.insertBefore(newChild, appendAfter.nextSibling); | ||
} | ||
return (this as any).__appendChild(newChild); | ||
}; | ||
|
||
}; | ||
|
||
const getSlotName = (node: Node) => | ||
(node.nodeType === 1 && (node as Element).getAttribute('slot')) || ''; | ||
|
||
const getHostSlotNode = (elm: d.RenderNode, slotName: string) => { | ||
let childNodes = elm.childNodes as any as d.RenderNode[]; | ||
let i = 0; | ||
let childNode: d.RenderNode; | ||
|
||
for (; i < childNodes.length; i++) { | ||
childNode = childNodes[i]; | ||
if (childNode['s-sr'] && childNode['s-sn'] === slotName) { | ||
return childNode; | ||
} | ||
childNode = getHostSlotNode(childNode, slotName); | ||
if (childNode) { | ||
return childNode; | ||
} | ||
} | ||
return null; | ||
}; | ||
|
||
const getHostSlotChildNodes = (n: d.RenderNode, slotName: string) => { | ||
const childNodes: d.RenderNode[] = [n]; | ||
while ((n = n.nextSibling as any) && (n as d.RenderNode)['s-sn'] === slotName) { | ||
childNodes.push(n as any); | ||
} | ||
return childNodes; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Component, Host, h } from '@stencil/core'; | ||
|
||
@Component({ | ||
tag: 'append-child', | ||
styles: ` | ||
h1 { | ||
color: red; | ||
font-weight: bold; | ||
} | ||
article { | ||
color: green; | ||
font-weight: bold; | ||
} | ||
section { | ||
color: blue; | ||
font-weight: bold; | ||
} | ||
`, | ||
scoped: true, | ||
}) | ||
export class AppendChild { | ||
|
||
render() { | ||
return ( | ||
<Host> | ||
<h1> | ||
H1 Top | ||
<slot name="h1"/> | ||
<div> | ||
H1 Bottom | ||
</div> | ||
</h1> | ||
<article> | ||
Default Top | ||
<slot/> | ||
Default Bottom | ||
</article> | ||
<h6> | ||
<section> | ||
H6 Top | ||
<slot name="h6"/> | ||
<div> | ||
H6 Bottom | ||
</div> | ||
</section> | ||
</h6> | ||
</Host> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf8"> | ||
<script src="/build/testapp.esm.js" type="module"></script> | ||
<script src="/build/testapp.js" nomodule></script> | ||
|
||
<button id="btnDefault" onclick="appendToDefault()">Append To Default Slot</button> | ||
<br> | ||
<button id="btnH1" onclick="appendToH1()">Append To H1 Slot</button id="btnDefault"> | ||
<br> | ||
<button id="btnH6" onclick="appendToH6()">Append To H6 Slot</button id="btnDefault"> | ||
<br> | ||
|
||
<append-child id="appendCmp">LightDom</append-child> | ||
|
||
<script> | ||
var wc = document.getElementsByTagName('append-child')[0]; | ||
var defaultCount = 0; | ||
var h1Count = 0; | ||
var h6Count = 0; | ||
|
||
function appendToDefault() { | ||
var defaultElm = document.createElement('nav'); | ||
defaultElm.innerHTML = 'Default Slot ' + (defaultCount++); | ||
wc.appendChild(defaultElm); | ||
} | ||
|
||
function appendToH1() { | ||
var h1Elm = document.createElement('nav'); | ||
h1Elm.setAttribute('slot', 'h1'); | ||
h1Elm.innerHTML = 'H1 Middle ' + (h1Count++); | ||
wc.appendChild(h1Elm); | ||
} | ||
|
||
function appendToH6() { | ||
var h6Elm = document.createElement('nav'); | ||
h6Elm.setAttribute('slot', 'h6'); | ||
h6Elm.innerHTML = 'H6 Middle ' + (h6Count++); | ||
wc.appendChild(h6Elm); | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { setupDomTests, waitForChanges } from '../util'; | ||
|
||
|
||
describe('append-child', function() { | ||
const { setupDom, tearDownDom } = setupDomTests(document); | ||
let app: HTMLElement; | ||
|
||
beforeEach(async () => { | ||
app = await setupDom('/append-child/index.html'); | ||
}); | ||
afterEach(tearDownDom); | ||
|
||
it('appends to correct slot', async () => { | ||
const btnDefault = app.querySelector('#btnDefault') as HTMLButtonElement; | ||
btnDefault.click(); | ||
btnDefault.click(); | ||
|
||
const btnH1 = app.querySelector('#btnH1') as HTMLButtonElement; | ||
btnH1.click(); | ||
btnH1.click(); | ||
|
||
const btnH6 = app.querySelector('#btnH6') as HTMLButtonElement; | ||
btnH6.click(); | ||
btnH6.click(); | ||
|
||
await waitForChanges(); | ||
|
||
expect(app.querySelector('h1').textContent).toBe('H1 TopH1 Middle 0H1 Middle 1H1 Bottom'); | ||
expect(app.querySelector('article').textContent).toBe('Default TopLightDomDefault Slot 0Default Slot 1Default Bottom'); | ||
expect(app.querySelector('section').textContent).toBe('H6 TopH6 Middle 0H6 Middle 1H6 Bottom'); | ||
}); | ||
|
||
}); |
Oops, something went wrong.