crs-binding
Advanced tools
Comparing version 0.0.68 to 0.0.69
@@ -1,64 +0,1 @@ | ||
class BindableElement extends HTMLElement { | ||
constructor() { | ||
super(); | ||
crsbinding.events.enableEvents(this); | ||
crsbinding.dom.enableEvents(this); | ||
} | ||
dispose() { | ||
crsbinding.events.disableEvents(this); | ||
crsbinding.dom.disableEvents(this); | ||
} | ||
async connectedCallback() { | ||
if (this.html != null) { | ||
this.innerHTML = await fetch(this.html).then(result => result.text()); | ||
crsbinding.parsers.parseElements(this.children, this); | ||
crsbinding.expression.updateUI(this); | ||
} | ||
this.dispatchEvent(new CustomEvent("ready")); | ||
} | ||
async disconnectedCallback() { | ||
this.dispose(); | ||
if (this.observer != null) { | ||
this.observer.disconnect(); | ||
this.attributesChangedHandler = null; | ||
this.observer = null; | ||
} | ||
crsbinding.observation.releaseBinding(this); | ||
} | ||
getProperty(prop) { | ||
let result = this[`_${prop}`]; | ||
if (result == null && this.getAttribute != null) { | ||
result = this.getAttribute(prop); | ||
} | ||
return result; | ||
} | ||
setProperty(prop, value) { | ||
this[`_${prop}`] = value; | ||
crsbinding.events.notifyPropertyChanged(this, prop); | ||
} | ||
observeAttributes(attributes) { | ||
this.attributesChangedHandler = this.attributesChanged.bind(this); | ||
this.observer = new MutationObserver(this.attributesChangedHandler); | ||
this.observer.observe(this, {attributes: true, attributeFilter: attributes, attributeOldValue: true}); | ||
} | ||
attributesChanged(mutationsList) { | ||
for(let mutation of mutationsList) { | ||
const attr = `${mutation.attributeName}AttributeChanged`; | ||
if (this[attr] != null) { | ||
this[attr](mutation.target[mutation.attributeName], mutation.oldValue); | ||
} | ||
} | ||
} | ||
} | ||
export { BindableElement }; | ||
class t extends HTMLElement{constructor(){super(),crsbinding.events.enableEvents(this),crsbinding.dom.enableEvents(this)}dispose(){crsbinding.events.disableEvents(this),crsbinding.dom.disableEvents(this)}async connectedCallback(){null!=this.html&&(this.innerHTML=await fetch(this.html).then(t=>t.text()),crsbinding.parsers.parseElements(this.children,this),crsbinding.expression.updateUI(this)),this.dispatchEvent(new CustomEvent("ready"))}async disconnectedCallback(){this.dispose(),null!=this.observer&&(this.observer.disconnect(),this.attributesChangedHandler=null,this.observer=null),crsbinding.observation.releaseBinding(this)}getProperty(t){let e=this[`_${t}`];return null==e&&null!=this.getAttribute&&(e=this.getAttribute(t)),e}setProperty(t,e){this[`_${t}`]=e,crsbinding.events.notifyPropertyChanged(this,t)}observeAttributes(t){this.attributesChangedHandler=this.attributesChanged.bind(this),this.observer=new MutationObserver(this.attributesChangedHandler),this.observer.observe(this,{attributes:!0,attributeFilter:t,attributeOldValue:!0})}attributesChanged(t){for(let e of t){const t=`${e.attributeName}AttributeChanged`;null!=this[t]&&this[t](e.target[e.attributeName],e.oldValue)}}}export{t as BindableElement}; |
1617
crs-binding.js
@@ -1,1616 +0,1 @@ | ||
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; | ||
function compileExp(exp, parameters, options) { | ||
parameters = parameters || []; | ||
let sanitize = true; | ||
let async = false; | ||
let ctxName = "context"; | ||
if (options != null) { | ||
if (options.sanitize != null) sanitize = options.sanitize; | ||
if (options.async != null) async = options.async; | ||
if (options.ctxName != null) ctxName = options.ctxName; | ||
} | ||
if (crsbinding._expFn.has(exp)) { | ||
const x = crsbinding._expFn.get(exp); | ||
x.count += 1; | ||
return x; | ||
} | ||
let src = exp; | ||
let san; | ||
if (sanitize == true) { | ||
san = crsbinding.expression.sanitize(exp, ctxName); | ||
if (crsbinding._expFn.has(san.expression)) { | ||
const x = crsbinding._expFn.get(san.expression); | ||
x.count += 1; | ||
return x; | ||
} | ||
src = san.isLiteral === true ? ["return `", san.expression, "`"].join("") : `return ${san.expression}`; | ||
} | ||
else { | ||
san = { | ||
expression: exp | ||
}; | ||
} | ||
const fn = async == true ? new AsyncFunction(ctxName, ...parameters, src) : new Function(ctxName, ...parameters, src); | ||
const result = { | ||
function: fn, | ||
parameters: san, | ||
count: 1 | ||
}; | ||
crsbinding._expFn.set(san.expression, result); | ||
return result; | ||
} | ||
function releaseExp(exp) { | ||
if (exp == null || typeof exp != "object") return; | ||
const key = exp.parameters.expression; | ||
if (crsbinding._expFn.has(key)) { | ||
const x = crsbinding._expFn.get(key); | ||
x.count -= 1; | ||
if (x.count == 0) { | ||
x.function = null; | ||
x.parameters = null; | ||
crsbinding._expFn.delete(key); | ||
} | ||
} | ||
} | ||
function enableEvents(obj) { | ||
obj.__events = new Map(); | ||
obj.__conditions = new Map(); | ||
} | ||
function disableEvents(obj) { | ||
if (obj.__events != null) { | ||
obj.__events.forEach((ev) => { | ||
ev.length = 0; | ||
}); | ||
obj.__events.clear(); | ||
delete obj.__events; | ||
} | ||
if (obj.__conditions) { | ||
obj.__conditions.forEach((cnd) => { | ||
delete cnd.fn; | ||
delete cnd.properties; | ||
}); | ||
obj.__conditions.clear(); | ||
delete obj.__conditions; | ||
} | ||
} | ||
function when(obj, exp, callback) { | ||
let functions = obj.__events.get(exp) || []; | ||
functions = [...functions, callback]; | ||
obj.__events.set(exp, functions); | ||
const cmp = compileExp(exp); | ||
let cond = obj.__conditions.get(exp); | ||
if (cond == null) { | ||
const fn = () => { | ||
if (cmp.function(obj) == true) { | ||
for (let call of functions) { | ||
call(); | ||
} | ||
} | ||
}; | ||
cond = {fn: fn, properties: cmp.parameters.properties.slice(0)}; | ||
obj.__conditions.set(exp, cond); | ||
} | ||
const properties = cmp.parameters.properties; | ||
for (let property of properties) { | ||
crsbinding.events.on(obj, property, cond.fn); | ||
} | ||
} | ||
function removeWhen(obj, exp, callback) { | ||
crsbinding.events.removeOn(obj, exp, callback); | ||
const cnd = obj.__conditions.get(exp); | ||
for (let property of cnd.properties) { | ||
crsbinding.events.removeOn(obj, property, cnd.fn); | ||
} | ||
delete cnd.fn; | ||
delete cnd.properties; | ||
obj.__conditions.delete(exp); | ||
} | ||
function on(obj, property, callback) { | ||
if (obj == null || obj.__events == null) return; | ||
let functions = obj.__events.get(property) || []; | ||
functions = [...functions, callback]; | ||
obj.__events.set(property, functions); | ||
} | ||
function removeOn(obj, property, callback) { | ||
if (property.indexOf(".") != -1) { | ||
return removeOnPath(obj, property, callback); | ||
} | ||
if (obj == null || obj.__events == null) return; | ||
const functions = obj.__events.get(property) || []; | ||
const index = functions.indexOf(callback); | ||
if (index != -1) { | ||
functions.splice(index, 1); | ||
obj.__events.set(property, functions); | ||
} | ||
if (functions.length == 0) { | ||
obj.__events.delete(property); | ||
} | ||
} | ||
function removeOnPath(obj, property, callback) { | ||
const parts = property.split("."); | ||
for (let part of parts) { | ||
removeOn(obj, part, callback); | ||
obj = obj[part]; | ||
} | ||
} | ||
function notifyPropertyChanged(obj, property, args) { | ||
if (obj.__events == null || obj.__events.has(property) == false) return; | ||
const functions = obj.__events.get(property); | ||
for(let fn of functions) { | ||
fn(property, obj[property], args); | ||
} | ||
const changedFnName = `${property}Changed`; | ||
if (obj[changedFnName] != null) { | ||
obj[changedFnName].call(obj, args); | ||
} | ||
} | ||
const ISARRAY = "__isArray"; | ||
function observeArray(collection) { | ||
collection[ISARRAY] = true; | ||
if (collection._events == null) { | ||
crsbinding.events.enableEvents(collection); | ||
} | ||
collection.__nextId = 1; | ||
for (let i = 0; i < collection.length; i++) { | ||
observeIndex(collection, i); | ||
} | ||
const proxy = new Proxy(collection, { | ||
get: get | ||
}); | ||
return proxy; | ||
} | ||
function releaseObservedArray(collection) { | ||
crsbinding.events.disableEvents(collection); | ||
collection.forEach(item => crsbinding.observation.releaseObserved(item)); | ||
} | ||
const deleteFunctions = ["pop", "splice"]; | ||
const addFunctions = ["push"]; | ||
function get(collection, prop) { | ||
const value = collection[prop]; | ||
if (typeof value == "function") { | ||
return (...args) => { | ||
const result = collection[prop](...args); | ||
if (deleteFunctions.indexOf(prop) != -1) { | ||
itemsRemoved(collection, result); | ||
if (prop == "splice" && args.length > 2) { | ||
args = args.splice(2, args.length); | ||
itemsAdded(collection, args); | ||
} | ||
} | ||
else if (addFunctions.indexOf(prop) != -1) { | ||
itemsAdded(collection, args); | ||
} | ||
return result; | ||
} | ||
} | ||
return value; | ||
} | ||
function itemsRemoved(collection, items) { | ||
if (items == null) return; | ||
crsbinding.events.notifyPropertyChanged(collection, "items-deleted", items); | ||
if (Array.isArray(items)) { | ||
for (let item of items) { | ||
crsbinding.observation.releaseObserved(item); | ||
} | ||
} | ||
else { | ||
crsbinding.observation.releaseObserved(items); | ||
} | ||
} | ||
function itemsAdded(obj, items) { | ||
if (items == null) return; | ||
const payload = { | ||
items: [], | ||
indexes: [] | ||
}; | ||
for (let item of items) { | ||
const index = obj.indexOf(item); | ||
observeIndex(obj, index); | ||
payload.items.push(item); | ||
payload.indexes.push(index); | ||
} | ||
crsbinding.events.notifyPropertyChanged(obj, "items-added", payload); | ||
} | ||
function observeIndex(collection, index) { | ||
const item = collection[index]; | ||
item.__uid = collection.__nextId; | ||
collection.__nextId++; | ||
if (item.__isProxy != true) { | ||
collection[index] = crsbinding.observation.observe(item); | ||
} | ||
} | ||
const PROXY = "__isProxy"; | ||
const BACKUP = "__backup"; | ||
function observe(obj, prior) { | ||
obj[PROXY] = true; | ||
crsbinding.events.enableEvents(obj); | ||
if (Array.isArray(obj)) return observeArray(obj); | ||
obj[BACKUP] = {}; | ||
if (prior != null) { | ||
obj.__events = prior.__events; | ||
delete prior.__events; | ||
} | ||
const keys = Object.keys(obj); | ||
for (let key of keys) { | ||
if (Array.isArray(obj[key])) { | ||
obj[key] = observeArray(obj[key]); | ||
} | ||
} | ||
const proxy = new Proxy(obj, { | ||
get: get$1, | ||
set: set | ||
}); | ||
return proxy; | ||
} | ||
function releaseObserved(obj) { | ||
if (obj.__isArray == true) return releaseObservedArray(obj); | ||
crsbinding.events.disableEvents(obj); | ||
const keys = Object.keys(obj); | ||
for (let key of keys) { | ||
if (Array.isArray(obj[key])) { | ||
releaseObservedArray(obj[key]); | ||
} | ||
} | ||
if (obj.dispose != null) { | ||
obj._disposing = true; | ||
obj.dispose(); | ||
} | ||
const properties = Object.getOwnPropertyNames(obj); | ||
for (let prop of properties) { | ||
if (prop.indexOf("Changed") != -1 && typeof obj[prop] == "function") { | ||
delete obj[prop]; | ||
} | ||
} | ||
delete obj[PROXY]; | ||
delete obj[BACKUP]; | ||
} | ||
function get$1(obj, prop) { | ||
return obj[prop]; | ||
} | ||
function set(obj, prop, value) { | ||
if (prop == "_disposing" || obj._disposing == true) return true; | ||
if (value != null && value.indexOf && value.indexOf(".") > 0) { | ||
return setOnPath(); | ||
} | ||
else { | ||
return setSingle(obj, prop, value); | ||
} | ||
} | ||
const excludeBackup = ["__isProxy", "element"]; | ||
function setSingle(obj, prop, value) { | ||
const backup = obj[BACKUP]; | ||
const oldValue = obj[prop]; | ||
obj[prop] = createProxyValue(obj[prop], value); | ||
crsbinding.events.notifyPropertyChanged(obj, prop); | ||
if (obj.propertyChanged != null) { | ||
obj.propertyChanged(value, oldValue); | ||
} | ||
if (isProxy(oldValue)) { | ||
releaseObserved(oldValue); | ||
} | ||
else { | ||
if (excludeBackup.indexOf(prop) == -1 && prop.indexOf("__") == -1) { | ||
backup[prop] = oldValue; | ||
} | ||
} | ||
return true; | ||
} | ||
function setOnPath(obj, prop, value) { | ||
return true; | ||
} | ||
function createProxyValue(origional, value) { | ||
if (origional && origional.__isProxy == true) { | ||
if (value && value.__isProxy != true) { | ||
return crsbinding.observation.observe(value, origional); | ||
} | ||
} | ||
return value; | ||
} | ||
function isProxy(obj) { | ||
return obj && typeof obj == "object" && obj[PROXY] == true; | ||
} | ||
/** | ||
* Contextualize a expression and extract the properties defined in the expression | ||
* @param exp | ||
* @returns {{expression: *, properties: *}} | ||
*/ | ||
function sanitizeExp(exp, ctxName = "context") { | ||
const namedExp = ctxName != "context"; | ||
const prefix = `${ctxName}.`; | ||
const tokens = tokenize(exp, namedExp ? ctxName : null); | ||
if (tokens.length == 1) { | ||
return { | ||
isLiteral: false, | ||
expression: `${prefix}${tokens[0]}`, | ||
properties: [exp] | ||
} | ||
} | ||
const properties = []; | ||
const isLiteral = exp.indexOf("${") != -1; | ||
let oldToken = null; | ||
let path = []; | ||
let indexes = []; | ||
for (let i = 0; i < tokens.length; i++) { | ||
const token = tokens[i]; | ||
if (quotes.indexOf(oldToken) != -1 || (reserved.indexOf(token) != -1 && ignore.indexOf(token) == -1)) | ||
{ | ||
oldToken = token; | ||
if (path.length > 0) { | ||
if (isLiteral == false || oldToken == "}") { | ||
if (isNaN(path)) { | ||
indexes.push(i - path.length); | ||
properties.push(extractProperty(`${path.join("")}`)); | ||
} | ||
} | ||
path.length = 0; | ||
} | ||
continue; | ||
} | ||
path.push(token); | ||
oldToken = token; | ||
} | ||
if (namedExp && path.length > 0) { | ||
if (isLiteral == false || oldToken == "}") { | ||
if (isNaN(path)) { | ||
indexes.push(tokens.length - 1); | ||
properties.push(extractProperty(`${path.join("")}`)); | ||
} | ||
} | ||
} | ||
if (indexes.length == 0 && exp.indexOf(".") != -1) { | ||
indexes.push(0); | ||
} | ||
for (let i = 0; i < indexes.length; i++) { | ||
tokens.splice(i + indexes[i], 0, prefix); | ||
} | ||
return { | ||
isLiteral: isLiteral, | ||
expression: tokens.join(""), | ||
properties: properties | ||
} | ||
} | ||
/** | ||
* Extract the property path up to where a function is being called. | ||
* @param property {string} | ||
* @returns {string|*} | ||
*/ | ||
function extractProperty(property) { | ||
if (property.indexOf("(") == -1) return property; | ||
const result = []; | ||
for (let p of property.split(".")) { | ||
if (p.indexOf("(") != -1) { | ||
break; | ||
} | ||
result.push(p); | ||
} | ||
return result.join("."); | ||
} | ||
const reserved = ["true", "false", "-", "+", "=", "<", ">", "(", ")","{", "}", "/", "&", "|", "=", "!", "'", "`", '"', " ", "$", ".", ",", "?", ":", "null", "undefined"]; | ||
const ignore = [".", "(", ")", ","]; | ||
const quotes = ["'", '"', "`"]; | ||
const stdQuotes = ["'", '"']; | ||
/** | ||
* Break the expression into expression tokens | ||
* @param exp | ||
* @returns {[]} | ||
*/ | ||
function tokenize(exp, ctxName) { | ||
let tokens = []; | ||
let word = []; | ||
let isString = false; | ||
for (let i = 0; i < exp.length; i++) { | ||
const char = exp[i]; | ||
if (isString == true && char == "$" && exp[i + 1] == "{") { | ||
isString = false; | ||
} | ||
if (isString == true) { | ||
if (stdQuotes.indexOf(char) == -1) { | ||
word.push(char); | ||
} | ||
else { | ||
pushToken(tokens, word, char); | ||
isString = false; | ||
} | ||
} | ||
else if (reserved.indexOf(char) != -1) { | ||
pushToken(tokens, word, char); | ||
if (stdQuotes.indexOf(char) != -1) { | ||
isString = true; | ||
} | ||
} | ||
else { | ||
word.push(char); | ||
} | ||
} | ||
if (word.length > 0) { | ||
tokens.push(word.join("")); | ||
} | ||
if (ctxName != null) { | ||
tokens = removeNamedCtx(tokens, ctxName); | ||
} | ||
return tokens; | ||
} | ||
function removeNamedCtx(collection, ctxName) { | ||
const index = collection.indexOf(ctxName); | ||
if (index == -1) return collection; | ||
if (collection[index + 1] == ".") { | ||
collection.splice(index, 2); | ||
if (collection.indexOf(ctxName) != -1) { | ||
removeNamedCtx(collection, ctxName); | ||
} } | ||
return collection; | ||
} | ||
function pushToken(tokens, word, char) { | ||
if (word.length > 0) { | ||
tokens.push(word.join("")); | ||
word.length = 0; | ||
} | ||
tokens.push(char); | ||
return false; | ||
} | ||
class ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
this._element = element; | ||
this._context = context; | ||
this._property = property; | ||
this._value = value; | ||
this._ctxName = ctxName || "context"; | ||
this._eventsToRemove = []; | ||
this._isNamedContext = this._ctxName != "context"; | ||
crsbinding.providerManager.register(this); | ||
this.initialize().catch(error => { | ||
throw error; | ||
}); | ||
if (this._element.nodeName.indexOf("-") != -1 && this._property == this._ctxName) { | ||
this._element[this._property] = this._context; | ||
} | ||
} | ||
dispose() { | ||
this._eventsToRemove.forEach(event => { | ||
crsbinding.events.removeOn(this._context, event.value, event.callback); | ||
}); | ||
this._eventsToRemove.length = 0; | ||
this._eventsToRemove = null; | ||
this._element = null; | ||
this._context = null; | ||
this._property = null; | ||
this._value = null; | ||
this._ctxName = null; | ||
} | ||
/** | ||
* Override to perform starting process | ||
*/ | ||
async initialize() { | ||
} | ||
listenOnPath(value, callback) { | ||
if (Array.isArray(value) == true) { | ||
for (let v of value) { | ||
this.listenOnPath(v, callback); | ||
} | ||
return; | ||
} | ||
if (this._isNamedContext) { | ||
value = value.replace(`${this._ctxName}.`, ""); | ||
} | ||
if (value.indexOf(".") == -1) { | ||
crsbinding.events.listenOn(this._context, value, callback); | ||
} | ||
else { | ||
crsbinding.events.listenOnPath(this._context, value, callback); | ||
} | ||
this._eventsToRemove.push({ | ||
value: value, | ||
callback: callback | ||
}); | ||
} | ||
removeOn(value, callback) { | ||
crsbinding.events.removeOn(this._context, value, callback); | ||
} | ||
} | ||
const setElementProperty = `requestAnimationFrame(() => element.__property__ = value || "")`; | ||
const setAttribute = `element.setAttribute("__property__", value || "")`; | ||
const setElementConditional = "requestAnimationFrame(() => element.__property__ = (__exp__) ? __true__ : __false__)"; | ||
const setDataset = `element.dataset["__property__"] = value || ""`; | ||
const setClassListRemove = ` | ||
if (element.__classList!=null) { | ||
const remove = Array.isArray(element.__classList) ? element.__classList : [element.__classList]; | ||
remove.forEach(cls => element.classList.remove(cls)); | ||
}`; | ||
const setClassListValue = ` | ||
element.__classList = value; | ||
const add = Array.isArray(value) ? value : [value]; | ||
add.forEach(cls => element.classList.add(cls));`; | ||
const setClassList = `${setClassListRemove} ${setClassListValue}`; | ||
const setClassListCondition = ` | ||
${setClassListRemove} | ||
if (__exp__) { | ||
${setClassListValue.split("value").join("__true__")} | ||
} | ||
else { | ||
${setClassListValue.split("value").join("__false__")} | ||
} | ||
`; | ||
class OneWayProvider extends ProviderBase { | ||
dispose() { | ||
const contextPrefix = `${this._ctxName}.`; | ||
if (this._value.indexOf(contextPrefix) == 0) { | ||
this._value = this._value.replace(contextPrefix, ""); | ||
} | ||
this.removeOn(this._value, this._eventHandler); | ||
if (this._expObj != null) { | ||
crsbinding.expression.release(this._expObj); | ||
delete this._expObj; | ||
} | ||
if (this._getObj != null) { | ||
crsbinding.expression.release(this._getObj); | ||
delete this._getObj; | ||
} | ||
this._exp = null; | ||
this._eventHandler = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
if (this._value == "$context") { | ||
return this.setContext(); | ||
} | ||
this._eventHandler = this.propertyChanged.bind(this); | ||
this._exp = getExpForProvider(this); | ||
this._expObj = crsbinding.expression.compile(this._exp, ["element", "value"], {sanitize: false, ctxName: this._ctxName}); | ||
if (this._value.indexOf(".") != -1) { | ||
this._getObj = crsbinding.expression.compile(this._value, null, {ctxName: this._ctxName}); | ||
} | ||
this.listenOnPath(this._value, this._eventHandler); | ||
const v = this._context[this._value]; | ||
if (v != null) { | ||
this.propertyChanged(null, v); | ||
} | ||
} | ||
setContext() { | ||
if (this._element != null && this._property != null) { | ||
this._element[this._property] = this._context; | ||
} | ||
} | ||
propertyChanged(prop, value) { | ||
let v = value; | ||
if (this._getObj != null) { | ||
v = this._getObj.function(this._context); | ||
} | ||
crsbinding.idleTaskManager.add(this._expObj.function(this._context, this._element, v)); | ||
} | ||
} | ||
function getExpForProvider(provider) { | ||
let result; | ||
if (provider._property.toLocaleLowerCase() == "classlist") { | ||
return setClassList; | ||
} | ||
if (provider._property.indexOf("data-") != -1) { | ||
const prop = provider._property.replace("data-", ""); | ||
return setDataset.split("__property__").join(prop); | ||
} | ||
if (provider._property.indexOf("-") == -1 || (provider._property.indexOf("-") != -1 && provider._property.indexOf(".") != -1)) { | ||
result = setElementProperty; | ||
provider._property = crsbinding.utils.capitalizePropertyPath(provider._property); | ||
} | ||
else { | ||
result = setAttribute; | ||
} | ||
return result.split("__property__").join(provider._property); | ||
} | ||
class BindProvider extends OneWayProvider { | ||
dispose() { | ||
this._element.removeEventListener("change", this._changeHandler); | ||
this._changeHandler = null; | ||
crsbinding.expression.release(this._setObj); | ||
delete this._setObj; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
await super.initialize(); | ||
this._changeHandler = this._change.bind(this); | ||
this._element.addEventListener("change", this._changeHandler); | ||
const exp = this._isNamedContext == true ? `${this._value} = value` : `context.${this._value} = value`; | ||
this._setObj = crsbinding.expression.compile(exp, ["value"], {sanitize: false, ctxName: this._ctxName}); | ||
} | ||
_change(event) { | ||
let value = event.target[this._property]; | ||
const type = event.target.type || "text"; | ||
const typeFn = `_${type}`; | ||
if (this[typeFn] != null) { | ||
value = this[typeFn](value, event.target); | ||
} | ||
this._setObj.function(this._context, value); | ||
event.stopPropagation(); | ||
} | ||
_number(value) { | ||
return Number(value); | ||
} | ||
_date(value) { | ||
return new Date(value); | ||
} | ||
_checkbox(value, element) { | ||
return element.checked == true; | ||
} | ||
} | ||
function OnceProvider(element, context, property, value, ctxName = "context") { | ||
if (ctxName == "context") { | ||
setContext(element, context, property, value); | ||
} | ||
else { | ||
setItem(element, context, property, value, ctxName); | ||
} | ||
return null; | ||
} | ||
function setContext(element, context, property, value) { | ||
const fn = new Function("context", `return context.${value}`); | ||
setProperty(element, property, fn(context)); | ||
} | ||
function setItem(element, context, property, value, ctxName) { | ||
const fn = new Function(ctxName, `return ${ctxName}.${value}`); | ||
setProperty(element, property, fn(context)); | ||
} | ||
function setProperty(element, property, value) { | ||
if (property.indexOf("data-") == -1) { | ||
property = crsbinding.utils.capitalizePropertyPath(property); | ||
const fn = new Function("element", "value", `element.${property} = value`); | ||
fn(element, value); | ||
} | ||
else { | ||
const prop = property.replace("data-", ""); | ||
element.dataset[prop] = value; | ||
} | ||
} | ||
class CallProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
this._eventHandler = this.event.bind(this); | ||
this._element.addEventListener(this._property, this._eventHandler); | ||
} | ||
dispose() { | ||
this._element.removeEventListener(this._property, this._eventHandler); | ||
this._eventHandler = null; | ||
this._fn = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
let src = `context.${this._value}`.split("$event").join("event"); | ||
if (src.indexOf(")") == -1) { | ||
src = `${src}.call(context)`; | ||
} | ||
this._fn = new Function("context", src); | ||
} | ||
event(event) { | ||
crsbinding.idleTaskManager.add(this._fn(this._context)); | ||
event.stopPropagation(); | ||
} | ||
} | ||
class InnerProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
this._eventHandler = this._change.bind(this); | ||
this._expObj = crsbinding.expression.compile(element.innerText, null, {ctxName: this._ctxName}); | ||
for (let prop of this._expObj.parameters.properties) { | ||
this.listenOnPath(prop, this._eventHandler); | ||
} | ||
this._change(); | ||
} | ||
dispose() { | ||
crsbinding.expression.release(this._expObj); | ||
this._expObj = null; | ||
super.dispose(); | ||
this._eventHandler = null; | ||
} | ||
_change() { | ||
if (this._expObj == null) return; | ||
this._element.innerText = this._expObj.function(this._context); | ||
} | ||
} | ||
class AttrProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
this._eventHandler = this._change.bind(this); | ||
this._expObj = crsbinding.expression.compile(value, null, {ctxName: this._ctxName}); | ||
for (let prop of this._expObj.parameters.properties) { | ||
this.listenOnPath(prop, this._eventHandler); | ||
} | ||
} | ||
dispose() { | ||
crsbinding.expression.release(this._expObj); | ||
this._expObj = null; | ||
super.dispose(); | ||
this._eventHandler = null; | ||
} | ||
_change() { | ||
if (this._expObj == null) return; | ||
const value = this._expObj.function(this._context); | ||
this._element.setAttribute(this._property, value); | ||
} | ||
} | ||
class ForProvider extends ProviderBase { | ||
get ar() { | ||
return this._ar; | ||
} | ||
set ar(newValue) { | ||
if (this._ar != null) { | ||
crsbinding.events.removeOn(this._ar, "items-added", this._itemsAddedHandler); | ||
crsbinding.events.removeOn(this._ar, "items-deleted", this._itemsDeletedHandler); | ||
} | ||
this._ar = newValue; | ||
if (this._ar != null) { | ||
crsbinding.events.on(this._ar, "items-added", this._itemsAddedHandler); | ||
crsbinding.events.on(this._ar, "items-deleted", this._itemsDeletedHandler); | ||
} | ||
} | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
this._itemsAddedHandler = this._itemsAdded.bind(this); | ||
this._itemsDeletedHandler = this._itemsDeleted.bind(this); | ||
} | ||
dispose() { | ||
this.ar = null; | ||
crsbinding.expression.release(this._forExp); | ||
this._forExp = null; | ||
this._itemsAddedHandler = null; | ||
this._itemsDeletedHandler = null; | ||
this._singular = null; | ||
this._plural = null; | ||
this._container = null; | ||
this._collectionChangedHandler = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
// 1. get the container and remove the template | ||
this._container = this._element.parentElement; | ||
this._container.removeChild(this._element); | ||
// 2. get the properties to work with and build the for loop | ||
const parts = this._value.split("of"); | ||
this._singular = parts[0].trim(); | ||
this._plural = parts[1].trim(); | ||
const forExp = repeatCode | ||
.split("_p").join(this._singular) | ||
.split("_c").join(this._ctxName == "context" ? `context.${this._plural}` : this._plural); | ||
this._forExp = crsbinding.expression.compile(forExp, ["callback"], {sanitize: false, async: true, ctxName: this._ctxName}); | ||
// 3. listen to the collection property on the context changing | ||
this._collectionChangedHandler = this._collectionChanged.bind(this); | ||
this.listenOnPath(this._plural, this._collectionChangedHandler); | ||
} | ||
async _collectionChanged(property, newValue) { | ||
if (Array.isArray(newValue)) { | ||
this.ar = newValue; | ||
} | ||
else { | ||
const fn = new Function("context", `return context.${this._plural}`); | ||
this.ar = fn(this._context); | ||
} | ||
if (this.ar != null) { | ||
await this._renderItems(); | ||
} | ||
} | ||
async _renderItems() { | ||
// release the old content | ||
await crsbinding.observation.releaseChildBinding(this._container); | ||
if (this.ar == null) return; | ||
// create document fragment | ||
const fragment = document.createDocumentFragment(); | ||
// loop through items and add them to fragment after being parsed | ||
await this._forExp.function(this._context, (item) => { | ||
const element = this.createElement(item); | ||
fragment.appendChild(element); | ||
}); | ||
this._container.innerHTML = ""; | ||
this._container.appendChild(fragment); | ||
// render the updates. custom components are not ready at this time yet. so do it on the next frame. | ||
crsbinding.expression.updateUI(this.ar); | ||
// update the container's provider to this so that this can be freed when content changes | ||
if (this._container.__providers == null) { | ||
this._container.__providers = []; | ||
} | ||
if (this._container.__providers.indexOf(this.id) == -1) { | ||
this._container.__providers.push(this.id); | ||
} | ||
} | ||
_itemsAdded(event, value, added) { | ||
for (let i = 0; i < added.items.length; i++) { | ||
const item = added.items[i]; | ||
const index = added.indexes[i]; | ||
const element = this.createElement(item); | ||
const update = element.children[0]; | ||
const child = this._container.children[index]; | ||
this._container.insertBefore(element, child); | ||
for (let p of update.__providers || []) { | ||
const provider = crsbinding.providerManager.items.get(p); | ||
if (provider instanceof AttrProvider) { | ||
provider._change(); | ||
} | ||
} | ||
} | ||
} | ||
_itemsDeleted(event, value, removed) { | ||
const elements = []; | ||
const push = (item) => { | ||
const uid = item.__uid; | ||
const result = this._container.querySelectorAll([`[data-uid="${uid}"]`]); | ||
result.forEach(element => elements.push(element)); | ||
}; | ||
if (Array.isArray(removed)) { | ||
for (let item of removed) { | ||
push(item); | ||
} | ||
} | ||
else { | ||
push(removed); | ||
} | ||
for (let element of elements) { | ||
if (element != null) { | ||
element.parentElement.removeChild(element); | ||
crsbinding.observation.releaseBinding(element); | ||
} | ||
} | ||
} | ||
createElement(item) { | ||
const element = this._element.content.cloneNode(true); | ||
crsbinding.parsers.parseElement(element, item, this._singular); | ||
for (let child of element.children) { | ||
child.dataset.uid = item.__uid; | ||
} | ||
return element; | ||
} | ||
} | ||
const repeatCode = `for (_p of _c || []) {callback(_p);}`; | ||
class IfProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
} | ||
dispose() { | ||
crsbinding.expression.release(this._expObj); | ||
delete this._expObj; | ||
this._eventHandler = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
this._eventHandler = this.propertyChanged.bind(this); | ||
if (this._value.indexOf("?") == -1) { | ||
this._initCndAttr(); | ||
} | ||
else if(this._value.indexOf(":") != -1) { | ||
this._initCndValue(); | ||
} | ||
else { | ||
this._initCndAttrValue(); | ||
} | ||
this.propertyChanged(); | ||
} | ||
/** | ||
* There is no value to be set. | ||
* Add or remove the attribute. | ||
* Used for hidden.bind or disabled.bind | ||
* @private | ||
*/ | ||
_initCndAttr() { | ||
const value = crsbinding.expression.sanitize(this._value, this._ctxName); | ||
const fnCode = initCndAttrExp | ||
.split("__exp__").join(value.expression) | ||
.split("__attr__").join(this._property) | ||
.split("__attr-value__").join(this._property); | ||
this._expObj = crsbinding.expression.compile(fnCode, ["element"], {sanitize: false, ctxName: this._ctxName}); | ||
this.listenOnPath(value.properties, this._eventHandler); | ||
} | ||
/** | ||
* There is an attribute value that gets toggled do not remove the attribute | ||
* @private | ||
*/ | ||
_initCndValue() { | ||
const value = crsbinding.expression.sanitize(this._value, this._ctxName); | ||
const parts = value.expression.split("?"); | ||
const valueParts = parts[1].split(":"); | ||
const fnCode = initCndValueExp | ||
.split("__exp__").join(parts[0].trim()) | ||
.split("__attr__").join(this._property) | ||
.split("__true__").join(valueParts[0].trim()) | ||
.split("__false__").join(valueParts[1].trim()); | ||
this._expObj = crsbinding.expression.compile(fnCode, ["element"], {sanitize: false, ctxName: this._ctxName}); | ||
this.listenOnPath(value.properties, this._eventHandler); | ||
} | ||
/** | ||
* if the expression passes set the attribute else remove the attribute | ||
* @private | ||
*/ | ||
_initCndAttrValue() { | ||
const value = crsbinding.expression.sanitize(this._value, this._ctxName); | ||
const parts = value.expression.split("?"); | ||
const fnCode = initCndAttrExp | ||
.split("__exp__").join(parts[0].trim()) | ||
.split("__attr__").join(this._property) | ||
.split("__attr-value__").join(parts[1].trim()); | ||
this._expObj = crsbinding.expression.compile(fnCode, ["element"], {sanitize: false, ctxName: this._ctxName}); | ||
this.listenOnPath(value.properties, this._eventHandler); | ||
} | ||
propertyChanged() { | ||
crsbinding.idleTaskManager.add(this._expObj.function(this._context, this._element)); | ||
} | ||
} | ||
const initCndAttrExp = ` | ||
if (__exp__) { | ||
element.setAttribute("__attr__", "__attr-value__"); | ||
} | ||
else { | ||
element.removeAttribute("__attr__"); | ||
} | ||
`; | ||
const initCndValueExp = ` | ||
if (__exp__) { | ||
element.setAttribute("__attr__", "__true__"); | ||
} | ||
else { | ||
element.setAttribute("__attr__", "__false__"); | ||
} | ||
`; | ||
class IfClassProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
} | ||
dispose() { | ||
crsbinding.expression.release(this._expObj); | ||
delete this._expObj; | ||
this._eventHandler = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
this._eventHandler = this.propertyChanged.bind(this); | ||
const parts = this._value.split("?"); | ||
const value = crsbinding.expression.sanitize(parts[0], this._ctxName); | ||
const condition = value.expression; | ||
const values = parts[1].split(":"); | ||
const trueValue = values[0].trim(); | ||
const falseValue = values.length > 1 ? values[1].trim() : '[]'; | ||
const fnCode = setClassListCondition | ||
.split("__property__").join(this._property) | ||
.split("__exp__").join(condition) | ||
.split("__true__").join(trueValue) | ||
.split("__false__").join(falseValue); | ||
this._expObj = crsbinding.expression.compile(fnCode, ["element"], {sanitize: false, ctxName: this._ctxName}); | ||
this.listenOnPath(value.properties, this._eventHandler); | ||
} | ||
propertyChanged() { | ||
crsbinding.idleTaskManager.add(this._expObj.function(this._context, this._element)); | ||
} | ||
} | ||
class IfStylesProvider extends ProviderBase { | ||
constructor(element, context, property, value, ctxName) { | ||
super(element, context, property, value, ctxName); | ||
} | ||
dispose() { | ||
crsbinding.expression.release(this._expObj); | ||
delete this._expObj; | ||
this._eventHandler = null; | ||
super.dispose(); | ||
} | ||
async initialize() { | ||
this._eventHandler = this.propertyChanged.bind(this); | ||
const value = crsbinding.expression.sanitize(this._value, this._ctxName); | ||
const parts = value.expression.split("?"); | ||
const condition = parts[0].trim(); | ||
const values = parts[1].split(":"); | ||
const trueValue = values[0].trim(); | ||
const falseValue = values.length > 1 ? values[1].trim() : '""'; | ||
const fnCode = setElementConditional | ||
.split("__property__").join(this._property) | ||
.split("__exp__").join(condition) | ||
.split("__true__").join(trueValue) | ||
.split("__false__").join(falseValue); | ||
this._expObj = crsbinding.expression.compile(fnCode, ["element"], {sanitize: false, ctxName: this._ctxName}); | ||
this.listenOnPath(value.properties, this._eventHandler); | ||
} | ||
propertyChanged() { | ||
crsbinding.idleTaskManager.add(this._expObj.function(this._context, this._element)); | ||
} | ||
} | ||
class ProviderFactory { | ||
static "bind"(element, context, property, value, ctxName) { | ||
if (["value", "checked"].indexOf(property) != -1) { | ||
return new BindProvider(element, context, property, value, ctxName) | ||
} | ||
else { | ||
return this["one-way"](element, context, property, value, ctxName); | ||
} | ||
} | ||
static "two-way"(element, context, property, value, ctxName) { | ||
return this.bind(element, context, property, value, ctxName); | ||
} | ||
static "one-way"(element, context, property, value, ctxName) { | ||
return new OneWayProvider(element, context, property, value, ctxName); | ||
} | ||
static "once"(element, context, property, value, ctxName) { | ||
return OnceProvider(element, context, property, value, ctxName); | ||
} | ||
static "call"(element, context, property, value, ctxName) { | ||
return new CallProvider(element, context, property, value, ctxName); | ||
} | ||
static "delegate"(element, context, property, value, ctxName) { | ||
return new CallProvider(element, context, property, value, ctxName); | ||
} | ||
static "inner"(element, context, property, value, ctxName) { | ||
return new InnerProvider(element, context, property, value, ctxName); | ||
} | ||
static "for"(element, context, property, value, ctxName) { | ||
return new ForProvider(element, context, property, value, ctxName); | ||
} | ||
static "if"(element, context, property, value, ctxName) { | ||
if (property.toLowerCase() == "classlist") { | ||
return new IfClassProvider(element, context, property, value, ctxName); | ||
} | ||
if (property.toLowerCase().indexOf("style.") != -1) { | ||
return new IfStylesProvider(element, context, property, value, ctxName); | ||
} | ||
return new IfProvider(element, context, property, value, ctxName); | ||
} | ||
static "attr"(element, context, property, value, ctxName) { | ||
return new AttrProvider(element, context, property, value, ctxName); | ||
} | ||
} | ||
function parseElements(collection, context, ctxName = "context") { | ||
for (let element of collection || []) { | ||
parseElement(element, context, ctxName); | ||
} | ||
} | ||
function parseElement(element, context, ctxName = "context") { | ||
parseElements(element.children, context, ctxName); | ||
const attributes = Array.from(element.attributes || []); | ||
const boundAttributes = attributes.filter(attr => | ||
(attr.ownerElement.tagName == "TEMPLATE" && attr.name == "for") || | ||
(attr.name.indexOf(".") != -1) || | ||
((attr.value || "").indexOf("${") == 0) | ||
); | ||
parseAttributes(boundAttributes, context, ctxName); | ||
if (element.children && element.children.length == 0 && (element.innerText || "").indexOf("${") != -1) { | ||
ProviderFactory["inner"](element, context, null, null, ctxName); | ||
} | ||
} | ||
function parseAttributes(collection, context, ctxName) { | ||
for (let attr of collection) { | ||
parseAttribute(attr, context, ctxName); | ||
} | ||
} | ||
function parseAttribute(attr, context, ctxName) { | ||
const parts = attr.name.split("."); | ||
let prop = parts.length == 2 ? parts[0] : parts.slice(0, parts.length -1).join("."); | ||
let prov = prop == "for" ? prop : parts[parts.length - 1]; | ||
if (prop.length == 0 && attr.value[0] == "$") { | ||
prop = prov; | ||
prov = "attr"; | ||
} | ||
const provider = ProviderFactory[prov](attr.ownerElement, context, prop, attr.value, ctxName); | ||
attr.ownerElement.removeAttribute(attr.nodeName); | ||
// used for testing | ||
return provider; | ||
} | ||
function releaseBinding(element) { | ||
crsbinding.providerManager.releaseElement(element); | ||
} | ||
function releaseChildBinding(element) { | ||
for (let child of element.children) { | ||
releaseBinding(child); | ||
} | ||
} | ||
class ProviderManager { | ||
constructor() { | ||
this._nextId = 0; | ||
this.items = new Map(); | ||
} | ||
async register(provider) { | ||
provider.id = this._nextId; | ||
if (provider._element.__providers == null) { | ||
Reflect.set(provider._element, "__providers", []); | ||
} | ||
provider._element.__providers.push(this._nextId); | ||
this.items.set(this._nextId, provider); | ||
this._nextId += 1; | ||
} | ||
async releaseElement(element) { | ||
for (let child of element.children || []) { | ||
await this.releaseElement(child); | ||
} | ||
if (element.__providers == null) return; | ||
for (let id of element.__providers) { | ||
const provider = this.items.get(id); | ||
this.items.delete(id); | ||
provider && provider.dispose(); | ||
} | ||
element.__providers = null; | ||
} | ||
} | ||
globalThis.requestIdleCallback = | ||
globalThis.requestIdleCallback || | ||
function (cb) { | ||
const start = Date.now(); | ||
return setTimeout(function () { | ||
cb({ | ||
didTimeout: false, | ||
timeRemaining: function () { | ||
return Math.max(0, 50 - (Date.now() - start)); | ||
} | ||
}); | ||
}, 1); | ||
}; | ||
globalThis.cancelIdleCallback = | ||
globalThis.cancelIdleCallback || | ||
function (id) { | ||
clearTimeout(id); | ||
}; | ||
class IdleTaskManager { | ||
constructor() { | ||
this.processing = false; | ||
this._list = []; | ||
} | ||
dispose() { | ||
this._list = null; | ||
} | ||
/** | ||
* Add a function to the manager to call once the system is idle | ||
* @param fn {Function} | ||
*/ | ||
add(fn) { | ||
fn && this._list.push(fn); | ||
!this.processing && this._processQueue(); | ||
} | ||
/** | ||
* Loop through the required functions and execute them in turn. | ||
* @private | ||
*/ | ||
_processQueue() { | ||
if (requestIdleCallback == null) return this._runNextFunction(); | ||
this.processing = true; | ||
requestIdleCallback(deadline => { | ||
while((deadline.timeRemaining() > 0 || deadline.didTimeout) && this._list.length) { | ||
this._runNextFunction(); | ||
} | ||
this.processing = false; | ||
}, {timeout: 1000}); | ||
} | ||
/** | ||
* Shift the list and run the function | ||
* @private | ||
*/ | ||
_runNextFunction() { | ||
let fn = this._list.shift(); | ||
fn && fn(); | ||
} | ||
} | ||
function updateUI(context) { | ||
if (context.__isProxy == false) return; | ||
if (Array.isArray(context)) return updateUIArray(context); | ||
const keys = context.constructor.properties || Object.keys(context).filter(item => item.indexOf("__") == -1 && item != "__isProxy"); | ||
for (let key of keys) { | ||
crsbinding.events.notifyPropertyChanged(context, key); | ||
if (Array.isArray(context[key])) { | ||
updateUIArray(context[key]); | ||
} | ||
} | ||
} | ||
function updateUIArray (context) { | ||
context.forEach(item => updateUI(item)); | ||
} | ||
function listenOnPath(context, value, callback) { | ||
let obj = context; | ||
const parts = value.split("."); | ||
for (let i = 0; i < parts.length; i++) { | ||
const part = parts[i]; | ||
if (i == parts.length -1) { | ||
listenOn(obj, part, callback); | ||
} | ||
else { | ||
if (obj[part] == null) { | ||
// actual vs empty object | ||
obj[part] = crsbinding.observation.observe({}); | ||
} | ||
listenOn(obj, part, callback); | ||
obj = obj[part]; | ||
} | ||
} | ||
} | ||
function listenOn(context, property, callback) { | ||
crsbinding.events.on(context, property.trim(), callback); | ||
} | ||
function domEnableEvents(element) { | ||
element._domEvents = []; | ||
element.registerEvent = registerEvent; | ||
element.unregisterEvent = unregisterEvent; | ||
} | ||
function domDisableEvents(element) { | ||
if (element._domEvents == null) return; | ||
for (let event of element._domEvents) { | ||
event.callback = null; | ||
event.event = null; | ||
} | ||
element._domEvents.length = 0; | ||
delete element._domEvents; | ||
delete element.registerEvent; | ||
delete element.unregisterEvent; | ||
} | ||
function registerEvent(event, callback) { | ||
this.addEventListener(event, callback); | ||
this._domEvents.push({ | ||
event: event, | ||
callback: callback | ||
}); | ||
} | ||
function unregisterEvent(event, callback) { | ||
const item = this._domEvents.find(item => item.event == event && item.callback == callback); | ||
if (item == null) return; | ||
this.removeEventListener(item.event, item.callback); | ||
this._domEvents.splice(this._domEvents.indexOf(item), 1); | ||
item.callback = null; | ||
item.event = null; | ||
} | ||
String.prototype.capitalize = function() { | ||
return this.charAt(0).toUpperCase() + this.slice(1) | ||
}; | ||
function capitalizePropertyPath(str) { | ||
const parts = str.split("-"); | ||
for (let i = 1; i < parts.length; i++) { | ||
parts[i] = parts[i].capitalize(); | ||
} | ||
return parts.join(""); | ||
} | ||
const crsbinding$1 = { | ||
_expFn: new Map(), | ||
idleTaskManager: new IdleTaskManager(), | ||
providerManager: new ProviderManager(), | ||
expression: { | ||
sanitize: sanitizeExp, | ||
compile: compileExp, | ||
release: releaseExp, | ||
updateUI: updateUI, | ||
}, | ||
observation: { | ||
observe: observe, | ||
releaseObserved: releaseObserved, | ||
releaseBinding: releaseBinding, | ||
releaseChildBinding: releaseChildBinding | ||
}, | ||
parsers: { | ||
parseElement: parseElement, | ||
parseElements: parseElements, | ||
}, | ||
events: { | ||
enableEvents: enableEvents, | ||
disableEvents: disableEvents, | ||
when: when, | ||
on: on, | ||
notifyPropertyChanged: notifyPropertyChanged, | ||
removeOn: removeOn, | ||
removeWhen: removeWhen, | ||
listenOn: listenOn, | ||
listenOnPath: listenOnPath | ||
}, | ||
dom: { | ||
enableEvents: domEnableEvents, | ||
disableEvents: domDisableEvents | ||
}, | ||
utils: { | ||
capitalizePropertyPath: capitalizePropertyPath | ||
} | ||
}; | ||
globalThis.crsbinding = crsbinding$1; | ||
export { crsbinding$1 as crsbinding }; | ||
const e=Object.getPrototypeOf((async function(){})).constructor;function t(t,n,i){n=n||[];let s=!0,r=!1,l="context";if(null!=i&&(null!=i.sanitize&&(s=i.sanitize),null!=i.async&&(r=i.async),null!=i.ctxName&&(l=i.ctxName)),crsbinding._expFn.has(t)){const e=crsbinding._expFn.get(t);return e.count+=1,e}let o,a=t;if(1==s){if(o=crsbinding.expression.sanitize(t,l),crsbinding._expFn.has(o.expression)){const e=crsbinding._expFn.get(o.expression);return e.count+=1,e}a=!0===o.isLiteral?["return `",o.expression,"`"].join(""):`return ${o.expression}`}else o={expression:t};const _={function:1==r?new e(l,...n,a):new Function(l,...n,a),parameters:o,count:1};return crsbinding._expFn.set(o.expression,_),_}function n(e,t,i){if(-1!=t.indexOf("."))return function(e,t,i){const s=t.split(".");for(let t of s)n(e,t,i),e=e[t]}(e,t,i);if(null==e||null==e.__events)return;const s=e.__events.get(t)||[],r=s.indexOf(i);-1!=r&&(s.splice(r,1),e.__events.set(t,s)),0==s.length&&e.__events.delete(t)}const i="__isArray";function s(e){e[i]=!0,null==e._events&&crsbinding.events.enableEvents(e),e.__nextId=1;for(let t=0;t<e.length;t++)c(e,t);return new Proxy(e,{get:a})}function r(e){crsbinding.events.disableEvents(e),e.forEach(e=>crsbinding.observation.releaseObserved(e))}const l=["pop","splice"],o=["push"];function a(e,t){const n=e[t];return"function"==typeof n?(...n)=>{const i=e[t](...n);return-1!=l.indexOf(t)?(!function(e,t){if(null==t)return;if(crsbinding.events.notifyPropertyChanged(e,"items-deleted",t),Array.isArray(t))for(let e of t)crsbinding.observation.releaseObserved(e);else crsbinding.observation.releaseObserved(t)}(e,i),"splice"==t&&n.length>2&&(n=n.splice(2,n.length),_(e,n))):-1!=o.indexOf(t)&&_(e,n),i}:n}function _(e,t){if(null==t)return;const n={items:[],indexes:[]};for(let i of t){const t=e.indexOf(i);c(e,t),n.items.push(i),n.indexes.push(t)}crsbinding.events.notifyPropertyChanged(e,"items-added",n)}function c(e,t){const n=e[t];n.__uid=e.__nextId,e.__nextId++,1!=n.__isProxy&&(e[t]=crsbinding.observation.observe(n))}const h="__isProxy",d="__backup";function p(e){if(1==e.__isArray)return r(e);crsbinding.events.disableEvents(e);const t=Object.keys(e);for(let n of t)Array.isArray(e[n])&&r(e[n]);null!=e.dispose&&(e._disposing=!0,e.dispose());const n=Object.getOwnPropertyNames(e);for(let t of n)-1!=t.indexOf("Changed")&&"function"==typeof e[t]&&delete e[t];delete e[h],delete e[d]}function u(e,t){return e[t]}function f(e,t,n){return"_disposing"==t||1==e._disposing||(!!(null!=n&&n.indexOf&&n.indexOf(".")>0)||function(e,t,n){const i=e[d],s=e[t];e[t]=function(e,t){if(e&&1==e.__isProxy&&t&&1!=t.__isProxy)return crsbinding.observation.observe(t,e);return t}(e[t],n),crsbinding.events.notifyPropertyChanged(e,t),null!=e.propertyChanged&&e.propertyChanged(n,s);!function(e){return e&&"object"==typeof e&&1==e[h]}(s)?-1==x.indexOf(t)&&-1==t.indexOf("__")&&(i[t]=s):p(s);return!0}(e,t,n))}const x=["__isProxy","element"];function m(e){if(-1==e.indexOf("("))return e;const t=[];for(let n of e.split(".")){if(-1!=n.indexOf("("))break;t.push(n)}return t.join(".")}const g=["true","false","-","+","=","<",">","(",")","{","}","/","&","|","=","!","'","`",'"'," ","$",".",",","?",":","null","undefined"],v=[".","(",")",","],b=["'",'"',"`"],y=["'",'"'];function O(e,t,n){return t.length>0&&(e.push(t.join("")),t.length=0),e.push(n),!1}class j{constructor(e,t,n,i,s){this._element=e,this._context=t,this._property=n,this._value=i,this._ctxName=s||"context",this._eventsToRemove=[],this._isNamedContext="context"!=this._ctxName,crsbinding.providerManager.register(this),this.initialize().catch(e=>{throw e}),-1!=this._element.nodeName.indexOf("-")&&this._property==this._ctxName&&(this._element[this._property]=this._context)}dispose(){this._eventsToRemove.forEach(e=>{crsbinding.events.removeOn(this._context,e.value,e.callback)}),this._eventsToRemove.length=0,this._eventsToRemove=null,this._element=null,this._context=null,this._property=null,this._value=null,this._ctxName=null}async initialize(){}listenOnPath(e,t){if(1!=Array.isArray(e))this._isNamedContext&&(e=e.replace(`${this._ctxName}.`,"")),-1==e.indexOf(".")?crsbinding.events.listenOn(this._context,e,t):crsbinding.events.listenOnPath(this._context,e,t),this._eventsToRemove.push({value:e,callback:t});else for(let n of e)this.listenOnPath(n,t)}removeOn(e,t){crsbinding.events.removeOn(this._context,e,t)}}const E='requestAnimationFrame(() => element.__property__ = value || "")',N='element.setAttribute("__property__", value || "")',C="requestAnimationFrame(() => element.__property__ = (__exp__) ? __true__ : __false__)",A='element.dataset["__property__"] = value || ""',w="\nif (element.__classList!=null) {\n const remove = Array.isArray(element.__classList) ? element.__classList : [element.__classList];\n remove.forEach(cls => element.classList.remove(cls));\n}",H="\nelement.__classList = value;\nconst add = Array.isArray(value) ? value : [value];\nadd.forEach(cls => element.classList.add(cls));",P=`${w} ${H}`,$=`\n ${w}\n\n if (__exp__) {\n ${H.split("value").join("__true__")}\n }\n else {\n ${H.split("value").join("__false__")}\n }\n`;class z extends j{dispose(){const e=`${this._ctxName}.`;0==this._value.indexOf(e)&&(this._value=this._value.replace(e,"")),this.removeOn(this._value,this._eventHandler),null!=this._expObj&&(crsbinding.expression.release(this._expObj),delete this._expObj),null!=this._getObj&&(crsbinding.expression.release(this._getObj),delete this._getObj),this._exp=null,this._eventHandler=null,super.dispose()}async initialize(){if("$context"==this._value)return this.setContext();this._eventHandler=this.propertyChanged.bind(this),this._exp=function(e){let t;if("classlist"==e._property.toLocaleLowerCase())return P;if(-1!=e._property.indexOf("data-")){const t=e._property.replace("data-","");return A.split("__property__").join(t)}-1==e._property.indexOf("-")||-1!=e._property.indexOf("-")&&-1!=e._property.indexOf(".")?(t=E,e._property=crsbinding.utils.capitalizePropertyPath(e._property)):t=N;return t.split("__property__").join(e._property)}(this),this._expObj=crsbinding.expression.compile(this._exp,["element","value"],{sanitize:!1,ctxName:this._ctxName}),-1!=this._value.indexOf(".")&&(this._getObj=crsbinding.expression.compile(this._value,null,{ctxName:this._ctxName})),this.listenOnPath(this._value,this._eventHandler);const e=this._context[this._value];null!=e&&this.propertyChanged(null,e)}setContext(){null!=this._element&&null!=this._property&&(this._element[this._property]=this._context)}propertyChanged(e,t){let n=t;null!=this._getObj&&(n=this._getObj.function(this._context)),crsbinding.idleTaskManager.add(this._expObj.function(this._context,this._element,n))}}class k extends z{dispose(){this._element.removeEventListener("change",this._changeHandler),this._changeHandler=null,crsbinding.expression.release(this._setObj),delete this._setObj,super.dispose()}async initialize(){await super.initialize(),this._changeHandler=this._change.bind(this),this._element.addEventListener("change",this._changeHandler);const e=1==this._isNamedContext?`${this._value} = value`:`context.${this._value} = value`;this._setObj=crsbinding.expression.compile(e,["value"],{sanitize:!1,ctxName:this._ctxName})}_change(e){let t=e.target[this._property];const n=`_${e.target.type||"text"}`;null!=this[n]&&(t=this[n](t,e.target)),this._setObj.function(this._context,t),e.stopPropagation()}_number(e){return Number(e)}_date(e){return new Date(e)}_checkbox(e,t){return 1==t.checked}}function T(e,t,n,i,s="context"){return"context"==s?function(e,t,n,i){const s=new Function("context",`return context.${i}`);L(e,n,s(t))}(e,t,n,i):function(e,t,n,i,s){const r=0==i.indexOf(s)?`return ${i}`:`return ${s}.${i}`,l=new Function(s,r);L(e,n,l(t))}(e,t,n,i,s),null}function L(e,t,n){if(-1==t.indexOf("data-")){t=crsbinding.utils.capitalizePropertyPath(t),new Function("element","value",`element.${t} = value`)(e,n)}else{const i=t.replace("data-","");e.dataset[i]=n}}class F extends j{constructor(e,t,n,i,s){super(e,t,n,i,s),this._eventHandler=this.event.bind(this),this._element.addEventListener(this._property,this._eventHandler)}dispose(){this._element.removeEventListener(this._property,this._eventHandler),this._eventHandler=null,this._fn=null,super.dispose()}async initialize(){let e=`context.${this._value}`.split("$event").join("event");-1==e.indexOf(")")&&(e=`${e}.call(context)`),this._fn=new Function("context",e)}event(e){crsbinding.idleTaskManager.add(this._fn(this._context)),e.stopPropagation()}}class I extends j{constructor(e,t,n,i,s){super(e,t,n,i,s),this._eventHandler=this._change.bind(this),this._expObj=crsbinding.expression.compile(e.innerText,null,{ctxName:this._ctxName});for(let e of this._expObj.parameters.properties)this.listenOnPath(e,this._eventHandler);this._change()}dispose(){crsbinding.expression.release(this._expObj),this._expObj=null,super.dispose(),this._eventHandler=null}_change(){null!=this._expObj&&(this._element.innerText=this._expObj.function(this._context))}}class M extends j{constructor(e,t,n,i,s){super(e,t,n,i,s),this._eventHandler=this._change.bind(this),this._expObj=crsbinding.expression.compile(i,null,{ctxName:this._ctxName});for(let e of this._expObj.parameters.properties)this.listenOnPath(e,this._eventHandler)}dispose(){crsbinding.expression.release(this._expObj),this._expObj=null,super.dispose(),this._eventHandler=null}_change(){if(null==this._expObj)return;const e=this._expObj.function(this._context);this._element.setAttribute(this._property,e)}}class D extends j{get ar(){return this._ar}set ar(e){null!=this._ar&&(crsbinding.events.removeOn(this._ar,"items-added",this._itemsAddedHandler),crsbinding.events.removeOn(this._ar,"items-deleted",this._itemsDeletedHandler)),this._ar=e,null!=this._ar&&(crsbinding.events.on(this._ar,"items-added",this._itemsAddedHandler),crsbinding.events.on(this._ar,"items-deleted",this._itemsDeletedHandler))}constructor(e,t,n,i,s){super(e,t,n,i,s),this._itemsAddedHandler=this._itemsAdded.bind(this),this._itemsDeletedHandler=this._itemsDeleted.bind(this)}dispose(){this.ar=null,crsbinding.expression.release(this._forExp),this._forExp=null,this._itemsAddedHandler=null,this._itemsDeletedHandler=null,this._singular=null,this._plural=null,this._container=null,this._collectionChangedHandler=null,super.dispose()}async initialize(){this._container=this._element.parentElement,this._container.removeChild(this._element);const e=this._value.split("of");this._singular=e[0].trim(),this._plural=e[1].trim();const t=R.split("_p").join(this._singular).split("_c").join("context"==this._ctxName?`context.${this._plural}`:this._plural);this._forExp=crsbinding.expression.compile(t,["callback"],{sanitize:!1,async:!0,ctxName:this._ctxName}),this._collectionChangedHandler=this._collectionChanged.bind(this),this.listenOnPath(this._plural,this._collectionChangedHandler)}async _collectionChanged(e,t){if(Array.isArray(t))this.ar=t;else{const e=new Function("context",`return context.${this._plural}`);this.ar=e(this._context)}null!=this.ar&&await this._renderItems()}async _renderItems(){if(await crsbinding.observation.releaseChildBinding(this._container),null==this.ar)return;const e=document.createDocumentFragment();await this._forExp.function(this._context,t=>{const n=this.createElement(t);e.appendChild(n)}),this._container.innerHTML="",this._container.appendChild(e),crsbinding.expression.updateUI(this.ar),null==this._container.__providers&&(this._container.__providers=[]),-1==this._container.__providers.indexOf(this.id)&&this._container.__providers.push(this.id)}_itemsAdded(e,t,n){for(let e=0;e<n.items.length;e++){const t=n.items[e],i=n.indexes[e],s=this.createElement(t),r=s.children[0],l=this._container.children[i];this._container.insertBefore(s,l);for(let e of r.__providers||[]){const t=crsbinding.providerManager.items.get(e);t instanceof M&&t._change()}}}_itemsDeleted(e,t,n){const i=[],s=e=>{const t=e.__uid;this._container.querySelectorAll([`[data-uid="${t}"]`]).forEach(e=>i.push(e))};if(Array.isArray(n))for(let e of n)s(e);else s(n);for(let e of i)null!=e&&(e.parentElement.removeChild(e),crsbinding.observation.releaseBinding(e))}createElement(e){const t=this._element.content.cloneNode(!0);crsbinding.parsers.parseElement(t,e,this._singular);for(let n of t.children)n.dataset.uid=e.__uid;return t}}const R="for (_p of _c || []) {callback(_p);}";class q extends j{constructor(e,t,n,i,s){super(e,t,n,i,s)}dispose(){crsbinding.expression.release(this._expObj),delete this._expObj,this._eventHandler=null,super.dispose()}async initialize(){this._eventHandler=this.propertyChanged.bind(this),-1==this._value.indexOf("?")?this._initCndAttr():-1!=this._value.indexOf(":")?this._initCndValue():this._initCndAttrValue(),this.propertyChanged()}_initCndAttr(){const e=crsbinding.expression.sanitize(this._value,this._ctxName),t=B.split("__exp__").join(e.expression).split("__attr__").join(this._property).split("__attr-value__").join(this._property);this._expObj=crsbinding.expression.compile(t,["element"],{sanitize:!1,ctxName:this._ctxName}),this.listenOnPath(e.properties,this._eventHandler)}_initCndValue(){const e=crsbinding.expression.sanitize(this._value,this._ctxName),t=e.expression.split("?"),n=t[1].split(":"),i=V.split("__exp__").join(t[0].trim()).split("__attr__").join(this._property).split("__true__").join(n[0].trim()).split("__false__").join(n[1].trim());this._expObj=crsbinding.expression.compile(i,["element"],{sanitize:!1,ctxName:this._ctxName}),this.listenOnPath(e.properties,this._eventHandler)}_initCndAttrValue(){const e=crsbinding.expression.sanitize(this._value,this._ctxName),t=e.expression.split("?"),n=B.split("__exp__").join(t[0].trim()).split("__attr__").join(this._property).split("__attr-value__").join(t[1].trim());this._expObj=crsbinding.expression.compile(n,["element"],{sanitize:!1,ctxName:this._ctxName}),this.listenOnPath(e.properties,this._eventHandler)}propertyChanged(){crsbinding.idleTaskManager.add(this._expObj.function(this._context,this._element))}}const B='\nif (__exp__) {\n element.setAttribute("__attr__", "__attr-value__");\n}\nelse {\n element.removeAttribute("__attr__");\n}\n',V='\nif (__exp__) {\n element.setAttribute("__attr__", "__true__");\n}\nelse {\n element.setAttribute("__attr__", "__false__");\n}\n';class U extends j{constructor(e,t,n,i,s){super(e,t,n,i,s)}dispose(){crsbinding.expression.release(this._expObj),delete this._expObj,this._eventHandler=null,super.dispose()}async initialize(){this._eventHandler=this.propertyChanged.bind(this);const e=this._value.split("?"),t=crsbinding.expression.sanitize(e[0],this._ctxName),n=t.expression,i=e[1].split(":"),s=i[0].trim(),r=i.length>1?i[1].trim():"[]",l=$.split("__property__").join(this._property).split("__exp__").join(n).split("__true__").join(s).split("__false__").join(r);this._expObj=crsbinding.expression.compile(l,["element"],{sanitize:!1,ctxName:this._ctxName}),this.listenOnPath(t.properties,this._eventHandler)}propertyChanged(){crsbinding.idleTaskManager.add(this._expObj.function(this._context,this._element))}}class Q extends j{constructor(e,t,n,i,s){super(e,t,n,i,s)}dispose(){crsbinding.expression.release(this._expObj),delete this._expObj,this._eventHandler=null,super.dispose()}async initialize(){this._eventHandler=this.propertyChanged.bind(this);const e=crsbinding.expression.sanitize(this._value,this._ctxName),t=e.expression.split("?"),n=t[0].trim(),i=t[1].split(":"),s=i[0].trim(),r=i.length>1?i[1].trim():'""',l=C.split("__property__").join(this._property).split("__exp__").join(n).split("__true__").join(s).split("__false__").join(r);this._expObj=crsbinding.expression.compile(l,["element"],{sanitize:!1,ctxName:this._ctxName}),this.listenOnPath(e.properties,this._eventHandler)}propertyChanged(){crsbinding.idleTaskManager.add(this._expObj.function(this._context,this._element))}}class S{static bind(e,t,n,i,s){return-1!=["value","checked"].indexOf(n)?new k(e,t,n,i,s):this["one-way"](e,t,n,i,s)}static"two-way"(e,t,n,i,s){return this.bind(e,t,n,i,s)}static"one-way"(e,t,n,i,s){return new z(e,t,n,i,s)}static once(e,t,n,i,s){return T(e,t,n,i,s)}static call(e,t,n,i,s){return new F(e,t,n,i,s)}static delegate(e,t,n,i,s){return new F(e,t,n,i,s)}static inner(e,t,n,i,s){return new I(e,t,n,i,s)}static for(e,t,n,i,s){return new D(e,t,n,i,s)}static if(e,t,n,i,s){return"classlist"==n.toLowerCase()?new U(e,t,n,i,s):-1!=n.toLowerCase().indexOf("style.")?new Q(e,t,n,i,s):new q(e,t,n,i,s)}static attr(e,t,n,i,s){return new M(e,t,n,i,s)}}function W(e,t,n="context"){for(let i of e||[])G(i,t,n)}function G(e,t,n="context"){W(e.children,t,n),function(e,t,n){for(let i of e)J(i,t,n)}(Array.from(e.attributes||[]).filter(e=>"TEMPLATE"==e.ownerElement.tagName&&"for"==e.name||-1!=e.name.indexOf(".")||0==(e.value||"").indexOf("${")),t,n),e.children&&0==e.children.length&&-1!=(e.innerText||"").indexOf("${")&&S.inner(e,t,null,null,n)}function J(e,t,n){const i=e.name.split(".");let s=2==i.length?i[0]:i.slice(0,i.length-1).join("."),r="for"==s?s:i[i.length-1];0==s.length&&"$"==e.value[0]&&(s=r,r="attr");const l=S[r](e.ownerElement,t,s,e.value,n);return e.ownerElement.removeAttribute(e.nodeName),l}function K(e){crsbinding.providerManager.releaseElement(e)}globalThis.requestIdleCallback=globalThis.requestIdleCallback||function(e){const t=Date.now();return setTimeout((function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-t))}})}),1)},globalThis.cancelIdleCallback=globalThis.cancelIdleCallback||function(e){clearTimeout(e)};function X(e){if(0==e.__isProxy)return;if(Array.isArray(e))return Y(e);const t=e.constructor.properties||Object.keys(e).filter(e=>-1==e.indexOf("__")&&"__isProxy"!=e);for(let n of t)crsbinding.events.notifyPropertyChanged(e,n),Array.isArray(e[n])&&Y(e[n])}function Y(e){e.forEach(e=>X(e))}function Z(e,t,n){crsbinding.events.on(e,t.trim(),n)}function ee(e,t){this.addEventListener(e,t),this._domEvents.push({event:e,callback:t})}function te(e,t){const n=this._domEvents.find(n=>n.event==e&&n.callback==t);null!=n&&(this.removeEventListener(n.event,n.callback),this._domEvents.splice(this._domEvents.indexOf(n),1),n.callback=null,n.event=null)}String.prototype.capitalize=function(){return this.charAt(0).toUpperCase()+this.slice(1)};const ne={_expFn:new Map,idleTaskManager:new class{constructor(){this.processing=!1,this._list=[]}dispose(){this._list=null}add(e){e&&this._list.push(e),!this.processing&&this._processQueue()}_processQueue(){if(null==requestIdleCallback)return this._runNextFunction();this.processing=!0,requestIdleCallback(e=>{for(;(e.timeRemaining()>0||e.didTimeout)&&this._list.length;)this._runNextFunction();this.processing=!1},{timeout:1e3})}_runNextFunction(){let e=this._list.shift();e&&e()}},providerManager:new class{constructor(){this._nextId=0,this.items=new Map}async register(e){e.id=this._nextId,null==e._element.__providers&&Reflect.set(e._element,"__providers",[]),e._element.__providers.push(this._nextId),this.items.set(this._nextId,e),this._nextId+=1}async releaseElement(e){for(let t of e.children||[])await this.releaseElement(t);if(null!=e.__providers){for(let t of e.__providers){const e=this.items.get(t);this.items.delete(t),e&&e.dispose()}e.__providers=null}}},expression:{sanitize:function(e,t="context"){const n="context"!=t,i=`${t}.`,s=function(e,t){let n=[],i=[],s=!1;for(let t=0;t<e.length;t++){const r=e[t];1==s&&"$"==r&&"{"==e[t+1]&&(s=!1),1==s?-1==y.indexOf(r)?i.push(r):(O(n,i,r),s=!1):-1!=g.indexOf(r)?(O(n,i,r),-1!=y.indexOf(r)&&(s=!0)):i.push(r)}i.length>0&&n.push(i.join(""));null!=t&&(n=function e(t,n){const i=t.indexOf(n);if(-1==i)return t;"."==t[i+1]&&(t.splice(i,2),-1!=t.indexOf(n)&&e(t,n));return t}(n,t));return n}(e,n?t:null);if(1==s.length)return{isLiteral:!1,expression:`${i}${s[0]}`,properties:[e]};const r=[],l=-1!=e.indexOf("${");let o=null,a=[],_=[];for(let e=0;e<s.length;e++){const t=s[e];-1!=b.indexOf(o)||-1!=g.indexOf(t)&&-1==v.indexOf(t)?(o=t,a.length>0&&(0!=l&&"}"!=o||isNaN(a)&&(_.push(e-a.length),r.push(m(`${a.join("")}`))),a.length=0)):(a.push(t),o=t)}n&&a.length>0&&(0!=l&&"}"!=o||isNaN(a)&&(_.push(s.length-1),r.push(m(`${a.join("")}`)))),0==_.length&&-1!=e.indexOf(".")&&_.push(0);for(let e=0;e<_.length;e++)s.splice(e+_[e],0,i);return{isLiteral:l,expression:s.join(""),properties:r}},compile:t,release:function(e){if(null==e||"object"!=typeof e)return;const t=e.parameters.expression;if(crsbinding._expFn.has(t)){const e=crsbinding._expFn.get(t);e.count-=1,0==e.count&&(e.function=null,e.parameters=null,crsbinding._expFn.delete(t))}},updateUI:X},observation:{observe:function(e,t){if(e[h]=!0,crsbinding.events.enableEvents(e),Array.isArray(e))return s(e);e[d]={},null!=t&&(e.__events=t.__events,delete t.__events);const n=Object.keys(e);for(let t of n)Array.isArray(e[t])&&(e[t]=s(e[t]));return new Proxy(e,{get:u,set:f})},releaseObserved:p,releaseBinding:K,releaseChildBinding:function(e){for(let t of e.children)K(t)}},parsers:{parseElement:G,parseElements:W},events:{enableEvents:function(e){e.__events=new Map,e.__conditions=new Map},disableEvents:function(e){null!=e.__events&&(e.__events.forEach(e=>{e.length=0}),e.__events.clear(),delete e.__events),e.__conditions&&(e.__conditions.forEach(e=>{delete e.fn,delete e.properties}),e.__conditions.clear(),delete e.__conditions)},when:function(e,n,i){let s=e.__events.get(n)||[];s=[...s,i],e.__events.set(n,s);const r=t(n);let l=e.__conditions.get(n);if(null==l){l={fn:()=>{if(1==r.function(e))for(let e of s)e()},properties:r.parameters.properties.slice(0)},e.__conditions.set(n,l)}const o=r.parameters.properties;for(let t of o)crsbinding.events.on(e,t,l.fn)},on:function(e,t,n){if(null==e||null==e.__events)return;let i=e.__events.get(t)||[];i=[...i,n],e.__events.set(t,i)},notifyPropertyChanged:function(e,t,n){if(null==e.__events||0==e.__events.has(t))return;const i=e.__events.get(t);for(let s of i)s(t,e[t],n);const s=`${t}Changed`;null!=e[s]&&e[s].call(e,n)},removeOn:n,removeWhen:function(e,t,n){crsbinding.events.removeOn(e,t,n);const i=e.__conditions.get(t);for(let t of i.properties)crsbinding.events.removeOn(e,t,i.fn);delete i.fn,delete i.properties,e.__conditions.delete(t)},listenOn:Z,listenOnPath:function(e,t,n){let i=e;const s=t.split(".");for(let e=0;e<s.length;e++){const t=s[e];e==s.length-1?Z(i,t,n):(null==i[t]&&(i[t]=crsbinding.observation.observe({})),Z(i,t,n),i=i[t])}}},dom:{enableEvents:function(e){e._domEvents=[],e.registerEvent=ee,e.unregisterEvent=te},disableEvents:function(e){if(null!=e._domEvents){for(let t of e._domEvents)t.callback=null,t.event=null;e._domEvents.length=0,delete e._domEvents,delete e.registerEvent,delete e.unregisterEvent}}},utils:{capitalizePropertyPath:function(e){const t=e.split("-");for(let e=1;e<t.length;e++)t[e]=t[e].capitalize();return t.join("")}}};globalThis.crsbinding=ne;export{ne as crsbinding}; |
@@ -1,168 +0,1 @@ | ||
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; | ||
function compileExp(exp, parameters, options) { | ||
parameters = parameters || []; | ||
let sanitize = true; | ||
let async = false; | ||
let ctxName = "context"; | ||
if (options != null) { | ||
if (options.sanitize != null) sanitize = options.sanitize; | ||
if (options.async != null) async = options.async; | ||
if (options.ctxName != null) ctxName = options.ctxName; | ||
} | ||
if (crsbinding._expFn.has(exp)) { | ||
const x = crsbinding._expFn.get(exp); | ||
x.count += 1; | ||
return x; | ||
} | ||
let src = exp; | ||
let san; | ||
if (sanitize == true) { | ||
san = crsbinding.expression.sanitize(exp, ctxName); | ||
if (crsbinding._expFn.has(san.expression)) { | ||
const x = crsbinding._expFn.get(san.expression); | ||
x.count += 1; | ||
return x; | ||
} | ||
src = san.isLiteral === true ? ["return `", san.expression, "`"].join("") : `return ${san.expression}`; | ||
} | ||
else { | ||
san = { | ||
expression: exp | ||
}; | ||
} | ||
const fn = async == true ? new AsyncFunction(ctxName, ...parameters, src) : new Function(ctxName, ...parameters, src); | ||
const result = { | ||
function: fn, | ||
parameters: san, | ||
count: 1 | ||
}; | ||
crsbinding._expFn.set(san.expression, result); | ||
return result; | ||
} | ||
function enableEvents(obj) { | ||
obj.__events = new Map(); | ||
obj.__conditions = new Map(); | ||
} | ||
function disableEvents(obj) { | ||
if (obj.__events != null) { | ||
obj.__events.forEach((ev) => { | ||
ev.length = 0; | ||
}); | ||
obj.__events.clear(); | ||
delete obj.__events; | ||
} | ||
if (obj.__conditions) { | ||
obj.__conditions.forEach((cnd) => { | ||
delete cnd.fn; | ||
delete cnd.properties; | ||
}); | ||
obj.__conditions.clear(); | ||
delete obj.__conditions; | ||
} | ||
} | ||
function when(obj, exp, callback) { | ||
let functions = obj.__events.get(exp) || []; | ||
functions = [...functions, callback]; | ||
obj.__events.set(exp, functions); | ||
const cmp = compileExp(exp); | ||
let cond = obj.__conditions.get(exp); | ||
if (cond == null) { | ||
const fn = () => { | ||
if (cmp.function(obj) == true) { | ||
for (let call of functions) { | ||
call(); | ||
} | ||
} | ||
}; | ||
cond = {fn: fn, properties: cmp.parameters.properties.slice(0)}; | ||
obj.__conditions.set(exp, cond); | ||
} | ||
const properties = cmp.parameters.properties; | ||
for (let property of properties) { | ||
crsbinding.events.on(obj, property, cond.fn); | ||
} | ||
} | ||
function removeWhen(obj, exp, callback) { | ||
crsbinding.events.removeOn(obj, exp, callback); | ||
const cnd = obj.__conditions.get(exp); | ||
for (let property of cnd.properties) { | ||
crsbinding.events.removeOn(obj, property, cnd.fn); | ||
} | ||
delete cnd.fn; | ||
delete cnd.properties; | ||
obj.__conditions.delete(exp); | ||
} | ||
function on(obj, property, callback) { | ||
if (obj == null || obj.__events == null) return; | ||
let functions = obj.__events.get(property) || []; | ||
functions = [...functions, callback]; | ||
obj.__events.set(property, functions); | ||
} | ||
function removeOn(obj, property, callback) { | ||
if (property.indexOf(".") != -1) { | ||
return removeOnPath(obj, property, callback); | ||
} | ||
if (obj == null || obj.__events == null) return; | ||
const functions = obj.__events.get(property) || []; | ||
const index = functions.indexOf(callback); | ||
if (index != -1) { | ||
functions.splice(index, 1); | ||
obj.__events.set(property, functions); | ||
} | ||
if (functions.length == 0) { | ||
obj.__events.delete(property); | ||
} | ||
} | ||
function removeOnPath(obj, property, callback) { | ||
const parts = property.split("."); | ||
for (let part of parts) { | ||
removeOn(obj, part, callback); | ||
obj = obj[part]; | ||
} | ||
} | ||
function notifyPropertyChanged(obj, property, args) { | ||
if (obj.__events == null || obj.__events.has(property) == false) return; | ||
const functions = obj.__events.get(property); | ||
for(let fn of functions) { | ||
fn(property, obj[property], args); | ||
} | ||
const changedFnName = `${property}Changed`; | ||
if (obj[changedFnName] != null) { | ||
obj[changedFnName].call(obj, args); | ||
} | ||
} | ||
export { disableEvents, enableEvents, notifyPropertyChanged, on, removeOn, removeWhen, when }; | ||
const e=Object.getPrototypeOf((async function(){})).constructor;function n(e){e.__events=new Map,e.__conditions=new Map}function t(e){null!=e.__events&&(e.__events.forEach(e=>{e.length=0}),e.__events.clear(),delete e.__events),e.__conditions&&(e.__conditions.forEach(e=>{delete e.fn,delete e.properties}),e.__conditions.clear(),delete e.__conditions)}function s(n,t,s){let i=n.__events.get(t)||[];i=[...i,s],n.__events.set(t,i);const o=function(n,t,s){t=t||[];let i=!0,o=!1,r="context";if(null!=s&&(null!=s.sanitize&&(i=s.sanitize),null!=s.async&&(o=s.async),null!=s.ctxName&&(r=s.ctxName)),crsbinding._expFn.has(n)){const e=crsbinding._expFn.get(n);return e.count+=1,e}let c,_=n;if(1==i){if(c=crsbinding.expression.sanitize(n,r),crsbinding._expFn.has(c.expression)){const e=crsbinding._expFn.get(c.expression);return e.count+=1,e}_=!0===c.isLiteral?["return `",c.expression,"`"].join(""):`return ${c.expression}`}else c={expression:n};const l={function:1==o?new e(r,...t,_):new Function(r,...t,_),parameters:c,count:1};return crsbinding._expFn.set(c.expression,l),l}(t);let r=n.__conditions.get(t);if(null==r){r={fn:()=>{if(1==o.function(n))for(let e of i)e()},properties:o.parameters.properties.slice(0)},n.__conditions.set(t,r)}const c=o.parameters.properties;for(let e of c)crsbinding.events.on(n,e,r.fn)}function i(e,n,t){crsbinding.events.removeOn(e,n,t);const s=e.__conditions.get(n);for(let n of s.properties)crsbinding.events.removeOn(e,n,s.fn);delete s.fn,delete s.properties,e.__conditions.delete(n)}function o(e,n,t){if(null==e||null==e.__events)return;let s=e.__events.get(n)||[];s=[...s,t],e.__events.set(n,s)}function r(e,n,t){if(-1!=n.indexOf("."))return function(e,n,t){const s=n.split(".");for(let n of s)r(e,n,t),e=e[n]}(e,n,t);if(null==e||null==e.__events)return;const s=e.__events.get(n)||[],i=s.indexOf(t);-1!=i&&(s.splice(i,1),e.__events.set(n,s)),0==s.length&&e.__events.delete(n)}function c(e,n,t){if(null==e.__events||0==e.__events.has(n))return;const s=e.__events.get(n);for(let i of s)i(n,e[n],t);const i=`${n}Changed`;null!=e[i]&&e[i].call(e,t)}export{t as disableEvents,n as enableEvents,c as notifyPropertyChanged,o as on,r as removeOn,i as removeWhen,s as when}; |
@@ -1,61 +0,1 @@ | ||
class ViewBase { | ||
static get properties() { | ||
return ["title"] | ||
} | ||
get title() { | ||
return this._title; | ||
} | ||
set title(newValue) { | ||
this._title = newValue; | ||
} | ||
get element() { | ||
return this._element; | ||
} | ||
set element(newValue) { | ||
if (newValue != null) { | ||
newValue.style.display = "none"; | ||
} | ||
this._element = newValue; | ||
} | ||
constructor(element) { | ||
this.element = element; | ||
} | ||
async connectedCallback() { | ||
this.__isProxy = true; | ||
crsbinding.events.enableEvents(this); | ||
crsbinding.parsers.parseElement(this.element, this); | ||
this._loaded(); | ||
} | ||
async disconnectedCallback() { | ||
crsbinding.observation.releaseBinding(this.element); | ||
crsbinding.events.disableEvents(this); | ||
} | ||
getProperty(prop) { | ||
let result = this[`_${prop}`]; | ||
if (result == null && this.getAttribute != null) { | ||
result = this.getAttribute(prop); | ||
} | ||
return result; | ||
} | ||
setProperty(prop, value) { | ||
this[`_${prop}`] = value; | ||
crsbinding.events.notifyPropertyChanged(this, prop); | ||
} | ||
_loaded() { | ||
crsbinding.expression.updateUI(this); | ||
this.element.style.display = "block"; | ||
} | ||
} | ||
export { ViewBase }; | ||
class e{static get properties(){return["title"]}get title(){return this._title}set title(e){this._title=e}get element(){return this._element}set element(e){null!=e&&(e.style.display="none"),this._element=e}constructor(e){this.element=e}async connectedCallback(){this.__isProxy=!0,crsbinding.events.enableEvents(this),crsbinding.parsers.parseElement(this.element,this),this._loaded()}async disconnectedCallback(){crsbinding.observation.releaseBinding(this.element),crsbinding.events.disableEvents(this)}getProperty(e){let t=this[`_${e}`];return null==t&&null!=this.getAttribute&&(t=this.getAttribute(e)),t}setProperty(e,t){this[`_${e}`]=t,crsbinding.events.notifyPropertyChanged(this,e)}_loaded(){crsbinding.expression.updateUI(this),this.element.style.display="block"}}export{e as ViewBase}; |
{ | ||
"name": "crs-binding", | ||
"version": "0.0.68", | ||
"version": "0.0.69", | ||
"description": "zero dependency binding engine", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
55419
106