Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!--
- <h2>WC Wish List</h2>
- <ul>
- <li><input type=checkbox> dynamic attributes</li>
- <li><input type=checkbox checked> if/else conditionals</li>
- </ul>
- -->
- <template id="tpl-href-link">
- <style>
- a {
- color: red;
- }
- </style>
- <a href="{{href}}">
- <slot></slot>
- </a>
- </template>
- <template id="tpl-show-once-loaded">
- <slot></slot>
- </template>
- <template id="tpl-show-once-loading">
- <slot name="is-loading">
- <p>Loading...</p>
- </slot>
- </template>
- <template id="tpl-news-preview">
- <article>
- <show-once>
- <slot slot="show-once" name="headline"></slot>
- <h2><slot name="headline"></slot></h2>
- <show-once>
- <slot slot="show-once" name="author.name"></slot>
- <div slot="is-loading"></div>
- <p>
- By <href-link>
- <slot name="author.@id" slot="href"></slot>
- <slot name="author.name"></slot>
- </href-link>
- </p>
- </show-once>
- <show-once>
- <slot slot="show-once" name="dateModified"></slot>
- <div slot="is-loading"></div>
- Last modified <slot name="dateModified"></slot>
- </show-once>
- <show-once>
- <slot slot="show-once" name="description"></slot>
- <wrap-with>
- <p slot="wrap-with"></p>
- <slot name="description"></slot>
- </wrap-with>
- </show-once>
- </show-once>
- </article>
- </template>
- <template id="tpl-event-preview">
- <style>
- article * {
- all: unset;
- display: flex;
- flex-basis: auto;
- flex-shrink: 0;
- flex-grow: 0;
- line-height: var(--line-height);
- --line-height: 28px;
- }
- h2 {
- font-size: 18px;
- }
- slot {
- padding-right: .25em;
- }
- </style>
- <fetch-data>
- <slot slot="by-id" name="agent.@id"></slot>
- <slot slot="by-id" name="object.@id"></slot>
- </fetch-data>
- <show-once>
- <slot slot="show-once" name="agent.name"></slot>
- <show-once>
- <slot slot="show-once" name="object.name"></slot>
- <article>
- <h2>
- <href-link>
- <slot slot="href" name="agent.@id"></slot>
- <slot name="agent.name"></slot>
- </href-link>
- <slot name="@type"></slot>
- <href-link>
- <slot slot="href" name="object.@id"></slot>
- <slot name="object.name"></slot>
- </href-link>
- </h2>
- <show-once>
- <slot slot="show-once" name="body"></slot>
- <wrap-with>
- <p slot="wrap-with"></p>
- <slot name="body"></slot>
- </wrap-with>
- </show-once>
- </article>
- </show-once>
- </show-once>
- </template>
- <script>
- (() => {
- // utility components
- window.customElements.define('wrap-with', class WrapWith extends window.HTMLElement {
- constructor() {
- super()
- this.attachShadow({
- mode: 'open'
- })
- const wrapWithSlotNode = [...this.children].find(node => node.matches('[slot="wrap-with"]'))
- if (wrapWithSlotNode) {
- const contentSlot = [...this.children].find(node => !node.matches('[slot="wrap-with"]'))
- contentSlot.addEventListener('slotchange', () => {
- this.slotChangedCallback()
- })
- }
- }
- slotChangedCallback() {
- ;[...this.shadowRoot.children].forEach(node => node.remove())
- const wrapWithSlotNode = [...this.children].find(node => node.matches('[slot="wrap-with"]'))
- const contentSlot = [...this.children].find(node => !node.matches('[slot="wrap-with"]'))
- contentSlot.assignedNodes().forEach((contentSlot) => {
- const clone = contentSlot.cloneNode(true)
- const wrapper = wrapWithSlotNode.cloneNode(true)
- clone.removeAttribute('slot')
- wrapper.removeAttribute('slot')
- wrapper.appendChild(clone)
- this.shadowRoot.appendChild(wrapper)
- })
- }
- })
- window.customElements.define('fetch-data', class FetchData extends window.HTMLElement {
- constructor() {
- super()
- this.attachShadow({
- mode: 'open'
- })
- const slots = [...this.querySelectorAll('[slot="by-id"]')]
- slots.forEach(async slot => {
- // fetch(slot.assignedNodes()[0].innerText.trim()).then(...)
- await new Promise(resolve => setTimeout(resolve))
- this.parentNode.host.appendChild(window.document.createTextNode(JSON.stringify({
- "agent": {
- "name": "Justin Amash"
- },
- "object": {
- "name": "Republican Party"
- }
- })))
- slot.remove()
- })
- }
- })
- window.customElements.define('show-once', class ShowOnce extends window.HTMLElement {
- constructor() {
- super()
- this.attachShadow({
- mode: 'open'
- })
- this.shadowRoot.appendChild(window.document.getElementById('tpl-show-once-loading').content.cloneNode(true))
- ;[...this.children].find(node => node.matches('[slot="show-once"]')).addEventListener('slotchange', () => {
- this.slotChangedCallback()
- })
- }
- slotChangedCallback() {
- const showIfSlot = [...this.children].find(node => node.matches('[slot~="show-once"]'))
- const showIfSlotText = !showIfSlot || showIfSlot.assignedNodes && showIfSlot.assignedNodes()[0] && showIfSlot.assignedNodes()[0].innerText.trim()
- ;[...this.shadowRoot.children].forEach(node => node.remove())
- if (showIfSlotText) {
- this.shadowRoot.appendChild(window.document.getElementById('tpl-show-once-loaded').content.cloneNode(true))
- if (showIfSlot) {
- showIfSlot.remove()
- }
- } else {
- this.shadowRoot.appendChild(window.document.getElementById('tpl-show-once-loading').content.cloneNode(true))
- }
- }
- })
- window.customElements.define('href-link', class HrefLink extends window.HTMLElement {
- constructor() {
- super()
- this.attachShadow({
- mode: 'open'
- })
- const hrefSlot = this.querySelector('[slot="href"]')
- hrefSlot.addEventListener('slotchange', () => {
- this.slotChangedCallback()
- })
- }
- slotChangedCallback() {
- const hrefSlot = this.querySelector('[slot="href"]')
- const href = hrefSlot.innerText.trim() || (hrefSlot.assignedNodes && hrefSlot.assignedNodes()[0] && hrefSlot.assignedNodes()[0].innerText.trim())
- if (href) {
- hrefSlot.assignedNodes()[0].remove()
- this.shadowRoot.innerHTML = [...window.document.getElementById('tpl-href-link').content.cloneNode(true).children].map(node => node.outerHTML).join(' ').replace(/{{href}}/, href)
- }
- }
- })
- // ui components
- const BaseCustomElement = class BaseCustomElement extends window.HTMLElement {
- constructor() {
- super()
- this.attachShadow({
- mode: 'open'
- })
- this.shadowRoot.appendChild(window.document.getElementById(this.constructor.templateId).content.cloneNode(true))
- const hiddenDataNode = window.document.createElement('data')
- const hiddenDataSlot = window.document.createElement('slot')
- hiddenDataNode.setAttribute('hidden', 'hidden')
- hiddenDataNode.appendChild(hiddenDataSlot)
- this.shadowRoot.appendChild(hiddenDataNode)
- const defaultSlot = this.shadowRoot.querySelector('slot:not([name])')
- if (defaultSlot) {
- defaultSlot.addEventListener('slotchange', () => {
- this.slotChangedCallback()
- })
- }
- }
- slotChangedCallback() {
- const slotEl = this.shadowRoot.querySelector('slot:not([name])')
- const value = slotEl.assignedNodes().map(node => node.textContent.trim()).join('')
- if (value) {
- Object.entries(JSON.parse(value)).forEach(this.handleSlotCreation.bind(this))
- slotEl.assignedNodes().forEach(node => node.remove())
- }
- }
- handleSlotCreation([key, value]) {
- if (typeof value === 'string') {
- const slotEl = this.querySelector(`[slot="${key}"]`) || window.document.createElement('data')
- slotEl.setAttribute('slot', key)
- slotEl.innerText = value
- this.appendChild(slotEl)
- this.shadowRoot.firstElementChild.setAttribute(`data-${key}`.replace(/@/g, '').replace(/([A-Z])/g, '-$1').toLowerCase(), value)
- } else if (Array.isArray(value)) {
- ;[...this.querySelectorAll(`[slot="${key}"]`)].forEach(node => node.remove())
- const slotEls = value.forEach(v => {
- const slotEl = window.document.createElement('data')
- slotEl.setAttribute('slot', key)
- slotEl.innerText = v
- this.appendChild(slotEl)
- })
- } else if (value) {
- Object.entries(value).forEach(([innerKey, innerValue]) => {
- const slot = innerKey === '@value' ? key : `${key}.${innerKey}`
- if (typeof innerValue === 'string') {
- const slotEl = this.querySelector(`[slot="${slot}"]`) || window.document.createElement('data')
- slotEl.setAttribute('slot', `${slot}`)
- slotEl.innerText = innerValue
- this.appendChild(slotEl)
- } else {
- this.handleSlotCreation([slot, innerValue])
- }
- })
- }
- }
- }
- window.customElements.define('event-preview', class EventPreview extends BaseCustomElement {
- constructor() {
- super()
- }
- static get templateId() {
- return 'tpl-event-preview'
- }
- })
- window.customElements.define('news-preview', class NewsPreview extends BaseCustomElement {
- constructor() {
- super()
- }
- static get templateId() {
- return 'tpl-news-preview'
- }
- })
- })()
- ;(async () => {
- await new Promise(resolve => setTimeout(resolve, 500))
- window.document.querySelector('#newsPreview').appendChild(window.document.createTextNode(JSON.stringify({
- "headline": "Justin Amash leaves Republican Party",
- "author": {
- "@type": "Person",
- "@id": "Person/Michael-Puckett"
- },
- "description": [
- `Justin Amash announced Thursday he was leaving the Republican Party to become an independent. He said he decided to exit the
- GOP "in this current Congress."`,
- `Amash in a July 4 Washington Post op-ed Amash wrote that he was departing the GOP after becoming "disenchanted
- with party politics and frightened by what I see from it."`
- ]
- })))
- await new Promise(resolve => setTimeout(resolve, 500))
- window.document.querySelector('#newsPreview').appendChild(window.document.createTextNode(JSON.stringify({
- "dateModified": {
- "@type": "DateTime",
- "@value": "2019-07-04T11:30:00-07:00"
- },
- "author": {
- "name": "Michael Puckett"
- },
- "about": {
- "agent": {
- "name": "Justin Amash"
- },
- "object": {
- "name": "Republican Party"
- }
- }
- })))
- })()
- </script>
- <news-preview id="newsPreview">
- {
- "@type": "NewsArticle",
- "@id": "NewsArticle/234567890123",
- "about": {
- "@type": "LeaveAction",
- "@id": "LeaveAction/234567890123",
- "agent": {
- "@id": "Person/Justin-Amash"
- },
- "object": {
- "@id": "Organization/Republican-Party"
- }
- }
- }
- </news-preview>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement