Files
linkding/bookmarks/frontend/behaviors/index.js
Sascha Ißbrücker ffaaf0521d Speed up response times for certain actions (#829)
* return updated HTML from bookmark actions

* open details through URL

* fix details update

* improve modal behavior

* use a frame

* make behaviors properly destroy themselves

* remove page and details params from tag urls

* use separate behavior for details and tags

* remove separate details view

* make it work with other views

* add asset actions

* remove asset refresh for now

* remove details partial

* fix tests

* remove old partials

* update tests

* cache and reuse tags

* extract search autocomplete behavior

* remove details param from pagination

* fix tests

* only return details modal when navigating in frame

* fix link target

* remove unused behaviors

* use auto submit behavior for user select

* fix import
2024-09-16 12:48:19 +02:00

106 lines
2.5 KiB
JavaScript

const behaviorRegistry = {};
const debug = false;
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.removedNodes.forEach((node) => {
if (node instanceof HTMLElement && !node.isConnected) {
destroyBehaviors(node);
}
});
mutation.addedNodes.forEach((node) => {
if (node instanceof HTMLElement && node.isConnected) {
applyBehaviors(node);
}
});
});
});
document.addEventListener("turbo:load", () => {
mutationObserver.observe(document.body, {
childList: true,
subtree: true,
});
applyBehaviors(document.body);
});
document.addEventListener("turbo:before-cache", () => {
destroyBehaviors(document.body);
});
export class Behavior {
constructor(element) {
this.element = element;
}
destroy() {}
}
Behavior.interacting = false;
export function registerBehavior(name, behavior) {
behaviorRegistry[name] = behavior;
applyBehaviors(document, [name]);
}
export function applyBehaviors(container, behaviorNames = null) {
if (!behaviorNames) {
behaviorNames = Object.keys(behaviorRegistry);
}
behaviorNames.forEach((behaviorName) => {
const behavior = behaviorRegistry[behaviorName];
const elements = Array.from(
container.querySelectorAll(`[${behaviorName}]`),
);
// Include the container element if it has the behavior
if (container.hasAttribute && container.hasAttribute(behaviorName)) {
elements.push(container);
}
elements.forEach((element) => {
element.__behaviors = element.__behaviors || [];
const hasBehavior = element.__behaviors.some(
(b) => b instanceof behavior,
);
if (hasBehavior) {
return;
}
const behaviorInstance = new behavior(element);
element.__behaviors.push(behaviorInstance);
if (debug) {
console.log(
`[Behavior] ${behaviorInstance.constructor.name} initialized`,
);
}
});
});
}
export function destroyBehaviors(element) {
const behaviorNames = Object.keys(behaviorRegistry);
behaviorNames.forEach((behaviorName) => {
const elements = Array.from(element.querySelectorAll(`[${behaviorName}]`));
elements.push(element);
elements.forEach((element) => {
if (!element.__behaviors) {
return;
}
element.__behaviors.forEach((behavior) => {
behavior.destroy();
if (debug) {
console.log(`[Behavior] ${behavior.constructor.name} destroyed`);
}
});
delete element.__behaviors;
});
});
}