diff --git a/application/source/dom/customelement.mjs b/application/source/dom/customelement.mjs index 7e7d86f88dacb36367f26313187e6991205feccd..858cfd824efa4ab68517e3a059116b00abfb7a1f 100644 --- a/application/source/dom/customelement.mjs +++ b/application/source/dom/customelement.mjs @@ -5,19 +5,19 @@ * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html */ -import { internalSymbol } from "../constants.mjs"; -import { extend } from "../data/extend.mjs"; -import { Pathfinder } from "../data/pathfinder.mjs"; -import { Formatter } from "../text/formatter.mjs"; - -import { parseDataURL } from "../types/dataurl.mjs"; -import { getGlobalObject } from "../types/global.mjs"; -import { isArray, isFunction, isIterable, isObject, isString } from "../types/is.mjs"; -import { Observer } from "../types/observer.mjs"; -import { ProxyObserver } from "../types/proxyobserver.mjs"; -import { validateFunction, validateInstance, validateObject, validateString } from "../types/validate.mjs"; -import { clone } from "../util/clone.mjs"; -import { addAttributeToken, getLinkedObjects, hasObjectLink } from "./attributes.mjs"; +import {internalSymbol} from "../constants.mjs"; +import {extend} from "../data/extend.mjs"; +import {Pathfinder} from "../data/pathfinder.mjs"; +import {Formatter} from "../text/formatter.mjs"; + +import {parseDataURL} from "../types/dataurl.mjs"; +import {getGlobalObject} from "../types/global.mjs"; +import {isArray, isFunction, isIterable, isObject, isString} from "../types/is.mjs"; +import {Observer} from "../types/observer.mjs"; +import {ProxyObserver} from "../types/proxyobserver.mjs"; +import {validateFunction, validateInstance, validateObject, validateString} from "../types/validate.mjs"; +import {clone} from "../util/clone.mjs"; +import {addAttributeToken, getLinkedObjects, hasObjectLink} from "./attributes.mjs"; import { ATTRIBUTE_DISABLED, ATTRIBUTE_ERRORMESSAGE, @@ -25,11 +25,11 @@ import { ATTRIBUTE_OPTIONS_SELECTOR, customElementUpdaterLinkSymbol, } from "./constants.mjs"; -import { findDocumentTemplate, Template } from "./template.mjs"; -import { addObjectWithUpdaterToElement } from "./updater.mjs"; -import { instanceSymbol } from "../constants.mjs"; -import { getDocumentTranslations, Translations } from "../i18n/translations.mjs"; -import { getSlottedElements } from "./slotted.mjs"; +import {findDocumentTemplate, Template} from "./template.mjs"; +import {addObjectWithUpdaterToElement} from "./updater.mjs"; +import {instanceSymbol} from "../constants.mjs"; +import {getDocumentTranslations, Translations} from "../i18n/translations.mjs"; +import {getSlottedElements} from "./slotted.mjs"; import {initOptionsFromAttributes} from "./util/init-options-from-attributes.mjs"; export { @@ -203,6 +203,7 @@ class CustomElement extends HTMLElement { this[internalSymbol] = new ProxyObserver({ options: initOptionsFromAttributes(this, extend({}, this.defaults)), }); + initAttributeChangeMutationObserver.call(this); initOptionObserver.call(this); this[initMethodSymbol](); } @@ -217,7 +218,9 @@ class CustomElement extends HTMLElement { } /** - * This method determines which attributes are to be monitored by `attributeChangedCallback()`. + * This method determines which attributes are to be + * monitored by `attributeChangedCallback()`. Unfortunately, this method is static. + * Therefore, the `observedAttributes` property cannot be changed during runtime. * * @return {string[]} * @since 1.15.0 @@ -421,7 +424,8 @@ class CustomElement extends HTMLElement { try { value = new Pathfinder(this[internalSymbol].getRealSubject()["options"]).getVia(path); - } catch (e) {} + } catch (e) { + } if (value === undefined) return defaultValue; return value; @@ -491,7 +495,8 @@ class CustomElement extends HTMLElement { try { initShadowRoot.call(self); elements = self.shadowRoot.childNodes; - } catch (e) {} + } catch (e) { + } try { initCSSStylesheet.call(this); @@ -542,7 +547,8 @@ class CustomElement extends HTMLElement { * @return {void} * @since 1.7.0 */ - disconnectedCallback() {} + disconnectedCallback() { + } /** * The custom element has been moved into a new document (e.g. someone called document.adoptNode(el)). @@ -550,7 +556,8 @@ class CustomElement extends HTMLElement { * @return {void} * @since 1.7.0 */ - adoptedCallback() {} + adoptedCallback() { + } /** * Called when an observed attribute has been added, removed, updated, or replaced. Also called for initial @@ -595,6 +602,32 @@ class CustomElement extends HTMLElement { } } +/** + * This method is called when the element is first created. + * + * @private + * @this CustomElement + */ +function initAttributeChangeMutationObserver() { + const self = this; + + if (self[attributeObserverSymbol] === undefined) { + self[attributeObserverSymbol] = {}; + } + + new MutationObserver(function (mutations) { + for (const mutation of mutations) { + if (mutation.type === "attributes") { + self.attributeChangedCallback(mutation.attributeName, mutation.oldValue, mutation.target.getAttribute(mutation.attributeName)); + } + } + }).observe(self, { + attributes: true, + attributeOldValue: true, + attributeFilter: Object.keys(self[attributeObserverSymbol]), + }); +} + /** * @this CustomElement * @private @@ -787,7 +820,8 @@ function parseOptionsJSON(data) { try { let dataUrl = parseDataURL(data); data = dataUrl.content; - } catch (e) {} + } catch (e) { + } try { obj = JSON.parse(data);