mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
feat: support for custom and slot elements (#2581)
This commit is contained in:
parent
eeb5a3ea1d
commit
acb4cd24b8
@ -20,21 +20,32 @@ const parseNodeTree = (node: Node, parent: ElementContainer, root: ElementContai
|
|||||||
if (isTextNode(childNode) && childNode.data.trim().length > 0) {
|
if (isTextNode(childNode) && childNode.data.trim().length > 0) {
|
||||||
parent.textNodes.push(new TextContainer(childNode, parent.styles));
|
parent.textNodes.push(new TextContainer(childNode, parent.styles));
|
||||||
} else if (isElementNode(childNode)) {
|
} else if (isElementNode(childNode)) {
|
||||||
const container = createContainer(childNode);
|
if (isSlotElement(childNode) && childNode.assignedNodes) {
|
||||||
if (container.styles.isVisible()) {
|
childNode.assignedNodes().forEach((childNode) => parseNodeTree(childNode, parent, root));
|
||||||
if (createsRealStackingContext(childNode, container, root)) {
|
} else {
|
||||||
container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT;
|
const container = createContainer(childNode);
|
||||||
} else if (createsStackingContext(container.styles)) {
|
if (container.styles.isVisible()) {
|
||||||
container.flags |= FLAGS.CREATES_STACKING_CONTEXT;
|
if (createsRealStackingContext(childNode, container, root)) {
|
||||||
}
|
container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT;
|
||||||
|
} else if (createsStackingContext(container.styles)) {
|
||||||
|
container.flags |= FLAGS.CREATES_STACKING_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) {
|
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) {
|
||||||
container.flags |= FLAGS.IS_LIST_OWNER;
|
container.flags |= FLAGS.IS_LIST_OWNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.elements.push(container);
|
parent.elements.push(container);
|
||||||
if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) {
|
childNode.slot;
|
||||||
parseNodeTree(childNode, container, root);
|
if (childNode.shadowRoot) {
|
||||||
|
parseNodeTree(childNode.shadowRoot, container, root);
|
||||||
|
} else if (
|
||||||
|
!isTextareaElement(childNode) &&
|
||||||
|
!isSVGElement(childNode) &&
|
||||||
|
!isSelectElement(childNode)
|
||||||
|
) {
|
||||||
|
parseNodeTree(childNode, container, root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,3 +129,4 @@ export const isStyleElement = (node: Element): node is HTMLStyleElement => node.
|
|||||||
export const isScriptElement = (node: Element): node is HTMLScriptElement => node.tagName === 'SCRIPT';
|
export const isScriptElement = (node: Element): node is HTMLScriptElement => node.tagName === 'SCRIPT';
|
||||||
export const isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA';
|
export const isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA';
|
||||||
export const isSelectElement = (node: Element): node is HTMLSelectElement => node.tagName === 'SELECT';
|
export const isSelectElement = (node: Element): node is HTMLSelectElement => node.tagName === 'SELECT';
|
||||||
|
export const isSlotElement = (node: Element): node is HTMLSlotElement => node.tagName === 'SLOT';
|
||||||
|
45
tests/reftests/webcomponents/autonomous-custom-element.js
Normal file
45
tests/reftests/webcomponents/autonomous-custom-element.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
class AutonomousCustomElement extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const shadow = this.attachShadow({mode: 'open'});
|
||||||
|
const wrapper = document.createElement('span');
|
||||||
|
wrapper.setAttribute('class', 'wrapper');
|
||||||
|
|
||||||
|
const info = document.createElement('span');
|
||||||
|
info.setAttribute('class', 'info');
|
||||||
|
|
||||||
|
info.textContent = this.getAttribute('text');
|
||||||
|
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = this.getAttribute('img');
|
||||||
|
|
||||||
|
// Create some CSS to apply to the shadow dom
|
||||||
|
const style = document.createElement('style');
|
||||||
|
|
||||||
|
style.textContent = `
|
||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
width: 200px;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 10px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
shadow.appendChild(style);
|
||||||
|
shadow.appendChild(wrapper);
|
||||||
|
wrapper.appendChild(img);
|
||||||
|
wrapper.appendChild(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('autonomous-custom-element', AutonomousCustomElement);
|
51
tests/reftests/webcomponents/slot-element.js
Normal file
51
tests/reftests/webcomponents/slot-element.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
customElements.define('summary-display',
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const template = document.getElementById('summary-display-template');
|
||||||
|
const templateContent = template.content;
|
||||||
|
|
||||||
|
const shadowRoot = this.attachShadow({mode: 'open'});
|
||||||
|
shadowRoot.appendChild(templateContent.cloneNode(true));
|
||||||
|
|
||||||
|
const items = Array.from(this.querySelectorAll('li'));
|
||||||
|
const descriptions = Array.from(this.querySelectorAll('p'));
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
handleClick(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
descriptions.forEach(description => {
|
||||||
|
updateDisplay(description, items[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleClick(item) {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
items.forEach(item => {
|
||||||
|
item.style.backgroundColor = 'white';
|
||||||
|
});
|
||||||
|
|
||||||
|
descriptions.forEach(description => {
|
||||||
|
updateDisplay(description, item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay(description, item) {
|
||||||
|
description.removeAttribute('slot');
|
||||||
|
|
||||||
|
if(description.getAttribute('data-name') === item.textContent) {
|
||||||
|
description.setAttribute('slot', 'choice');
|
||||||
|
item.style.backgroundColor = '#bad0e4';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const slots = this.shadowRoot.querySelectorAll('slot');
|
||||||
|
slots[1].addEventListener('slotchange', function(e) {
|
||||||
|
const nodes = slots[1].assignedNodes();
|
||||||
|
console.log(`Element in Slot "${slots[1].name}" changed to "${nodes[0].outerHTML}".`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
53
tests/reftests/webcomponents/webcomponents.html
Normal file
53
tests/reftests/webcomponents/webcomponents.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Web components tests</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<script type="text/javascript" src="../../test.js"></script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h1>Autonomous custom element</h1>
|
||||||
|
<autonomous-custom-element img="../../assets/image.jpg" text="This is text"></autonomous-custom-element>
|
||||||
|
<h1>Slot element</h1>
|
||||||
|
<summary-display>
|
||||||
|
<ul slot="master-list">
|
||||||
|
<li>Apples</li>
|
||||||
|
<li>Pears</li>
|
||||||
|
<li>Bananas</li>
|
||||||
|
<li>Oranges</li>
|
||||||
|
<li>Peaches</li>
|
||||||
|
<li>Strawberries</li>
|
||||||
|
<li>Blueberries</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p data-name="Apples">A common, sweet, crunchy fruit, usually green or yellow in color.</p>
|
||||||
|
<p data-name="Pears">A fairly common, sweet, usually green fruit, usually softer than Apples.</p>
|
||||||
|
<p data-name="Bananas">A long, curved, yellow fruit, with a fairly gentle flavor.</p>
|
||||||
|
<p data-name="Oranges">Orange in color, usually sweet but can be sharp, often contains pips.</p>
|
||||||
|
<p data-name="Peaches">An orange fruit with big stone in the middle, and sweet, juicy flesh.</p>
|
||||||
|
<p data-name="Strawberries">A red fruit with yellow seeds on the outside; has a sweet flavor and a pretty shape.</p>
|
||||||
|
<p data-name="Blueberries">They are berries and they are blue; sweet in flavor, small in size, round.</p>
|
||||||
|
</summary-display>
|
||||||
|
|
||||||
|
<template id="summary-display-template">
|
||||||
|
<article>
|
||||||
|
<div>
|
||||||
|
<slot name="master-list"></slot>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<slot name="choice"></slot>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="autonomous-custom-element.js"></script>
|
||||||
|
<script src="slot-element.js"></script>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user