PageSourceSearch

https://campus.w3schools.com/cdn/shop/t/68/assets/is-land.min.js?v=92343381495565747271785919708

js w3schools.com collected 2026-09-24 08:24:11 UTC 7,109 bytes, 195 lines download raw bytes

1// MIT License
2
3// Copyright (c) 2022–2023 Zach Leatherman @zachleat
4// https://github.com/11ty/is-land
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15
16class Island extends HTMLElement {
17  static tagName = 'is-land'
18  static prefix = 'is-land--'
19  static attr = { template: 'data-island', ready: 'ready', defer: 'defer-hydration' }
20  static onceCache = new Map()
21  static onReady = new Map()
22  static fallback = {
23    ':not(is-land,:defined,[defer-hydration])': (readyPromise, node, prefix) => {
24      let cloned = document.createElement(prefix + node.localName)
25      for (let attr of node.getAttributeNames()) cloned.setAttribute(attr, node.getAttribute(attr))
26      let shadowroot = node.shadowRoot
27      if (!shadowroot) {
28        let tmpl = node.querySelector(':scope > template:is([shadowrootmode], [shadowroot])')
29        if (tmpl) {
30          let mode = tmpl.getAttribute('shadowrootmode') || tmpl.getAttribute('shadowroot') || 'closed'
31          ;(shadowroot = node.attachShadow({ mode: mode })), shadowroot.appendChild(tmpl.content.cloneNode(!0))
32        }
33      }
34      return (
35        shadowroot && cloned.attachShadow({ mode: shadowroot.mode }).append(...shadowroot.childNodes),
36        cloned.append(...node.childNodes),
37        node.replaceWith(cloned),
38        readyPromise.then(() => {
39          cloned.shadowRoot && node.shadowRoot.append(...cloned.shadowRoot.childNodes),
40            node.append(...cloned.childNodes),
41            cloned.replaceWith(node)
42        })
43      )
44    }
45  }
46  constructor() {
47    super(),
48      (this.ready = new Promise((resolve) => {
49        this.readyResolve = resolve
50      }))
51  }
52  static getParents(el, stopAt = !1) {
53    let nodes = []
54    for (; el; ) {
55      if (el.matches && el.matches(Island.tagName)) {
56        if (stopAt && el === stopAt) break
57        Conditions.hasConditions(el) && nodes.push(el)
58      }
59      el = el.parentNode
60    }
61    return nodes
62  }
63  static async ready(el, parents) {
64    if ((parents || (parents = Island.getParents(el)), 0 === parents.length)) return
65    let imports = await Promise.all(parents.map((p) => p.wait()))
66    return imports.length ? imports[0] : void 0
67  }
68  forceFallback() {
69    window.Island && Object.assign(Island.fallback, window.Island.fallback)
70    for (let selector in Island.fallback) {
71      let components = Array.from(this.querySelectorAll(selector)).reverse()
72      for (let node of components) {
73        if (!node.isConnected) continue
74        let parents = Island.getParents(node)
75        if (1 === parents.length) {
76          let p = Island.ready(node, parents)
77          Island.fallback[selector](p, node, Island.prefix)
78        }
79      }
80    }
81  }
82  wait() {
83    return this.ready
84  }
85  async connectedCallback() {
86    Conditions.hasConditions(this) && this.forceFallback(), await this.hydrate()
87  }
88  getTemplates() {
89    return this.querySelectorAll(`template[${Island.attr.template}]`)
90  }
91  replaceTemplates(templates) {
92    for (let node of templates) {
93      if (Island.getParents(node, this).length > 0) continue
94      let value = node.getAttribute(Island.attr.template)
95      if ('replace' === value) {
96        let children = Array.from(this.childNodes)
97        for (let child of children) this.removeChild(child)
98        this.appendChild(node.content)
99        break
100      }
101      {
102        let html = node.innerHTML
103        if ('once' === value && html) {
104          if (Island.onceCache.has(html)) return void node.remove()
105          Island.onceCache.set(html, !0)
106        }
107        node.replaceWith(node.content)
108      }
109    }
110  }
111  async hydrate() {
112    let conditions = []
113    this.parentNode && conditions.push(Island.ready(this.parentNode))
114    let attrs = Conditions.getConditions(this)
115    for (let condition in attrs)
116      Conditions.map[condition] && conditions.push(Conditions.map[condition](attrs[condition], this))
117    await Promise.all(conditions), this.replaceTemplates(this.getTemplates())
118    for (let fn of Island.onReady.values()) await fn.call(this, Island)
119    this.readyResolve(),
120      this.setAttribute(Island.attr.ready, ''),
121      this.querySelectorAll(`[${Island.attr.defer}]`).forEach((node) => node.removeAttribute(Island.attr.defer))
122  }
123}
124class Conditions {
125  static map = {
126    visible: Conditions.visible,
127    idle: Conditions.idle,
128    interaction: Conditions.interaction,
129    media: Conditions.media,
130    'save-data': Conditions.saveData
131  }
132  static hasConditions(node) {
133    return Object.keys(Conditions.getConditions(node)).length > 0
134  }
135  static getConditions(node) {
136    let map = {}
137    for (let key of Object.keys(Conditions.map))
138      node.hasAttribute(`on:${key}`) && (map[key] = node.getAttribute(`on:${key}`))
139    return map
140  }
141  static visible(noop, el) {
142    if ('IntersectionObserver' in window)
143      return new Promise((resolve) => {
144        let observer = new IntersectionObserver((entries) => {
145          let [entry] = entries
146          entry.isIntersecting && (observer.unobserve(entry.target), resolve())
147        })
148        observer.observe(el)
149      })
150  }
151  static idle() {
152    let onload = new Promise((resolve) => {
153      'complete' !== document.readyState ? window.addEventListener('load', () => resolve(), { once: !0 }) : resolve()
154    })
155    return 'requestIdleCallback' in window
156      ? Promise.all([
157          new Promise((resolve) => {
158            requestIdleCallback(() => {
159              resolve()
160            })
161          }),
162          onload
163        ])
164      : onload
165  }
166  static interaction(eventOverrides, el) {
167    let events = ['click', 'touchstart']
168    return (
169      eventOverrides && (events = (eventOverrides || '').split(',').map((entry) => entry.trim())),
170      new Promise((resolve) => {
171        function resolveFn(e) {
172          resolve()
173          for (let name of events) el.removeEventListener(name, resolveFn)
174        }
175        for (let name of events) el.addEventListener(name, resolveFn, { once: !0 })
176      })
177    )
178  }
179  static media(query) {
180    let mm = { matches: !0 }
181    if ((query && 'matchMedia' in window && (mm = window.matchMedia(query)), !mm.matches))
182      return new Promise((resolve) => {
183        mm.addListener((e) => {
184          e.matches && resolve()
185        })
186      })
187  }
188  static saveData(expects) {
189    if ('connection' in navigator && navigator.connection.saveData !== ('false' !== expects))
190      return new Promise(() => {})
191  }
192}
193'customElements' in window && (window.customElements.define(Island.tagName, Island), (window.Island = Island))
194export { Island, Island as component }
195export const ready = Island.ready

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.