oxe
Version:
A mighty tiny web components framework/library
1,090 lines (1,066 loc) • 99.8 kB
JavaScript
/*!
Name: oxe
Version: 6.0.8
License: MPL-2.0
Author: Alexander Elias
Email: alex.steven.elis@gmail.com
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Oxe = factory());
})(this, (function () { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __classPrivateFieldGet(receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}
function __classPrivateFieldSet(receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
}
const get = function (task, path, target, key, receiver) {
const value = Reflect.get(target, key, receiver);
if (value && typeof value === 'object') {
path = path ? `${path}.${key}` : `${key}`;
return new Proxy(value, {
get: get.bind(null, task, path),
set: set.bind(null, task, path),
deleteProperty: deleteProperty.bind(null, task, path)
});
}
else {
return value;
}
};
const deleteProperty = function (task, path, target, key) {
if (target instanceof Array) {
target.splice(key, 1);
}
else {
Reflect.deleteProperty(target, key);
}
task(path ? `${path}.${key}` : `${key}`, 'unrender');
return true;
};
const set = function (task, path, target, key, to, receiver) {
const from = Reflect.get(target, key, receiver);
if (key === 'length') {
task(path, 'render');
task(path ? `${path}.${key}` : `${key}`, 'render');
return true;
}
else if (from === to) {
return true;
}
Reflect.set(target, key, to, receiver);
// console.log(path, key, from, to);
// if (from && typeof from === 'object') {
// if (to && typeof to === 'object') {
// const tasks = [];
// for (const child in from) {
// if (!(child in to)) {
// tasks.push(task(path ? `${path}.${key}.${child}` : `${key}.${child}`, 'unrender'));
// }
// }
// Promise.all(tasks).then(() => task(path ? `${path}.${key}` : `${key}`, 'render'));
// } else {
// task(path ? `${path}.${key}` : `${key}`, 'unrender').then(() => task(path ? `${path}.${key}` : `${key}`, 'render'));
// }
// } else {
// task(path ? `${path}.${key}` : `${key}`, 'render');
// }
task(path ? `${path}.${key}` : `${key}`, 'render');
return true;
};
const observer = function (source, task, path = '') {
return new Proxy(source, {
get: get.bind(null, task, path),
set: set.bind(null, task, path),
deleteProperty: deleteProperty.bind(null, task, path)
});
};
var booleanTypes = [
'allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default',
'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'draggable', 'enabled', 'formnovalidate',
'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'hidden',
'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected',
'sortable', 'spellcheck', 'translate', 'truespeed', 'typemustmatch', 'visible'
];
const format = (data) => data === undefined ? '' : typeof data === 'object' ? JSON.stringify(data) : data;
const standardRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
let data = yield binder.compute();
const boolean = booleanTypes.includes(binder.name);
binder.node.value = '';
if (boolean) {
data = data ? true : false;
if (data)
binder.owner.setAttributeNode(binder.node);
else
binder.owner.removeAttribute(binder.name);
}
else {
data = format(data);
binder.owner[binder.name] = data;
binder.owner.setAttribute(binder.name, data);
}
});
};
const standardUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
const boolean = booleanTypes.includes(binder.name);
if (boolean) {
binder.owner.removeAttribute(binder.name);
}
else {
binder.owner.setAttribute(binder.name, '');
}
});
};
var standard = { render: standardRender, unrender: standardUnrender };
const flag = Symbol('RadioFlag');
const handler = function (binder, event) {
return __awaiter(this, void 0, void 0, function* () {
const checked = binder.owner.checked;
const computed = yield binder.compute({ $event: event, $checked: checked, $assignment: !!event });
if (computed) {
binder.owner.setAttributeNode(binder.node);
}
else {
binder.owner.removeAttribute('checked');
}
});
};
const checkedRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
if (!binder.meta.setup) {
binder.node.value = '';
binder.meta.setup = true;
if (binder.owner.type === 'radio') {
binder.owner.addEventListener('input', (event) => __awaiter(this, void 0, void 0, function* () {
if (event.detail === flag)
return handler(binder, event);
const parent = binder.owner.form || binder.owner.getRootNode();
const radios = parent.querySelectorAll(`[type="radio"][name="${binder.owner.name}"]`);
const input = new CustomEvent('input', { detail: flag });
for (const radio of radios) {
if (radio === event.target) {
yield handler(binder, event);
}
else {
let checked;
const bounds = binder.binder.ownerBinders.get(binder.owner);
if (bounds) {
for (const bound of bounds) {
if (bound.name === 'checked') {
checked = bound;
break;
}
}
}
if (checked) {
radio.dispatchEvent(input);
}
else {
radio.checked = !event.target.checked;
if (radio.checked) {
radio.setAttribute('checked', '');
}
else {
radio.removeAttribute('checked');
}
}
}
}
}));
}
else {
binder.owner.addEventListener('input', event => handler(binder, event));
}
}
yield handler(binder);
});
};
const checkedUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
binder.owner.removeAttribute('checked');
});
};
var checked = { render: checkedRender, unrender: checkedUnrender };
const inheritRender = function (binder) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if (!binder.meta.setup) {
binder.meta.setup = true;
binder.node.value = '';
}
if (!binder.owner.inherited) {
return console.warn(`inherited not implemented ${binder.owner.localName}`);
}
const inherited = yield binder.compute();
(_b = (_a = binder.owner).inherited) === null || _b === void 0 ? void 0 : _b.call(_a, inherited);
});
};
const inheritUnrender = function (binder) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if (!binder.owner.inherited) {
return console.warn(`inherited not implemented ${binder.owner.localName}`);
}
(_b = (_a = binder.owner).inherited) === null || _b === void 0 ? void 0 : _b.call(_a);
});
};
var inherit = { render: inheritRender, unrender: inheritUnrender };
var dateTypes = ['date', 'datetime-local', 'month', 'time', 'week'];
console.warn('value: setter/getter issue with multiselect');
const defaultInputEvent = new Event('input');
const parseable = function (value) {
return !isNaN(value) && value !== null && value !== undefined && typeof value !== 'string';
};
const stampFromView = function (data) {
const date = new Date(data);
return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds()).getTime();
};
const stampToView = function (data) {
const date = new Date(data);
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())).getTime();
};
const input = function (binder, event) {
return __awaiter(this, void 0, void 0, function* () {
const { owner } = binder;
const { type } = owner;
let display, computed;
if (type === 'select-one') {
const [option] = owner.selectedOptions;
const value = option ? '$value' in option ? option.$value : option.value : undefined;
computed = yield binder.compute({ $event: event, $value: value, $assignment: true });
display = format(computed);
}
else if (type === 'select-multiple') {
const value = [];
for (const option of owner.selectedOptions) {
value.push('$value' in option ? option.$value : option.value);
}
computed = yield binder.compute({ $event: event, $value: value, $assignment: true });
display = format(computed);
}
else if (type === 'number' || type === 'range') {
computed = yield binder.compute({ $event: event, $value: owner.valueAsNumber, $assignment: true });
// if (typeof computed === 'number' && computed !== Infinity) owner.valueAsNumber = computed;
// else owner.value = computed;
owner.value = computed;
display = owner.value;
}
else if (dateTypes.includes(type)) {
const value = typeof owner.$value === 'string' ? owner.value : stampFromView(owner.valueAsNumber);
computed = yield binder.compute({ $event: event, $value: value, $assignment: true });
if (typeof owner.$value === 'string')
owner.value = computed;
else
owner.valueAsNumber = stampToView(computed);
display = owner.value;
}
else {
const value = '$value' in owner && parseable(owner.$value) ? JSON.parse(owner.value) : owner.value;
const checked = '$value' in owner && parseable(owner.$value) ? JSON.parse(owner.checked) : owner.checked;
computed = yield binder.compute({ $event: event, $value: value, $checked: checked, $assignment: true });
display = format(computed);
owner.value = display;
}
owner.$value = computed;
if (type === 'checked' || type === 'radio')
owner.$checked = computed;
owner.setAttribute('value', display);
});
};
const valueRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
const { owner, meta } = binder;
if (!meta.setup) {
meta.setup = true;
owner.addEventListener('input', event => input(binder, event));
}
const computed = yield binder.compute();
let display;
if (binder.owner.type === 'select-one') {
owner.value = undefined;
for (const option of owner.options) {
const optionValue = '$value' in option ? option.$value : option.value;
if (option.selected = optionValue === computed)
break;
}
if (computed === undefined && owner.options.length && !owner.selectedOptions.length) {
const [option] = owner.options;
option.selected = true;
return owner.dispatchEvent(defaultInputEvent);
}
display = format(computed);
owner.value = display;
}
else if (binder.owner.type === 'select-multiple') {
for (const option of owner.options) {
const optionValue = '$value' in option ? option.$value : option.value;
option.selected = computed === null || computed === void 0 ? void 0 : computed.includes(optionValue);
}
display = format(computed);
}
else if (binder.owner.type === 'number' || binder.owner.type === 'range') {
if (typeof computed === 'number' && computed !== Infinity)
owner.valueAsNumber = computed;
else
owner.value = computed;
display = owner.value;
}
else if (dateTypes.includes(binder.owner.type)) {
if (typeof computed === 'string')
owner.value = computed;
else
owner.valueAsNumber = stampToView(computed);
display = owner.value;
}
else {
display = format(computed);
owner.value = display;
}
owner.$value = computed;
if (binder.owner.type === 'checked' || binder.owner.type === 'radio')
owner.$checked = computed;
owner.setAttribute('value', display);
});
};
const valueUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
if (binder.owner.type === 'select-one' || binder.owner.type === 'select-multiple') {
for (const option of binder.owner.options) {
option.selected = false;
}
}
binder.owner.value = undefined;
binder.owner.$value = undefined;
if (binder.owner.type === 'checked' || binder.owner.type === 'radio')
binder.owner.$checked = undefined;
binder.owner.setAttribute('value', '');
});
};
var value = { render: valueRender, unrender: valueUnrender };
const space = /\s+/;
const prepare = /{{\s*(.*?)\s+(of|in)\s+(.*?)\s*}}/;
// const nextFrame = async function () {
// return new Promise((resolve: any) =>
// window.requestAnimationFrame(() =>
// window.requestAnimationFrame(() => resolve())
// )
// );
// };
const wait = function () {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => setTimeout(() => resolve(), 0));
});
};
const eachHas = function (binder, indexValue, keyValue, target, key) {
return key === binder.meta.variableName ||
key === binder.meta.indexName ||
key === binder.meta.keyName ||
key in target;
};
const eachGet = function (binder, indexValue, keyValue, target, key) {
if (key === binder.meta.variableName) {
let result = binder.context;
for (const part of binder.meta.parts) {
result = result[part];
if (!result)
return;
}
return typeof result === 'object' ? result[keyValue] : undefined;
}
else if (key === binder.meta.indexName) {
return indexValue;
}
else if (key === binder.meta.keyName) {
return keyValue;
}
else {
return binder.context[key];
}
};
const eachSet = function (binder, indexValue, keyValue, target, key, value) {
if (key === binder.meta.variableName) {
let result = binder.context;
for (const part of binder.meta.parts) {
result = result[part];
if (!result)
return true;
}
typeof result === 'object' ? result[keyValue] = value : undefined;
}
else if (key === binder.meta.indexName || key === binder.meta.keyName) {
return true;
}
else {
binder.context[key] = value;
}
return true;
};
const eachUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
binder.meta.tasks = [];
binder.meta.targetLength = 0;
binder.meta.currentLength = 0;
return Promise.all([
(() => __awaiter(this, void 0, void 0, function* () {
let node;
while (node = binder.owner.lastChild)
binder.binder.remove(binder.owner.removeChild(node));
}))(),
(() => __awaiter(this, void 0, void 0, function* () {
let node;
while (node = binder.meta.queueElement.content.lastChild)
binder.meta.queueElement.content.removeChild(node);
}))()
]);
});
};
const eachRender = function (binder) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
if (!binder.meta.setup) {
binder.node.value = '';
const [path, variable, index, key] = binder.value.replace(prepare, '$1,$3').split(/\s*,\s*/).reverse();
binder.meta.path = path;
binder.meta.keyName = key;
binder.meta.indexName = index;
binder.meta.parts = path.split('.');
binder.meta.variableName = variable;
binder.meta.variableNamePattern = new RegExp(`(^|[^.a-zA-Z0-9$_])(${variable})\\b`);
// binder.meta.variableNamePattern = new RegExp(`^${variable}\\b`);
// binder.meta.variableNamePattern = new RegExp(`([^.a-zA-Z0-9$_\\[\\]])(${variable})\\b`);
binder.meta.keys = [];
binder.meta.tasks = [];
binder.meta.setup = true;
binder.meta.targetLength = 0;
binder.meta.currentLength = 0;
binder.meta.templateLength = 0;
binder.meta.queueElement = document.createElement('template');
binder.meta.templateElement = document.createElement('template');
let node = binder.owner.firstChild;
while (node) {
if (space.test(node.nodeValue)) {
binder.owner.removeChild(node);
}
else {
binder.meta.templateLength++;
binder.meta.templateElement.content.appendChild(node);
}
node = binder.owner.firstChild;
}
}
const data = yield binder.compute();
if ((data === null || data === void 0 ? void 0 : data.constructor) === Array) {
binder.meta.targetLength = data.length;
}
else {
binder.meta.keys = Object.keys(data || {});
binder.meta.targetLength = binder.meta.keys.length;
}
if (binder.meta.currentLength > binder.meta.targetLength) {
while (binder.meta.currentLength > binder.meta.targetLength) {
let count = binder.meta.templateLength;
while (count--) {
const node = binder.owner.lastChild;
binder.owner.removeChild(node);
binder.meta.tasks.push(binder.binder.remove(node));
}
binder.meta.currentLength--;
}
}
else if (binder.meta.currentLength < binder.meta.targetLength) {
while (binder.meta.currentLength < binder.meta.targetLength) {
const indexValue = binder.meta.currentLength;
const keyValue = (_a = binder.meta.keys[binder.meta.currentLength]) !== null && _a !== void 0 ? _a : binder.meta.currentLength;
const variableValue = `${binder.meta.path}.${(_b = binder.meta.keys[binder.meta.currentLength]) !== null && _b !== void 0 ? _b : binder.meta.currentLength}`;
const context = new Proxy(binder.context, {
has: eachHas.bind(null, binder, indexValue, keyValue),
get: eachGet.bind(null, binder, indexValue, keyValue),
set: eachSet.bind(null, binder, indexValue, keyValue),
});
const rewrites = ((_c = binder.rewrites) === null || _c === void 0 ? void 0 : _c.slice()) || [];
if (binder.meta.keyName)
rewrites.unshift([binder.meta.keyName, keyValue]);
// if (binder.meta.indexName) rewrites.unshift([ binder.meta.indexName, indexValue ]);
// if (binder.meta.variableName) rewrites.unshift([ binder.meta.variableName, variableValue ]);
if (binder.meta.variableName)
rewrites.unshift([binder.meta.variableNamePattern, variableValue]);
const clone = binder.meta.templateElement.content.cloneNode(true);
let node = clone.firstChild;
if (node) {
do {
binder.meta.tasks.push(binder.binder.add(node, binder.container, context, rewrites));
} while (node = node.nextSibling);
}
binder.meta.queueElement.content.appendChild(clone);
// var d = document.createElement('div');
// d.classList.add('box');
// var t = document.createTextNode('{{item.number}}');
// binder.meta.tasks.push(binder.binder.add(t, binder.container, context, rewrites));
// d.appendChild(t);
// binder.meta.queueElement.content.appendChild(d);
binder.meta.currentLength++;
}
}
if (binder.meta.currentLength === binder.meta.targetLength) {
yield Promise.all(binder.meta.tasks.splice(0, binder.meta.length - 1));
binder.owner.appendChild(binder.meta.queueElement.content);
yield wait();
}
if (binder.owner.nodeName === 'SELECT') {
(_d = binder.binder.nodeBinders.get(binder.owner.attributes['value'])) === null || _d === void 0 ? void 0 : _d.render();
}
});
};
var each = { render: eachRender, unrender: eachUnrender };
const htmlRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
const tasks = [];
let data = yield binder.compute();
if (typeof data !== 'string') {
data = '';
console.warn('html binder requires a string');
}
let removeChild;
while (removeChild = binder.owner.lastChild) {
binder.owner.removeChild(removeChild);
tasks.push(binder.binder.remove(removeChild));
}
const template = document.createElement('template');
template.innerHTML = data;
let addChild = template.content.firstChild;
while (addChild) {
tasks.push(binder.binder.add.bind(binder.binder, addChild, binder.container));
addChild = addChild.nextSibling;
}
yield Promise.all(tasks);
binder.owner.appendChild(template.content);
});
};
const htmlUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
const tasks = [];
let node;
while (node = binder.owner.lastChild) {
tasks.push(binder.binder.remove(node));
binder.owner.removeChild(node);
}
yield Promise.all(tasks);
});
};
var html = { render: htmlRender, unrender: htmlUnrender };
const textRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
let data = yield binder.compute();
binder.owner.textContent = format(data);
});
};
const textUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
binder.owner.textContent = '';
});
};
var text = { render: textRender, unrender: textUnrender };
const Value = function (element) {
if (!element)
return undefined;
else if ('$value' in element)
return element.$value ? JSON.parse(JSON.stringify(element.$value)) : element.$value;
else if (element.type === 'number' || element.type === 'range')
return element.valueAsNumber;
else
return element.value;
};
const submit = function (event, binder) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
event.preventDefault();
const form = {};
const target = event.target;
// const elements = target?.elements || target?.form?.elements;
const elements = (_a = ((target === null || target === void 0 ? void 0 : target.form) || target)) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[name]');
for (const element of elements) {
const { type, name, checked, hidden } = element;
if (!name)
continue;
if (hidden)
continue;
if (type === 'radio' && !checked)
continue;
if (type === 'submit' || type === 'button')
continue;
let value;
if (type === 'select-multiple') {
value = [];
for (const option of element.selectedOptions) {
value.push(Value(option));
}
}
else if (type === 'select-one') {
const [option] = element.selectedOptions;
value = Value(option);
}
else {
value = Value(element);
}
let data = form;
name.split(/\s*\.\s*/).forEach((part, index, parts) => {
const next = parts[index + 1];
if (next) {
if (!data[part]) {
data[part] = /[0-9]+/.test(next) ? [] : {};
}
data = data[part];
}
else {
data[part] = value;
}
});
}
yield binder.compute({ $form: form, $event: event });
if (target.getAttribute('reset'))
target.reset();
return false;
});
};
const reset = function (event, binder) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
event.preventDefault();
const target = event.target;
// const elements = target?.elements || target?.form?.elements;
const elements = (_a = ((target === null || target === void 0 ? void 0 : target.form) || target)) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[name]');
for (const element of elements) {
const { type, name, checked, hidden, nodeName } = element;
if (!name)
continue;
if (hidden)
continue;
if (type === 'radio' && !checked)
continue;
if (type === 'submit' || type === 'button')
continue;
if (type === 'select-one') {
element.selectedIndex = 0;
}
else if (type === 'select-multiple') {
element.selectedIndex = -1;
}
else if (type === 'radio' || type === 'checkbox') {
element.checked = false;
}
else {
element.value = undefined;
}
element.dispatchEvent(new Event('input'));
}
yield binder.compute({ $event: event });
return false;
});
};
const onRender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
binder.owner[binder.name] = null;
const name = binder.name.slice(2);
if (!binder.meta.setup) {
binder.meta.setup = true;
binder.node.value = '';
}
if (binder.meta.method) {
binder.owner.removeEventListener(name, binder.meta.method);
}
binder.meta.method = event => {
if (name === 'reset') {
return reset(event, binder);
}
else if (name === 'submit') {
return submit(event, binder);
}
else {
return binder.compute({ $event: event });
}
};
binder.owner.addEventListener(name, binder.meta.method);
});
};
const onUnrender = function (binder) {
return __awaiter(this, void 0, void 0, function* () {
binder.owner[binder.name] = null;
const name = binder.name.slice(2);
if (binder.meta.method) {
binder.owner.removeEventListener(name, binder.meta.method);
}
});
};
var on = { render: onRender, unrender: onUnrender };
const caches = new Map();
const splitPattern = /\s*{{\s*|\s*}}\s*/;
const instancePattern = /(\$\w+)/;
const bracketPattern = /({{)|(}})/;
const eachPattern = /({{.*?\s+(of|in)\s+(.*?)}})/;
const assignmentPattern = /({{(.*?)([_$a-zA-Z0-9.?\[\]]+)([-+?^*%|\\ ]*=[-+?^*%|\\ ]*)([^<>=].*?)}})/;
const codePattern = new RegExp(`${eachPattern.source}|${assignmentPattern.source}|${instancePattern.source}|${bracketPattern.source}`, 'g');
const ignores = [
// '$assignee', '$instance', '$binder', '$event', '$value', '$checked', '$form', '$e', '$v', '$c', '$f',
// '$e', '$v', '$c', '$f',
'$instance', '$event', '$value', '$checked', '$form',
'this', 'window', 'document', 'console', 'location',
'globalThis', 'Infinity', 'NaN', 'undefined',
'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent ',
'Error', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', 'AggregateError',
'Object', 'Function', 'Boolean', 'Symbole', 'Array',
'Number', 'Math', 'Date', 'BigInt',
'String', 'RegExp',
'Array', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array',
'Int32Array', 'Uint32Array', 'BigInt64Array', 'BigUint64Array', 'Float32Array', 'Float64Array',
'Map', 'Set', 'WeakMap', 'WeakSet',
'ArrayBuffer', 'SharedArrayBuffer', 'DataView', 'Atomics', 'JSON',
'Promise', 'GeneratorFunction', 'AsyncGeneratorFunction', 'Generator', 'AsyncGenerator', 'AsyncFunction',
'Reflect', 'Proxy',
];
const has = function (target, key) {
return ignores.includes(key) ? false : key in target;
};
const computer = function (binder) {
let cache = caches.get(binder.value);
if (!cache) {
let code = binder.value;
const convert = code.split(splitPattern).filter(part => part).length > 1;
const isChecked = binder.node.name === 'checked';
const isValue = binder.node.name === 'value';
let reference = '';
let assignment = '';
let usesInstance = false;
// let hasEvent, hasForm, hasValue, hasChecked;
code = code.replace(codePattern, function (match, g1, g2, ofInRight, assignee, assigneeLeft, ref, assigneeMiddle, assigneeRight, instance, bracketLeft, bracketRight) {
if (bracketLeft)
return convert ? `' + (` : '(';
if (bracketRight)
return convert ? `) + '` : ')';
if (ofInRight)
return `(${ofInRight})`;
if (instance) {
usesInstance = true;
return match;
}
if (assignee) {
if (isValue || isChecked) {
reference = ref;
usesInstance = true;
assignment = assigneeLeft + assigneeRight;
return (convert ? `' + (` : '(') + assigneeLeft + ref + assigneeMiddle + assigneeRight + (convert ? `) + '` : ')');
}
else {
return (convert ? `' + (` : '(') + assigneeLeft + ref + assigneeMiddle + assigneeRight + (convert ? `) + '` : ')');
}
}
});
code = convert ? `'${code}'` : code;
if (usesInstance) {
code = `
$instance = $instance || {};
with ($instance) {
with ($context) {
if ($instance.$assignment) {
return ${code};
} else {
${isValue ? `$instance.$value = ${reference || `undefined`};` : ''}
${isChecked ? `$instance.$checked = ${reference || `undefined`};` : ''}
return ${assignment || code};
}
}
}
`;
}
else {
code = `with ($context) { return ${code}; }`;
}
code = `
try {
${code}
} catch (error){
console.error(error);
}
`;
cache = new Function('$context', '$binder', '$instance', code);
caches.set(binder.value, cache);
}
return cache.bind(null, new Proxy(binder.context, { has }), binder);
// return cache.bind(null, binder.context, binder);
};
const normalizeReference = /\s*(\??\.|\[\s*([0-9]+)\s*\])\s*/g;
const referenceMatch = new RegExp([
'(".*?[^\\\\]*"|\'.*?[^\\\\]*\'|`.*?[^\\\\]*`)',
'([^{}]*{{.*?\\s+(?:of|in)\\s+)',
'((?:^|}}).*?{{)',
'(}}.*?(?:{{|$))',
`(
(?:\\$assignee|\\$instance|\\$binder|\\$event|\\$value|\\$checked|\\$form|\\$e|\\$v|\\$c|\\$f|
this|window|document|console|location|
globalThis|Infinity|NaN|undefined|
isFinite|isNaN|parseFloat|parseInt|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|
Error|EvalError|RangeError|ReferenceError|SyntaxError|TypeError|URIError|AggregateError|
Object|Function|Boolean|Symbole|Array|
Number|Math|Date|BigInt|
String|RegExp|
Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|
Int32Array|Uint32Array|BigInt64Array|BigUint64Array|Float32Array|Float64Array|
Map|Set|WeakMap|WeakSet|
ArrayBuffer|SharedArrayBuffer|DataView|Atomics|JSON|
Promise|GeneratorFunction|AsyncGeneratorFunction|Generator|AsyncGenerator|AsyncFunction|
Reflect|Proxy|
true|false|null|undefined|NaN|of|in|do|if|for|new|try|case|else|with|await|break|catch|class|super|throw|while|
yield|delete|export|import|return|switch|default|extends|finally|continue|debugger|function|arguments|typeof|instanceof|void)
(?:[.][a-zA-Z0-9$_.? ]*)?\\b
)`,
'(\\b[a-zA-Z$_][a-zA-Z0-9$_.? ]*\\b)' // reference
].join('|').replace(/\s|\t|\n/g, ''), 'g');
const cache = new Map();
const parser = function (data, rewrites) {
data = data.replace(normalizeReference, '.$2');
if (rewrites) {
for (const [name, value] of rewrites) {
data = data.replace(name, `$1${value}`);
}
}
const cached = cache.get(data);
if (cached)
return cached;
const references = [];
cache.set(data, references);
let match;
while (match = referenceMatch.exec(data)) {
let reference = match[6];
if (reference) {
references.push(reference);
}
}
// console.log(data, references);
return references;
};
const TN = Node.TEXT_NODE;
const EN = Node.ELEMENT_NODE;
// const AN = Node.ATTRIBUTE_NODE;
class Binder {
constructor() {
this.prefix = 'o-';
this.prefixEach = 'o-each';
this.prefixValue = 'o-value';
this.syntaxEnd = '}}';
this.syntaxStart = '{{';
this.syntaxLength = 2;
this.syntaxMatch = new RegExp('{{.*?}}');
this.prefixReplace = new RegExp('^o-');
this.syntaxReplace = new RegExp('{{|}}', 'g');
this.nodeBinders = new Map();
this.ownerBinders = new Map();
this.pathBinders = new Map();
this.binders = {
standard,
checked,
inherit,
value,
each,
html,
text,
on,
};
}
get(data) {
if (typeof data === 'string') {
return this.pathBinders.get(data);
}
else {
return this.nodeBinders.get(data);
}
}
unbind(node) {
return __awaiter(this, void 0, void 0, function* () {
const ownerBinders = this.ownerBinders.get(node);
if (!ownerBinders)
return;
for (const ownerBinder of ownerBinders) {
this.nodeBinders.delete(ownerBinder.node);
for (const path of ownerBinder.paths) {
const pathBinders = this.pathBinders.get(path);
if (!pathBinders)
continue;
pathBinders.delete(ownerBinder);
if (!pathBinders.size)
this.pathBinders.delete(path);
}
}
this.nodeBinders.delete(node);
this.ownerBinders.delete(node);
});
}
bind(node, container, name, value, owner, context, rewrites) {
return __awaiter(this, void 0, void 0, function* () {
const type = name.startsWith('on') ? 'on' : name in this.binders ? name : 'standard';
const handler = this.binders[type];
const binder = {
meta: {},
ready: true,
binder: this,
paths: undefined,
render: undefined,
compute: undefined,
unrender: undefined,
binders: this.pathBinders,
node, owner, name, value, rewrites, context, container, type,
};
const [paths, compute] = yield Promise.all([
parser(value, rewrites),
computer(binder)
]);
binder.paths = paths;
binder.compute = compute;
binder.render = handler.render.bind(null, binder);
binder.unrender = handler.unrender.bind(null, binder);
for (const reference of paths) {
const binders = binder.binders.get(reference);
if (binders) {
binders.add(binder);
}
else {
binder.binders.set(reference, new Set([binder]));
}
}
this.nodeBinders.set(node, binder);
const ownerBinders = this.ownerBinders.get(binder.owner);
if (ownerBinders) {
ownerBinders.add(binder);
}
else {
this.ownerBinders.set(binder.owner, new Set([binder]));
}
return binder.render();
});
}
;
remove(node) {
return __awaiter(this, void 0, void 0, function* () {
const tasks = [];
// if (node.nodeType === AN) {
// tasks.push(this.unbind(node));
if (node.nodeType === TN) {
this.unbind(node);
}
else if (node.nodeType === EN) {
this.unbind(node);
const attributes = node.attributes;
for (const attribute of attributes) {
tasks.push(this.unbind(attribute));
}
let child = node.firstChild;
while (child) {
// this.remove(child);
tasks.push(this.remove(child));
child = child.nextSibling;
}
}
return Promise.all(tasks);
});
}
add(node, container, context, rewrites) {
return __awaiter(this, void 0, void 0, function* () {
// if (node.nodeType === AN) {
// const attribute = (node as Attr);
// if (this.syntaxMatch.test(attribute.value)) {
// tasks.push(this.bind(node, container, attribute.name, attribute.value, attribute.ownerElement, context, rewrites));
// }
// } else
if (node.nodeType === TN) {
const tasks = [];
const start = node.nodeValue.indexOf(this.syntaxStart);
if (start === -1)
return;
if (start !== 0)
node = node.splitText(start);
const end = node.nodeValue.indexOf(this.syntaxEnd);
if (end === -1)
return;
if (end + this.syntaxLength !== node.nodeValue.length) {
const split = node.splitText(end + this.syntaxLength);
tasks.push(this.add(split, container, context, rewrites));
}
tasks.push(this.bind(node, container, 'text', node.nodeValue, node, context, rewrites));
return Promise.all(tasks);
}
else if (node.nodeType === EN) {
const attributes = node.attributes;
const inherit = attributes['inherit'];
if (inherit) {
// await window.customElements.whenDefined((node as any).localName);
// await (node as any).whenReady();
if (!node.ready) {
yield new Promise((resolve) => node.addEventListener('ready', resolve));
}
yield this.bind(inherit, container, inherit.name, inherit.value, inherit.ownerElement, context, rewrites);
}
const each = attributes['each'];
if (each)
yield this.bind(each, container, each.name, each.value, each.ownerElement, context, rewrites);
if (!each && !inherit) {
let child = node.firstChild;
if (child) {
const tasks = [];
do {
tasks.push(this.add(child, container, context, rewrites));
} while (child = child.nextSibling);
if (tasks.length)
yield Promise.all(tasks);
}
}
if (attributes.length) {
const tasks = [];
for (const attribute of attributes) {
if (attribute.name !== 'each' && attribute.name !== 'inherit' && this.syntaxMatch.test(attribute.value)) {
tasks.push(this.bind(attribute, container, attribute.name, attribute.value, attribute.ownerElement, context, rewrites));
}
}
if (tasks.length)
yield Promise.all(tasks);
}
}
});
}
}
var _Css_data, _Css_style, _Css_support, _a$1;
var Css = new (_a$1 = class Css {
constructor() {
_Css_data.set(this, new Map());
_Css_style.set(this, document.createElement('style'));
_Css_support.set(this, !window.CSS || !window.CSS.supports || !window.CSS.supports('(--t: