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) {
|
||||
parent.textNodes.push(new TextContainer(childNode, parent.styles));
|
||||
} else if (isElementNode(childNode)) {
|
||||
const container = createContainer(childNode);
|
||||
if (container.styles.isVisible()) {
|
||||
if (createsRealStackingContext(childNode, container, root)) {
|
||||
container.flags |= FLAGS.CREATES_REAL_STACKING_CONTEXT;
|
||||
} else if (createsStackingContext(container.styles)) {
|
||||
container.flags |= FLAGS.CREATES_STACKING_CONTEXT;
|
||||
}
|
||||
if (isSlotElement(childNode) && childNode.assignedNodes) {
|
||||
childNode.assignedNodes().forEach((childNode) => parseNodeTree(childNode, parent, root));
|
||||
} else {
|
||||
const container = createContainer(childNode);
|
||||
if (container.styles.isVisible()) {
|
||||
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) {
|
||||
container.flags |= FLAGS.IS_LIST_OWNER;
|
||||
}
|
||||
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) {
|
||||
container.flags |= FLAGS.IS_LIST_OWNER;
|
||||
}
|
||||
|
||||
parent.elements.push(container);
|
||||
if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) {
|
||||
parseNodeTree(childNode, container, root);
|
||||
parent.elements.push(container);
|
||||
childNode.slot;
|
||||
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 isTextareaElement = (node: Element): node is HTMLTextAreaElement => node.tagName === 'TEXTAREA';
|
||||
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