'use strict'; class MiniElement { constructor(tagName = 'div') { this.tagName = String(tagName).toUpperCase(); this.nodeType = this.tagName === '#TEXT' ? 3 : 1; this.parentNode = null; this.children = []; this.attributes = {}; this.dataset = {}; this.listeners = {}; this.offsetLeft = 0; this.offsetTop = 0; this.offsetHeight = 0; this.offsetWidth = 0; this.scrollHeight = 0; this.scrollWidth = 0; this.clientWidth = 0; this.scrollLeft = 0; this.rectTop = 0; this.rectLeft = 0; this.rectWidth = 0; this.visible = true; this.scrollCalls = []; this._text = ''; this._classes = new Set(); this.classList = { add: (...tokens) => tokens.forEach((token) => this._classes.add(token)), remove: (...tokens) => tokens.forEach((token) => this._classes.delete(token)), contains: (token) => this._classes.has(token), toggle: (token, force) => { const shouldAdd = force === undefined ? !this._classes.has(token) : Boolean(force); if (shouldAdd) this._classes.add(token); else this._classes.delete(token); return shouldAdd; }, }; } get className() { return Array.from(this._classes).join(' '); } set className(value) { this._classes = new Set(String(value || '').split(/\s+/).filter(Boolean)); } get id() { return this.getAttribute('id') || ''; } set id(value) { this.setAttribute('id', value); } get type() { return this.getAttribute('type') || ''; } set type(value) { this.setAttribute('type', value); } get parentElement() { return this.parentNode && this.parentNode.tagName !== '#DOCUMENT' ? this.parentNode : null; } get firstChild() { return this.children[0] || null; } get firstElementChild() { return this.children.find((child) => child.nodeType === 1) || null; } get nextElementSibling() { if (!this.parentNode) return null; const siblings = this.parentNode.children.filter((child) => child.nodeType === 1); return siblings[siblings.indexOf(this) + 1] || null; } get textContent() { return this._text + this.children.map((child) => child.textContent).join(''); } set textContent(value) { this._text = String(value); this.replaceChildren(); } get innerHTML() { return this.children.map((child) => child.outerHTML || child.textContent).join(''); } set innerHTML(markup) { this._text = ''; this.replaceChildren(); parseMarkup(String(markup || ''), this); } setAttribute(name, value) { const text = String(value); this.attributes[name] = text; if (name === 'class') this.className = text; if (name.startsWith('data-')) this.dataset[toDatasetKey(name.slice(5))] = text; } getAttribute(name) { return Object.hasOwn(this.attributes, name) ? this.attributes[name] : null; } hasAttribute(name) { return Object.hasOwn(this.attributes, name); } removeAttribute(name) { delete this.attributes[name]; if (name === 'class') this.className = ''; if (name.startsWith('data-')) delete this.dataset[toDatasetKey(name.slice(5))]; } appendChild(child) { if (child.parentNode) child.remove(); child.parentNode = this; child.ownerDocument = this.ownerDocument; this.children.push(child); return child; } insertBefore(child, anchor) { if (!anchor || anchor.parentNode !== this) return this.appendChild(child); if (child.parentNode) child.remove(); child.parentNode = this; child.ownerDocument = this.ownerDocument; this.children.splice(this.children.indexOf(anchor), 0, child); return child; } replaceChildren(...nodes) { this.children.forEach((child) => { child.parentNode = null; }); this.children = []; nodes.forEach((node) => this.appendChild(node)); } remove() { if (!this.parentNode) return; const siblings = this.parentNode.children; const index = siblings.indexOf(this); if (index !== -1) siblings.splice(index, 1); this.parentNode = null; } addEventListener(type, callback, options = {}) { (this.listeners[type] ||= []).push({ callback, once: Boolean(options && options.once) }); } removeEventListener(type, callback) { this.listeners[type] = (this.listeners[type] || []).filter((item) => item.callback !== callback); } dispatch(type, properties = {}) { const event = { type, target: this, defaultPrevented: false, preventDefault() { this.defaultPrevented = true; }, stopPropagation() { this.propagationStopped = true; }, ...properties, }; let node = this; while (node) { const listeners = (node.listeners[type] || []).slice(); for (const listener of listeners) { listener.callback(event); if (listener.once) node.removeEventListener(type, listener.callback); } if (event.propagationStopped) break; node = node.parentNode; } return event; } dispatchEvent(event) { return this.dispatch(event.type, event); } click() { return this.dispatch('click'); } focus() { this.ownerDocument.activeElement = this; } closest(selector) { for (let node = this; node; node = node.parentNode) { if (matchesSelector(node, selector)) return node; } return null; } matches(selector) { return matchesSelector(this, selector); } querySelectorAll(selector) { const directOnly = selector.startsWith(':scope > '); const query = directOnly ? selector.slice(9) : selector; const nodes = directOnly ? this.children.slice() : descendants(this); return nodes.filter((node) => matchesSelector(node, query)); } querySelector(selector) { return this.querySelectorAll(selector)[0] || null; } insertAdjacentHTML(position, markup) { const fragment = this.ownerDocument.createElement('div'); fragment.innerHTML = markup; const nodes = fragment.children.slice(); if (position === 'afterbegin') nodes.reverse().forEach((node) => this.insertBefore(node, this.firstChild)); else if (position === 'beforebegin' && this.parentNode) nodes.forEach((node) => this.parentNode.insertBefore(node, this)); else nodes.forEach((node) => this.appendChild(node)); } scrollTo(options) { this.scrollCalls.push(options); } getBoundingClientRect() { return { top: this.rectTop, left: this.rectLeft, width: this.rectWidth || this.offsetWidth }; } getClientRects() { return this.visible ? [this.getBoundingClientRect()] : []; } } class MiniDocument extends MiniElement { constructor() { super('#document'); this.nodeType = 9; this.ownerDocument = this; this.readyState = 'complete'; this.body = this.createElement('body'); this.appendChild(this.body); this.activeElement = null; } createElement(tagName) { const element = new MiniElement(tagName); element.ownerDocument = this; return element; } getElementById(id) { return descendants(this).find((node) => node.id === String(id)) || null; } } function toDatasetKey(value) { return value.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase()); } function descendants(node) { return node.children.flatMap((child) => [child, ...descendants(child)]); } function matchesCompound(node, selector) { if (!selector || selector === '*') return true; const tag = selector.match(/^[a-z][a-z0-9-]*/i); if (tag && node.tagName.toLowerCase() !== tag[0].toLowerCase()) return false; const id = selector.match(/#([a-zA-Z_][\w-]*)/); if (id && node.getAttribute('id') !== id[1]) return false; for (const [, className] of selector.matchAll(/\.([a-zA-Z_][\w-]*)/g)) { if (!node.classList.contains(className)) return false; } for (const [, name, operator, expected] of selector.matchAll(/\[([\w-]+)(\^=|\$=|\*=|=)?(?:\s*["']?([^\]"']*)["']?)?\]/g)) { if (!node.hasAttribute(name)) return false; if (operator === '=') { if (node.getAttribute(name) !== expected) return false; } else if (operator === '^=' && !node.getAttribute(name).startsWith(expected)) return false; else if (operator === '$=' && !node.getAttribute(name).endsWith(expected)) return false; else if (operator === '*=' && !node.getAttribute(name).includes(expected)) return false; } return true; } function matchesSingleSelector(node, selector) { const tokens = selector.replace(/>/g, ' > ').trim().split(/\s+/); let cursor = node; if (!matchesCompound(cursor, tokens.pop())) return false; while (tokens.length) { const combinator = tokens.pop(); const previous = combinator === '>' ? tokens.pop() : combinator; if (combinator === '>') { cursor = cursor.parentNode; if (!cursor || !matchesCompound(cursor, previous)) return false; } else { cursor = cursor.parentNode; while (cursor && !matchesCompound(cursor, previous)) cursor = cursor.parentNode; if (!cursor) return false; } } return true; } function matchesSelector(node, selector) { return String(selector).split(',').some((part) => matchesSingleSelector(node, part.trim())); } function parseMarkup(markup, parent) { const tokens = markup.match(/|<[^>]+>|[^<]+/g) || []; const stack = [parent]; const voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']); for (const token of tokens) { if (token.startsWith('