import { isInsideHtmlEditor } from "../core/HtmlEditor.js";
import { timelinePolyfillInstalled } from "../polyfills/polyfills.js";
import { AnimationInstaller } from "./AnimationInstaller.js";
import { installSvgClipPath } from "./installSvgClipPath.js";
import { NodeListWalker } from "./NodeListWalker.js";
import RevealAttributes from "./RevealAttributes.js";
import RevealObserver from "./RevealObserver.js";
const prefix = "styler-";
const onDomReady = (resolve) => {
if (document.readyState !== "loading") {
resolve();
return;
}
const d = () => {
document.removeEventListener("DOMContentLoaded", d);
resolve();
};
document.addEventListener("DOMContentLoaded", d);
};
const timelineAttributes = [
'styler-on-scroll',
'styler-on-scroll-effect-1',
'styler-on-scroll-effect-2',
'styler-on-scroll-above',
'styler-on-scroll-above-effect-1',
'styler-on-scroll-above-effect-2',
'styler-on-scroll-top-half',
'styler-on-scroll-top-half-effect-1',
'styler-on-scroll-top-half-effect-2',
];
const keyFrameAttributes = [
'styler-on-enter',
'styler-on-enter-effect-1',
'styler-on-enter-effect-2',
'styler-on-hover',
'styler-on-hover-effect-1',
'styler-on-hover-effect-2',
'styler-on-leave',
'styler-on-leave-effect-1',
'styler-on-leave-effect-2',
... timelineAttributes
];
const maskAnimations = [
"styler-mask-on-enter"
];
const css = new CSSStyleSheet({
});
const scrollerCss = new CSSStyleSheet({});
const stylerCss = new CSSStyleSheet({
});
const stylerMap = new Set();
const updateStylerMap = (key, value, av = value) => {
if(!value) {
return;
}
try {
switch(key) {
case "styler-clip-path-url":
// install on svg...
av = `url("${installSvgClipPath(value)}")`;
break;
case "styler-background-image-url":
av = `url("${value}")`;
break;
}
const selector = `[${key}=${CSS.escape(value)}]`;
const match = `${key}=${value},${av}`
if (stylerMap.has(match)) {
return;
}
stylerMap.add(match);
stylerCss.insertRule(`${selector} {
--${key}: ${av};
}`);
} catch (e) {
console.error(e);
}
};
document.adoptedStyleSheets = document.adoptedStyleSheets?.length
? [... document.adoptedStyleSheets, css, stylerCss, scrollerCss]
: [css, stylerCss, scrollerCss];
document.addEventListener("scroll", ()=> {
scrollerCss.replaceSync(`:root {
--window-scroll-y: ${window.scrollY}px;
--body-scroll-top: ${document.body.scrollTop}px;
}`);
}, { passive: true });
const updateMaskAnimationAttribute = (e: HTMLElement, a, remove = false) => {
const url = e.getAttribute(a);
const img = document.createElement("img");
img.setAttribute("src", url);
updateStylerMap(a, url, `url("${img.src}")`);
};
const updateKeyFrameAttribute = (e: HTMLElement, a, remove = false) => {
const style = e.style;
if (!style) {
return;
}
const animationDefJson = e.getAttribute(a);
if (!animationDefJson) {
return;
}
const animationObj = AnimationInstaller.installAnimation(animationDefJson, stylerCss);
if (animationObj === void 0) {
const isValidAnimationName = /[\-\_a-z][\-\_a-z0-9]{0,200}/i.test(animationDefJson);
if (isValidAnimationName) {
updateStylerMap(a, animationDefJson);
if (timelinePolyfillInstalled) {
if (timelineAttributes.includes(a)) {
css.insertRule(`[${a}=${CSS.escape(animationDefJson)}] {
animation-duration: 1ms;
animation-play-state: paused;
--${animationDefJson}-animation-timeline: var(--${a}-timeline);
--${animationDefJson}-animation-range: var(--${a}-range);
}`);
}
}
}
return;
}
const { id } = animationObj;
if (timelinePolyfillInstalled) {
if (timelineAttributes.includes(a)) {
css.insertRule(`[${a}=${CSS.escape(animationDefJson)}] {
animation-duration: 1ms;
animation-play-state: paused;
--${id}-animation-timeline: var(--${a}-animation-timeline);
--${id}-animation-range: var(--${a}-animation-range);
}`);
}
}
updateStylerMap(a, animationDefJson, id);
};
onDomReady(() => {
if(typeof (document as any).stylerExpansion === "undefined") {
if (!document.body.hasAttribute("styler-expansion-enabled")) {
return;
}
}
const updateStyles = isInsideHtmlEditor(document.body)
? (element: HTMLElement) => {
if (!element.getAttributeNames) {
return;
}
for(const a of element.getAttributeNames()) {
if (!a.startsWith(prefix))
continue;
if (keyFrameAttributes.includes(a)) {
updateKeyFrameAttribute(element, a);
continue;
}
const v = element.getAttribute(a);
if (v !== "custom") {
updateStylerMap(a, v);
}
}
}
: (element: HTMLElement) => {
if (!element.getAttributeNames) {
return;
}
for(const a of element.getAttributeNames()) {
if (!a.startsWith(prefix))
continue;
if (a === "styler-on-enter") {
RevealObserver.observe(element);
}
if (a === "styler-mask-on-enter") {
RevealObserver.observe(element);
RevealAttributes.install(element);
}
if (maskAnimations.includes(a)) {
updateMaskAnimationAttribute(element, a);
continue;
}
if (keyFrameAttributes.includes(a)) {
updateKeyFrameAttribute(element, a);
continue;
}
const v = element.getAttribute(a);
if (v !== "custom") {
updateStylerMap(a, v);
}
}
};
const unobserve = (e: HTMLElement) => e.getAttributeNames && RevealObserver.unobserve(e);
// const prefix = document.body.hasAttribute("editing")
// ? "styler-on-"
// : "styler-";
// set all attributes...
const all = document.body.querySelectorAll("*");
all.forEach(updateStyles);
// we will only watch for changes here.
const ao = new MutationObserver((mutations) => {
for (const m of mutations) {
const { type } = m;
if (type === "childList") {
const { addedNodes, removedNodes } = m;
for (const a of NodeListWalker.walk(addedNodes)) {
updateStyles(a);
}
for(const a of NodeListWalker.walk(removedNodes)) {
unobserve(a);
}
// addedNodes.forEach(updateStyles);
// removedNodes.forEach(unobserve);
continue;
}
if (type === "attributes") {
const { target, attributeName, oldValue } = m;
if (!attributeName.startsWith(prefix)) {
continue;
}
const element = target as HTMLElement;
if (attributeName === "styler-on-enter") {
RevealObserver.observe(element);
}
if (keyFrameAttributes.includes(attributeName)) {
updateKeyFrameAttribute(element, attributeName);
continue;
}
const v = element.getAttribute(attributeName);
if (oldValue === v && oldValue !== null) {
// this duplication occurs for no reason...
continue;
}
if (v && v !== "custom") {
updateStylerMap(attributeName, v);
}
continue;
}
}
});
ao.observe(document.body, {
subtree: true,
childList: true,
attributes: true
});
});