stimulus-value-bindings
Version:
One-way reactive DOM bindings for Stimulus JS
1,313 lines (1,289 loc) • 113 kB
JavaScript
let $b3e7e8c1a3c43eb7$var$stack = [];
function $b3e7e8c1a3c43eb7$export$bdd553fddd433dcb(callback = ()=>{}) {
queueMicrotask(()=>{
setTimeout(()=>$b3e7e8c1a3c43eb7$var$releaseNextTicks());
});
return new Promise((res)=>{
$b3e7e8c1a3c43eb7$var$stack.push(()=>{
callback();
res();
});
});
}
function $b3e7e8c1a3c43eb7$var$releaseNextTicks() {
while($b3e7e8c1a3c43eb7$var$stack.length)$b3e7e8c1a3c43eb7$var$stack.shift()();
}
function $8f9b49c1a83abf36$export$588732934346abbf(el, callback) {
let skip = false;
callback(el, ()=>skip = true);
if (skip) return;
let node = el.firstElementChild;
while(node){
$8f9b49c1a83abf36$export$588732934346abbf(node, callback, false);
node = node.nextElementSibling;
}
}
let $48a071f4e22bc27f$var$flushPending = false;
let $48a071f4e22bc27f$var$flushing = false;
let $48a071f4e22bc27f$var$queue = [];
let $48a071f4e22bc27f$var$lastFlushedIndex = -1;
function $48a071f4e22bc27f$export$fba1a0a20887772f(job) {
if (!$48a071f4e22bc27f$var$queue.includes(job)) $48a071f4e22bc27f$var$queue.push(job);
$48a071f4e22bc27f$var$queueFlush();
}
function $48a071f4e22bc27f$var$queueFlush() {
if (!$48a071f4e22bc27f$var$flushing && !$48a071f4e22bc27f$var$flushPending) {
$48a071f4e22bc27f$var$flushPending = true;
queueMicrotask($48a071f4e22bc27f$export$8ca066e62735a16c);
}
}
function $48a071f4e22bc27f$export$8ca066e62735a16c() {
$48a071f4e22bc27f$var$flushPending = false;
$48a071f4e22bc27f$var$flushing = true;
for(let i = 0; i < $48a071f4e22bc27f$var$queue.length; i++){
$48a071f4e22bc27f$var$queue[i]();
$48a071f4e22bc27f$var$lastFlushedIndex = i;
}
$48a071f4e22bc27f$var$queue.length = 0;
$48a071f4e22bc27f$var$lastFlushedIndex = -1;
$48a071f4e22bc27f$var$flushing = false;
}
function $42a4c9f2d525081f$export$7e6f8094deb93e61(controller, callback) {
const values = controller.constructor.values || {};
let observing = false;
const changeCallbacks = Object.keys(values).map((key)=>{
const callbackName = `${key}ValueChanged`;
const controllerCallback = controller[callbackName];
const monkeyPatchedCallback = function(value, previousValue) {
if (observing) callback(key, value, previousValue, this);
if (typeof controllerCallback === "function") controllerCallback.call(this, value, previousValue);
};
return [
callbackName,
monkeyPatchedCallback.bind(controller)
];
});
Object.assign(controller, Object.fromEntries(changeCallbacks));
return {
start () {
observing = true;
},
stop () {
observing = false;
}
};
}
function $9ac3f1e21fdbcee2$export$1530b8c0a3516a7d(controller, callback) {
let observing = false;
const { element: element } = controller;
const filterElementNodes = (nodes)=>Array.from(nodes).filter((node)=>node.nodeType !== 3);
const onMutate = (mutationList)=>{
const removedNodes = [];
const addedNodes = [];
mutationList.forEach((mutation)=>{
if (mutation.type === "childList") {
removedNodes.push(...filterElementNodes(mutation.removedNodes));
addedNodes.push(...filterElementNodes(mutation.addedNodes));
}
});
if (addedNodes.length || removedNodes.length) callback(addedNodes, removedNodes);
};
const observer = new MutationObserver(onMutate);
return {
start () {
if (!observing) {
observer.observe(element, {
childList: true,
subtree: true
});
observing = true;
}
},
stop () {
if (observing) {
const mutations = observer.takeRecords();
if (mutations.length > 0) onMutate(mutations);
observer.disconnect();
observing = false;
}
},
runWithoutObservation (callback) {
this.stop();
callback();
this.start();
}
};
}
const $e831555dc9bb4016$var$isObject = (value)=>{
const type = typeof value;
return value !== null && (type === 'object' || type === 'function');
};
const $e831555dc9bb4016$var$isEmptyObject = (value)=>$e831555dc9bb4016$var$isObject(value) && Object.keys(value).length === 0;
const $e831555dc9bb4016$var$disallowedKeys = new Set([
'__proto__',
'prototype',
'constructor'
]);
const $e831555dc9bb4016$var$digits = new Set('0123456789');
function $e831555dc9bb4016$var$getPathSegments(path) {
const parts = [];
let currentSegment = '';
let currentPart = 'start';
let isIgnoring = false;
for (const character of path)switch(character){
case '\\':
if (currentPart === 'index') throw new Error('Invalid character in an index');
if (currentPart === 'indexEnd') throw new Error('Invalid character after an index');
if (isIgnoring) currentSegment += character;
currentPart = 'property';
isIgnoring = !isIgnoring;
break;
case '.':
if (currentPart === 'index') throw new Error('Invalid character in an index');
if (currentPart === 'indexEnd') {
currentPart = 'property';
break;
}
if (isIgnoring) {
isIgnoring = false;
currentSegment += character;
break;
}
if ($e831555dc9bb4016$var$disallowedKeys.has(currentSegment)) return [];
parts.push(currentSegment);
currentSegment = '';
currentPart = 'property';
break;
case '[':
if (currentPart === 'index') throw new Error('Invalid character in an index');
if (currentPart === 'indexEnd') {
currentPart = 'index';
break;
}
if (isIgnoring) {
isIgnoring = false;
currentSegment += character;
break;
}
if (currentPart === 'property') {
if ($e831555dc9bb4016$var$disallowedKeys.has(currentSegment)) return [];
parts.push(currentSegment);
currentSegment = '';
}
currentPart = 'index';
break;
case ']':
if (currentPart === 'index') {
parts.push(Number.parseInt(currentSegment, 10));
currentSegment = '';
currentPart = 'indexEnd';
break;
}
if (currentPart === 'indexEnd') throw new Error('Invalid character after an index');
default:
if (currentPart === 'index' && !$e831555dc9bb4016$var$digits.has(character)) throw new Error('Invalid character in an index');
if (currentPart === 'indexEnd') throw new Error('Invalid character after an index');
if (currentPart === 'start') currentPart = 'property';
if (isIgnoring) {
isIgnoring = false;
currentSegment += '\\';
}
currentSegment += character;
}
if (isIgnoring) currentSegment += '\\';
switch(currentPart){
case 'property':
if ($e831555dc9bb4016$var$disallowedKeys.has(currentSegment)) return [];
parts.push(currentSegment);
break;
case 'index':
throw new Error('Index was not closed');
case 'start':
parts.push('');
break;
}
return parts;
}
function $e831555dc9bb4016$var$isStringIndex(object, key) {
if (typeof key !== 'number' && Array.isArray(object)) {
const index = Number.parseInt(key, 10);
return Number.isInteger(index) && object[index] === object[key];
}
return false;
}
function $e831555dc9bb4016$var$assertNotStringIndex(object, key) {
if ($e831555dc9bb4016$var$isStringIndex(object, key)) throw new Error('Cannot use string index');
}
function $e831555dc9bb4016$export$63ef76b19cf4a753(object, path, value) {
if (!$e831555dc9bb4016$var$isObject(object) || typeof path !== 'string') return value === undefined ? object : value;
const pathArray = $e831555dc9bb4016$var$getPathSegments(path);
if (pathArray.length === 0) return value;
for(let index = 0; index < pathArray.length; index++){
const key = pathArray[index];
if ($e831555dc9bb4016$var$isStringIndex(object, key)) object = index === pathArray.length - 1 ? undefined : null;
else object = object[key];
if (object === undefined || object === null) {
// `object` is either `undefined` or `null` so we want to stop the loop, and
// if this is not the last bit of the path, and
// if it didn't return `undefined`
// it would return `null` if `object` is `null`
// but we want `get({foo: null}, 'foo.bar')` to equal `undefined`, or the supplied value, not `null`
if (index !== pathArray.length - 1) return value;
break;
}
}
return object === undefined ? value : object;
}
function $e831555dc9bb4016$export$a41c68a4eb5ff164(object, path, value) {
if (!$e831555dc9bb4016$var$isObject(object) || typeof path !== 'string') return object;
const root = object;
const pathArray = $e831555dc9bb4016$var$getPathSegments(path);
for(let index = 0; index < pathArray.length; index++){
const key = pathArray[index];
$e831555dc9bb4016$var$assertNotStringIndex(object, key);
if (index === pathArray.length - 1) object[key] = value;
else if (!$e831555dc9bb4016$var$isObject(object[key])) object[key] = typeof pathArray[index + 1] === 'number' ? [] : {};
object = object[key];
}
return root;
}
function $e831555dc9bb4016$export$2fae62fb628b9c68(object, path) {
if (!$e831555dc9bb4016$var$isObject(object) || typeof path !== 'string') return false;
const pathArray = $e831555dc9bb4016$var$getPathSegments(path);
for(let index = 0; index < pathArray.length; index++){
const key = pathArray[index];
$e831555dc9bb4016$var$assertNotStringIndex(object, key);
if (index === pathArray.length - 1) {
delete object[key];
return true;
}
object = object[key];
if (!$e831555dc9bb4016$var$isObject(object)) return false;
}
}
function $e831555dc9bb4016$export$bf9617eaf5d2451(object, path) {
if (!$e831555dc9bb4016$var$isObject(object) || typeof path !== 'string') return false;
const pathArray = $e831555dc9bb4016$var$getPathSegments(path);
if (pathArray.length === 0) return false;
for (const key of pathArray){
if (!$e831555dc9bb4016$var$isObject(object) || !(key in object) || $e831555dc9bb4016$var$isStringIndex(object, key)) return false;
object = object[key];
}
return true;
}
function $e831555dc9bb4016$export$b36556ce4a09dde6(path) {
if (typeof path !== 'string') throw new TypeError('Expected a string');
return path.replaceAll(/[\\.[]/g, '\\$&');
}
// The keys returned by Object.entries() for arrays are strings
function $e831555dc9bb4016$var$entries(value) {
const result = Object.entries(value);
if (Array.isArray(value)) return result.map(([key, value])=>[
Number(key),
value
]);
return result;
}
function $e831555dc9bb4016$var$stringifyPath(pathSegments) {
let result = '';
for (let [index, segment] of $e831555dc9bb4016$var$entries(pathSegments))if (typeof segment === 'number') result += `[${segment}]`;
else {
segment = $e831555dc9bb4016$export$b36556ce4a09dde6(segment);
result += index === 0 ? segment : `.${segment}`;
}
return result;
}
function* $e831555dc9bb4016$var$deepKeysIterator(object, currentPath = []) {
if (!$e831555dc9bb4016$var$isObject(object) || $e831555dc9bb4016$var$isEmptyObject(object)) {
if (currentPath.length > 0) yield $e831555dc9bb4016$var$stringifyPath(currentPath);
return;
}
for (const [key, value] of $e831555dc9bb4016$var$entries(object))yield* $e831555dc9bb4016$var$deepKeysIterator(value, [
...currentPath,
key
]);
}
function $e831555dc9bb4016$export$13f626a1d0c23ea1(object) {
return [
...$e831555dc9bb4016$var$deepKeysIterator(object)
];
}
function $6bb642d3be92d590$export$2385a24977818dd0(element, name, value) {
switch(name){
case "all":
$6bb642d3be92d590$var$bindAll(element, value);
break;
case "text":
$6bb642d3be92d590$var$bindText(element, value);
break;
case "html":
$6bb642d3be92d590$var$bindHTML(element, value);
break;
case "checked":
case "selected":
$6bb642d3be92d590$var$bindAttributeAndProperty(element, name, value);
break;
default:
$6bb642d3be92d590$var$bindAttribute(element, name, value);
break;
}
}
function $6bb642d3be92d590$var$bindText(element, value) {
element.textContent = value;
}
function $6bb642d3be92d590$var$bindHTML(element, value) {
element.innerHTML = value;
}
function $6bb642d3be92d590$var$bindAttribute(el, name, value) {
if ([
null,
undefined,
false
].includes(value) && $6bb642d3be92d590$var$attributeShouldntBePreservedIfFalsy(name)) el.removeAttribute(name);
else {
if ($6bb642d3be92d590$var$isBooleanAttr(name)) value = name;
$6bb642d3be92d590$var$setIfChanged(el, name, value);
}
}
function $6bb642d3be92d590$var$bindAll(element, obj) {
Object.keys(obj).forEach((name)=>$6bb642d3be92d590$export$2385a24977818dd0(element, name, (0, $e831555dc9bb4016$export$63ef76b19cf4a753)(obj, name)));
}
function $6bb642d3be92d590$var$bindAttributeAndProperty(el, name, value) {
$6bb642d3be92d590$var$bindAttribute(el, name, value);
$6bb642d3be92d590$var$setPropertyIfChanged(el, name, value);
}
function $6bb642d3be92d590$var$setIfChanged(el, attrName, value) {
if (el.getAttribute(attrName) != value) el.setAttribute(attrName, value);
}
function $6bb642d3be92d590$var$setPropertyIfChanged(el, propName, value) {
if (el[propName] !== value) el[propName] = value;
}
// As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute
const $6bb642d3be92d590$var$booleanAttributes = new Set([
"allowfullscreen",
"async",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"defer",
"disabled",
"formnovalidate",
"inert",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"playsinline",
"readonly",
"required",
"reversed",
"selected"
]);
function $6bb642d3be92d590$var$isBooleanAttr(attrName) {
return $6bb642d3be92d590$var$booleanAttributes.has(attrName);
}
function $6bb642d3be92d590$var$attributeShouldntBePreservedIfFalsy(name) {
return ![
"aria-pressed",
"aria-checked",
"aria-expanded",
"aria-selected"
].includes(name);
}
function $438b9fc6d2bad1a9$export$816b23a2bc3d44ec(controller, callback) {
const bindings = $438b9fc6d2bad1a9$export$afc479602647d2a4(controller);
bindings.forEach((binding)=>{
let { node: node, name: name, path: path, negated: negated } = binding;
if (!controller.element.contains(node)) // clean up any bindings for elements that have been removed from the DOM
bindings.delete(binding);
else {
// Update bindings for the node
const value = (0, $e831555dc9bb4016$export$63ef76b19cf4a753)(controller, path);
(0, $6bb642d3be92d590$export$2385a24977818dd0)(node, name, negated ? !value : value);
node.removeAttribute("data-cloak");
}
});
if (typeof callback === "function") // Run the callback once all bindings have been updated.
callback();
}
function $438b9fc6d2bad1a9$export$2696433f89f63f2f(controller) {
if (!$438b9fc6d2bad1a9$var$bindingsAreInitialized(controller)) {
controller.__value_bindings = new Set();
$438b9fc6d2bad1a9$export$9d08f9cef6f4df8b(controller, controller.element);
}
}
function $438b9fc6d2bad1a9$export$9d08f9cef6f4df8b(controller, rootNode) {
const attrPrefix = `data-${controller.identifier}-bind`;
(0, $8f9b49c1a83abf36$export$588732934346abbf)(rootNode, (node)=>{
Array.from(node.attributes).filter(({ name: name })=>name.startsWith(attrPrefix)).forEach((attr)=>{
let negated = false;
let path = attr.value;
if (path.startsWith("!")) {
negated = true;
path = path.replace("!", "");
}
const name = attr.name === attrPrefix ? "all" : attr.name.replace(`${attrPrefix}-`, "");
$438b9fc6d2bad1a9$export$794005cd6f1aea3(controller, node, name, path, negated);
node.removeAttribute(attr.name);
});
});
}
function $438b9fc6d2bad1a9$export$317a120ffaa434e1(controller) {
$438b9fc6d2bad1a9$export$b7c6f809f4c7570b(controller);
$438b9fc6d2bad1a9$export$2696433f89f63f2f(controller);
}
function $438b9fc6d2bad1a9$export$794005cd6f1aea3(controller, node, name, path, negated) {
$438b9fc6d2bad1a9$export$afc479602647d2a4(controller).add({
node: node,
name: name,
path: path,
negated: negated
});
}
function $438b9fc6d2bad1a9$export$3eff236524896414(controller, node) {
const bindings = $438b9fc6d2bad1a9$export$afc479602647d2a4(controller);
bindings.forEach((binding)=>{
if (binding.node === node) bindings.delete(binding);
});
}
function $438b9fc6d2bad1a9$export$b7c6f809f4c7570b(controller) {
controller.__value_bindings?.clear();
controller.__value_bindings = new Set();
}
function $438b9fc6d2bad1a9$export$afc479602647d2a4(controller) {
return controller.__value_bindings;
}
function $438b9fc6d2bad1a9$var$bindingsAreInitialized(controller) {
return controller.__value_bindings instanceof Set;
}
const $0c4a772011edf2b8$export$d8d8c48ace6d5d1b = (controller)=>{
let initialUpdateHasRun = false;
const updateBindingsAndNotify = ()=>{
(0, $438b9fc6d2bad1a9$export$816b23a2bc3d44ec)(controller, ()=>{
if (typeof controller.bindingsUpdated === "function") controller.bindingsUpdated(!initialUpdateHasRun);
});
initialUpdateHasRun = true;
};
const scheduleUpdate = ()=>(0, $48a071f4e22bc27f$export$fba1a0a20887772f)(updateBindingsAndNotify);
const valuesObserver = (0, $42a4c9f2d525081f$export$7e6f8094deb93e61)(controller, scheduleUpdate);
const treeObserver = (0, $9ac3f1e21fdbcee2$export$1530b8c0a3516a7d)(controller, (addedNodes, removedNodes)=>{
removedNodes.forEach((node)=>(0, $438b9fc6d2bad1a9$export$3eff236524896414)(controller, node));
addedNodes.forEach((node)=>(0, $438b9fc6d2bad1a9$export$9d08f9cef6f4df8b)(controller, node));
treeObserver.runWithoutObservation(updateBindingsAndNotify);
});
(0, $438b9fc6d2bad1a9$export$2696433f89f63f2f)(controller);
scheduleUpdate();
const disconnect = controller.disconnect;
Object.assign(controller, {
updateBindings: scheduleUpdate,
disconnect () {
valuesObserver.stop();
treeObserver.stop();
(0, $438b9fc6d2bad1a9$export$b7c6f809f4c7570b)(controller);
if (typeof disconnect === "function") disconnect.bind(controller)();
}
});
treeObserver.start();
valuesObserver.start();
};
/*
Stimulus 3.2.1
Copyright © 2023 Basecamp, LLC
*/ class $861a37e0262dfc28$var$EventListener {
constructor(eventTarget, eventName, eventOptions){
this.eventTarget = eventTarget;
this.eventName = eventName;
this.eventOptions = eventOptions;
this.unorderedBindings = new Set();
}
connect() {
this.eventTarget.addEventListener(this.eventName, this, this.eventOptions);
}
disconnect() {
this.eventTarget.removeEventListener(this.eventName, this, this.eventOptions);
}
bindingConnected(binding) {
this.unorderedBindings.add(binding);
}
bindingDisconnected(binding) {
this.unorderedBindings.delete(binding);
}
handleEvent(event) {
const extendedEvent = $861a37e0262dfc28$var$extendEvent(event);
for (const binding of this.bindings){
if (extendedEvent.immediatePropagationStopped) break;
else binding.handleEvent(extendedEvent);
}
}
hasBindings() {
return this.unorderedBindings.size > 0;
}
get bindings() {
return Array.from(this.unorderedBindings).sort((left, right)=>{
const leftIndex = left.index, rightIndex = right.index;
return leftIndex < rightIndex ? -1 : leftIndex > rightIndex ? 1 : 0;
});
}
}
function $861a37e0262dfc28$var$extendEvent(event) {
if ("immediatePropagationStopped" in event) return event;
else {
const { stopImmediatePropagation: stopImmediatePropagation } = event;
return Object.assign(event, {
immediatePropagationStopped: false,
stopImmediatePropagation () {
this.immediatePropagationStopped = true;
stopImmediatePropagation.call(this);
}
});
}
}
class $861a37e0262dfc28$var$Dispatcher {
constructor(application){
this.application = application;
this.eventListenerMaps = new Map();
this.started = false;
}
start() {
if (!this.started) {
this.started = true;
this.eventListeners.forEach((eventListener)=>eventListener.connect());
}
}
stop() {
if (this.started) {
this.started = false;
this.eventListeners.forEach((eventListener)=>eventListener.disconnect());
}
}
get eventListeners() {
return Array.from(this.eventListenerMaps.values()).reduce((listeners, map)=>listeners.concat(Array.from(map.values())), []);
}
bindingConnected(binding) {
this.fetchEventListenerForBinding(binding).bindingConnected(binding);
}
bindingDisconnected(binding, clearEventListeners = false) {
this.fetchEventListenerForBinding(binding).bindingDisconnected(binding);
if (clearEventListeners) this.clearEventListenersForBinding(binding);
}
handleError(error, message, detail = {}) {
this.application.handleError(error, `Error ${message}`, detail);
}
clearEventListenersForBinding(binding) {
const eventListener = this.fetchEventListenerForBinding(binding);
if (!eventListener.hasBindings()) {
eventListener.disconnect();
this.removeMappedEventListenerFor(binding);
}
}
removeMappedEventListenerFor(binding) {
const { eventTarget: eventTarget, eventName: eventName, eventOptions: eventOptions } = binding;
const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);
const cacheKey = this.cacheKey(eventName, eventOptions);
eventListenerMap.delete(cacheKey);
if (eventListenerMap.size == 0) this.eventListenerMaps.delete(eventTarget);
}
fetchEventListenerForBinding(binding) {
const { eventTarget: eventTarget, eventName: eventName, eventOptions: eventOptions } = binding;
return this.fetchEventListener(eventTarget, eventName, eventOptions);
}
fetchEventListener(eventTarget, eventName, eventOptions) {
const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);
const cacheKey = this.cacheKey(eventName, eventOptions);
let eventListener = eventListenerMap.get(cacheKey);
if (!eventListener) {
eventListener = this.createEventListener(eventTarget, eventName, eventOptions);
eventListenerMap.set(cacheKey, eventListener);
}
return eventListener;
}
createEventListener(eventTarget, eventName, eventOptions) {
const eventListener = new $861a37e0262dfc28$var$EventListener(eventTarget, eventName, eventOptions);
if (this.started) eventListener.connect();
return eventListener;
}
fetchEventListenerMapForEventTarget(eventTarget) {
let eventListenerMap = this.eventListenerMaps.get(eventTarget);
if (!eventListenerMap) {
eventListenerMap = new Map();
this.eventListenerMaps.set(eventTarget, eventListenerMap);
}
return eventListenerMap;
}
cacheKey(eventName, eventOptions) {
const parts = [
eventName
];
Object.keys(eventOptions).sort().forEach((key)=>{
parts.push(`${eventOptions[key] ? "" : "!"}${key}`);
});
return parts.join(":");
}
}
const $861a37e0262dfc28$var$defaultActionDescriptorFilters = {
stop ({ event: event, value: value }) {
if (value) event.stopPropagation();
return true;
},
prevent ({ event: event, value: value }) {
if (value) event.preventDefault();
return true;
},
self ({ event: event, value: value, element: element }) {
if (value) return element === event.target;
else return true;
}
};
const $861a37e0262dfc28$var$descriptorPattern = /^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;
function $861a37e0262dfc28$var$parseActionDescriptorString(descriptorString) {
const source = descriptorString.trim();
const matches = source.match($861a37e0262dfc28$var$descriptorPattern) || [];
let eventName = matches[2];
let keyFilter = matches[3];
if (keyFilter && ![
"keydown",
"keyup",
"keypress"
].includes(eventName)) {
eventName += `.${keyFilter}`;
keyFilter = "";
}
return {
eventTarget: $861a37e0262dfc28$var$parseEventTarget(matches[4]),
eventName: eventName,
eventOptions: matches[7] ? $861a37e0262dfc28$var$parseEventOptions(matches[7]) : {},
identifier: matches[5],
methodName: matches[6],
keyFilter: matches[1] || keyFilter
};
}
function $861a37e0262dfc28$var$parseEventTarget(eventTargetName) {
if (eventTargetName == "window") return window;
else if (eventTargetName == "document") return document;
}
function $861a37e0262dfc28$var$parseEventOptions(eventOptions) {
return eventOptions.split(":").reduce((options, token)=>Object.assign(options, {
[token.replace(/^!/, "")]: !/^!/.test(token)
}), {});
}
function $861a37e0262dfc28$var$stringifyEventTarget(eventTarget) {
if (eventTarget == window) return "window";
else if (eventTarget == document) return "document";
}
function $861a37e0262dfc28$var$camelize(value) {
return value.replace(/(?:[_-])([a-z0-9])/g, (_, char)=>char.toUpperCase());
}
function $861a37e0262dfc28$var$namespaceCamelize(value) {
return $861a37e0262dfc28$var$camelize(value.replace(/--/g, "-").replace(/__/g, "_"));
}
function $861a37e0262dfc28$var$capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}
function $861a37e0262dfc28$var$dasherize(value) {
return value.replace(/([A-Z])/g, (_, char)=>`-${char.toLowerCase()}`);
}
function $861a37e0262dfc28$var$tokenize(value) {
return value.match(/[^\s]+/g) || [];
}
function $861a37e0262dfc28$var$isSomething(object) {
return object !== null && object !== undefined;
}
function $861a37e0262dfc28$var$hasProperty(object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
}
const $861a37e0262dfc28$var$allModifiers = [
"meta",
"ctrl",
"alt",
"shift"
];
class $861a37e0262dfc28$var$Action {
constructor(element, index, descriptor, schema){
this.element = element;
this.index = index;
this.eventTarget = descriptor.eventTarget || element;
this.eventName = descriptor.eventName || $861a37e0262dfc28$var$getDefaultEventNameForElement(element) || $861a37e0262dfc28$var$error("missing event name");
this.eventOptions = descriptor.eventOptions || {};
this.identifier = descriptor.identifier || $861a37e0262dfc28$var$error("missing identifier");
this.methodName = descriptor.methodName || $861a37e0262dfc28$var$error("missing method name");
this.keyFilter = descriptor.keyFilter || "";
this.schema = schema;
}
static forToken(token, schema) {
return new this(token.element, token.index, $861a37e0262dfc28$var$parseActionDescriptorString(token.content), schema);
}
toString() {
const eventFilter = this.keyFilter ? `.${this.keyFilter}` : "";
const eventTarget = this.eventTargetName ? `@${this.eventTargetName}` : "";
return `${this.eventName}${eventFilter}${eventTarget}->${this.identifier}#${this.methodName}`;
}
shouldIgnoreKeyboardEvent(event) {
if (!this.keyFilter) return false;
const filters = this.keyFilter.split("+");
if (this.keyFilterDissatisfied(event, filters)) return true;
const standardFilter = filters.filter((key)=>!$861a37e0262dfc28$var$allModifiers.includes(key))[0];
if (!standardFilter) return false;
if (!$861a37e0262dfc28$var$hasProperty(this.keyMappings, standardFilter)) $861a37e0262dfc28$var$error(`contains unknown key filter: ${this.keyFilter}`);
return this.keyMappings[standardFilter].toLowerCase() !== event.key.toLowerCase();
}
shouldIgnoreMouseEvent(event) {
if (!this.keyFilter) return false;
const filters = [
this.keyFilter
];
if (this.keyFilterDissatisfied(event, filters)) return true;
return false;
}
get params() {
const params = {};
const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, "i");
for (const { name: name, value: value } of Array.from(this.element.attributes)){
const match = name.match(pattern);
const key = match && match[1];
if (key) params[$861a37e0262dfc28$var$camelize(key)] = $861a37e0262dfc28$var$typecast(value);
}
return params;
}
get eventTargetName() {
return $861a37e0262dfc28$var$stringifyEventTarget(this.eventTarget);
}
get keyMappings() {
return this.schema.keyMappings;
}
keyFilterDissatisfied(event, filters) {
const [meta, ctrl, alt, shift] = $861a37e0262dfc28$var$allModifiers.map((modifier)=>filters.includes(modifier));
return event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift;
}
}
const $861a37e0262dfc28$var$defaultEventNames = {
a: ()=>"click",
button: ()=>"click",
form: ()=>"submit",
details: ()=>"toggle",
input: (e)=>e.getAttribute("type") == "submit" ? "click" : "input",
select: ()=>"change",
textarea: ()=>"input"
};
function $861a37e0262dfc28$var$getDefaultEventNameForElement(element) {
const tagName = element.tagName.toLowerCase();
if (tagName in $861a37e0262dfc28$var$defaultEventNames) return $861a37e0262dfc28$var$defaultEventNames[tagName](element);
}
function $861a37e0262dfc28$var$error(message) {
throw new Error(message);
}
function $861a37e0262dfc28$var$typecast(value) {
try {
return JSON.parse(value);
} catch (o_O) {
return value;
}
}
class $861a37e0262dfc28$var$Binding {
constructor(context, action){
this.context = context;
this.action = action;
}
get index() {
return this.action.index;
}
get eventTarget() {
return this.action.eventTarget;
}
get eventOptions() {
return this.action.eventOptions;
}
get identifier() {
return this.context.identifier;
}
handleEvent(event) {
const actionEvent = this.prepareActionEvent(event);
if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(actionEvent)) this.invokeWithEvent(actionEvent);
}
get eventName() {
return this.action.eventName;
}
get method() {
const method = this.controller[this.methodName];
if (typeof method == "function") return method;
throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`);
}
applyEventModifiers(event) {
const { element: element } = this.action;
const { actionDescriptorFilters: actionDescriptorFilters } = this.context.application;
const { controller: controller } = this.context;
let passes = true;
for (const [name, value] of Object.entries(this.eventOptions)){
if (name in actionDescriptorFilters) {
const filter = actionDescriptorFilters[name];
passes = passes && filter({
name: name,
value: value,
event: event,
element: element,
controller: controller
});
} else continue;
}
return passes;
}
prepareActionEvent(event) {
return Object.assign(event, {
params: this.action.params
});
}
invokeWithEvent(event) {
const { target: target, currentTarget: currentTarget } = event;
try {
this.method.call(this.controller, event);
this.context.logDebugActivity(this.methodName, {
event: event,
target: target,
currentTarget: currentTarget,
action: this.methodName
});
} catch (error) {
const { identifier: identifier, controller: controller, element: element, index: index } = this;
const detail = {
identifier: identifier,
controller: controller,
element: element,
index: index,
event: event
};
this.context.handleError(error, `invoking action "${this.action}"`, detail);
}
}
willBeInvokedByEvent(event) {
const eventTarget = event.target;
if (event instanceof KeyboardEvent && this.action.shouldIgnoreKeyboardEvent(event)) return false;
if (event instanceof MouseEvent && this.action.shouldIgnoreMouseEvent(event)) return false;
if (this.element === eventTarget) return true;
else if (eventTarget instanceof Element && this.element.contains(eventTarget)) return this.scope.containsElement(eventTarget);
else return this.scope.containsElement(this.action.element);
}
get controller() {
return this.context.controller;
}
get methodName() {
return this.action.methodName;
}
get element() {
return this.scope.element;
}
get scope() {
return this.context.scope;
}
}
class $861a37e0262dfc28$export$12e07a2a9f87578a {
constructor(element, delegate){
this.mutationObserverInit = {
attributes: true,
childList: true,
subtree: true
};
this.element = element;
this.started = false;
this.delegate = delegate;
this.elements = new Set();
this.mutationObserver = new MutationObserver((mutations)=>this.processMutations(mutations));
}
start() {
if (!this.started) {
this.started = true;
this.mutationObserver.observe(this.element, this.mutationObserverInit);
this.refresh();
}
}
pause(callback) {
if (this.started) {
this.mutationObserver.disconnect();
this.started = false;
}
callback();
if (!this.started) {
this.mutationObserver.observe(this.element, this.mutationObserverInit);
this.started = true;
}
}
stop() {
if (this.started) {
this.mutationObserver.takeRecords();
this.mutationObserver.disconnect();
this.started = false;
}
}
refresh() {
if (this.started) {
const matches = new Set(this.matchElementsInTree());
for (const element of Array.from(this.elements))if (!matches.has(element)) this.removeElement(element);
for (const element of Array.from(matches))this.addElement(element);
}
}
processMutations(mutations) {
if (this.started) for (const mutation of mutations)this.processMutation(mutation);
}
processMutation(mutation) {
if (mutation.type == "attributes") this.processAttributeChange(mutation.target, mutation.attributeName);
else if (mutation.type == "childList") {
this.processRemovedNodes(mutation.removedNodes);
this.processAddedNodes(mutation.addedNodes);
}
}
processAttributeChange(element, attributeName) {
if (this.elements.has(element)) {
if (this.delegate.elementAttributeChanged && this.matchElement(element)) this.delegate.elementAttributeChanged(element, attributeName);
else this.removeElement(element);
} else if (this.matchElement(element)) this.addElement(element);
}
processRemovedNodes(nodes) {
for (const node of Array.from(nodes)){
const element = this.elementFromNode(node);
if (element) this.processTree(element, this.removeElement);
}
}
processAddedNodes(nodes) {
for (const node of Array.from(nodes)){
const element = this.elementFromNode(node);
if (element && this.elementIsActive(element)) this.processTree(element, this.addElement);
}
}
matchElement(element) {
return this.delegate.matchElement(element);
}
matchElementsInTree(tree = this.element) {
return this.delegate.matchElementsInTree(tree);
}
processTree(tree, processor) {
for (const element of this.matchElementsInTree(tree))processor.call(this, element);
}
elementFromNode(node) {
if (node.nodeType == Node.ELEMENT_NODE) return node;
}
elementIsActive(element) {
if (element.isConnected != this.element.isConnected) return false;
else return this.element.contains(element);
}
addElement(element) {
if (!this.elements.has(element)) {
if (this.elementIsActive(element)) {
this.elements.add(element);
if (this.delegate.elementMatched) this.delegate.elementMatched(element);
}
}
}
removeElement(element) {
if (this.elements.has(element)) {
this.elements.delete(element);
if (this.delegate.elementUnmatched) this.delegate.elementUnmatched(element);
}
}
}
class $861a37e0262dfc28$export$fe68319d413d05cb {
constructor(element, attributeName, delegate){
this.attributeName = attributeName;
this.delegate = delegate;
this.elementObserver = new $861a37e0262dfc28$export$12e07a2a9f87578a(element, this);
}
get element() {
return this.elementObserver.element;
}
get selector() {
return `[${this.attributeName}]`;
}
start() {
this.elementObserver.start();
}
pause(callback) {
this.elementObserver.pause(callback);
}
stop() {
this.elementObserver.stop();
}
refresh() {
this.elementObserver.refresh();
}
get started() {
return this.elementObserver.started;
}
matchElement(element) {
return element.hasAttribute(this.attributeName);
}
matchElementsInTree(tree) {
const match = this.matchElement(tree) ? [
tree
] : [];
const matches = Array.from(tree.querySelectorAll(this.selector));
return match.concat(matches);
}
elementMatched(element) {
if (this.delegate.elementMatchedAttribute) this.delegate.elementMatchedAttribute(element, this.attributeName);
}
elementUnmatched(element) {
if (this.delegate.elementUnmatchedAttribute) this.delegate.elementUnmatchedAttribute(element, this.attributeName);
}
elementAttributeChanged(element, attributeName) {
if (this.delegate.elementAttributeValueChanged && this.attributeName == attributeName) this.delegate.elementAttributeValueChanged(element, attributeName);
}
}
function $861a37e0262dfc28$export$e16d8520af44a096(map, key, value) {
$861a37e0262dfc28$export$e7aa7bc5c1b3cfb3(map, key).add(value);
}
function $861a37e0262dfc28$export$1d2f21e549771e67(map, key, value) {
$861a37e0262dfc28$export$e7aa7bc5c1b3cfb3(map, key).delete(value);
$861a37e0262dfc28$export$d6cf75919f12ca5a(map, key);
}
function $861a37e0262dfc28$export$e7aa7bc5c1b3cfb3(map, key) {
let values = map.get(key);
if (!values) {
values = new Set();
map.set(key, values);
}
return values;
}
function $861a37e0262dfc28$export$d6cf75919f12ca5a(map, key) {
const values = map.get(key);
if (values != null && values.size == 0) map.delete(key);
}
class $861a37e0262dfc28$export$8bd4ad37b76db6ba {
constructor(){
this.valuesByKey = new Map();
}
get keys() {
return Array.from(this.valuesByKey.keys());
}
get values() {
const sets = Array.from(this.valuesByKey.values());
return sets.reduce((values, set)=>values.concat(Array.from(set)), []);
}
get size() {
const sets = Array.from(this.valuesByKey.values());
return sets.reduce((size, set)=>size + set.size, 0);
}
add(key, value) {
$861a37e0262dfc28$export$e16d8520af44a096(this.valuesByKey, key, value);
}
delete(key, value) {
$861a37e0262dfc28$export$1d2f21e549771e67(this.valuesByKey, key, value);
}
has(key, value) {
const values = this.valuesByKey.get(key);
return values != null && values.has(value);
}
hasKey(key) {
return this.valuesByKey.has(key);
}
hasValue(value) {
const sets = Array.from(this.valuesByKey.values());
return sets.some((set)=>set.has(value));
}
getValuesForKey(key) {
const values = this.valuesByKey.get(key);
return values ? Array.from(values) : [];
}
getKeysForValue(value) {
return Array.from(this.valuesByKey).filter(([_key, values])=>values.has(value)).map(([key, _values])=>key);
}
}
class $861a37e0262dfc28$export$a7c3d2c2552a674d extends $861a37e0262dfc28$export$8bd4ad37b76db6ba {
constructor(){
super();
this.keysByValue = new Map();
}
get values() {
return Array.from(this.keysByValue.keys());
}
add(key, value) {
super.add(key, value);
$861a37e0262dfc28$export$e16d8520af44a096(this.keysByValue, value, key);
}
delete(key, value) {
super.delete(key, value);
$861a37e0262dfc28$export$1d2f21e549771e67(this.keysByValue, value, key);
}
hasValue(value) {
return this.keysByValue.has(value);
}
getKeysForValue(value) {
const set = this.keysByValue.get(value);
return set ? Array.from(set) : [];
}
}
class $861a37e0262dfc28$export$116e0b48509995b {
constructor(element, selector, delegate, details){
this._selector = selector;
this.details = details;
this.elementObserver = new $861a37e0262dfc28$export$12e07a2a9f87578a(element, this);
this.delegate = delegate;
this.matchesByElement = new $861a37e0262dfc28$export$8bd4ad37b76db6ba();
}
get started() {
return this.elementObserver.started;
}
get selector() {
return this._selector;
}
set selector(selector) {
this._selector = selector;
this.refresh();
}
start() {
this.elementObserver.start();
}
pause(callback) {
this.elementObserver.pause(callback);
}
stop() {
this.elementObserver.stop();
}
refresh() {
this.elementObserver.refresh();
}
get element() {
return this.elementObserver.element;
}
matchElement(element) {
const { selector: selector } = this;
if (selector) {
const matches = element.matches(selector);
if (this.delegate.selectorMatchElement) return matches && this.delegate.selectorMatchElement(element, this.details);
return matches;
} else return false;
}
matchElementsInTree(tree) {
const { selector: selector } = this;
if (selector) {
const match = this.matchElement(tree) ? [
tree
] : [];
const matches = Array.from(tree.querySelectorAll(selector)).filter((match)=>this.matchElement(match));
return match.concat(matches);
} else return [];
}
elementMatched(element) {
const { selector: selector } = this;
if (selector) this.selectorMatched(element, selector);
}
elementUnmatched(element) {
const selectors = this.matchesByElement.getKeysForValue(element);
for (const selector of selectors)this.selectorUnmatched(element, selector);
}
elementAttributeChanged(element, _attributeName) {
const { selector: selector } = this;
if (selector) {
const matches = this.matchElement(element);
const matchedBefore = this.matchesByElement.has(selector, element);
if (matches && !matchedBefore) this.selectorMatched(element, selector);
else if (!matches && matchedBefore) this.selectorUnmatched(element, selector);
}
}
selectorMatched(element, selector) {
this.delegate.selectorMatched(element, selector, this.details);
this.matchesByElement.add(selector, element);
}
selectorUnmatched(element, selector) {
this.delegate.selectorUnmatched(element, selector, this.details);
this.matchesByElement.delete(selector, element);
}
}
class $861a37e0262dfc28$export$da226bebbf7f6caa {
constructor(element, delegate){
this.element = element;
this.delegate = delegate;
this.started = false;
this.stringMap = new Map();
this.mutationObserver = new MutationObserver((mutations)=>this.processMutations(mutations));
}
start() {
if (!this.started) {
this.started = true;
this.mutationObserver.observe(this.element, {
attributes: true,
attributeOldValue: true
});
this.refresh();
}
}
stop() {
if (this.started) {
this.mutationObserver.takeRecords();
this.mutationObserver.disconnect();
this.started = false;
}
}
refresh() {
if (this.started) for (const attributeName of this.knownAttributeNames)this.refreshAttribute(attributeName, null);
}
processMutations(mutations) {
if (this.started) for (const mutation of mutations)this.processMutation(mutation);
}
processMutation(mutation) {
const attributeName = mutation.attributeName;
if (attributeName) this.refreshAttribute(attributeName, mutation.oldValue);
}
refreshAttribute(attributeName, oldValue) {
const key = this.delegate.getStringMapKeyForAttribute(attributeName);
if (key != null) {
if (!this.stringMap.has(attributeName)) this.stringMapKeyAdded(key, attributeName);
const value = this.element.getAttribute(attributeName);
if (this.stringMap.get(attributeName) != value) this.stringMapValueChanged(value, key, oldValue);
if (value == null) {
const oldValue = this.stringMap.get(attributeName);
this.stringMap.delete(attributeName);
if (oldValue) this.stringMapKeyRemoved(key, attributeName, oldValue);
} else this.stringMap.set(attributeName, value);
}
}
stringMapKeyAdded(key, attributeName) {
if (this.delegate.stringMapKeyAdded) this.delegate.stringMapKeyAdded(key, attributeName);
}
stringMapValueChanged(value, key, oldValue) {
if (this.delegate.stringMapValueChanged) this.delegate.stringMapValueChanged(value, key, oldValue);
}
stringMapKeyRemoved(key, attributeName, oldValue) {
if (this.delegate.stringMapKeyRemoved) this.delegate.stringMapKeyRemoved(key, attributeName, oldValue);
}
get knownAttributeNames() {
return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)));
}
get currentAttributeNames() {
return Array.from(this.element.attributes).map((attribute)=>attribute.name);
}
get recordedAttributeNames() {
return Array.from(this.stringMap.keys());
}
}
class $861a37e0262dfc28$export$3aa21c2f03ef6b3b {
constructor(element, attributeName, delegate){
this.attributeObserver = new $861a37e0262dfc28$export$fe68319d413d05cb(element, attributeName, this);
this.delegate = delegate;
this.tokensByElement = new $861a37e0262dfc28$export$8bd4ad37b76db6ba();
}
get started() {
return this.attributeObserver.started;
}
start() {
this.attributeObserver.start();
}
pause(callback) {
this.attributeObserver.pause(callback);
}
stop() {
this.attributeObserver.stop();
}
refresh() {
this.attributeObserver.refresh();
}
get element() {
return this.attributeObserver.element;
}
get attributeName() {
return this.attributeObserver.attributeName;
}
elementMatchedAttribute(element) {
this.tokensMatched(this