85 lines
2.5 KiB
JavaScript
85 lines
2.5 KiB
JavaScript
(() => {
|
|
"use strict";
|
|
|
|
const controllerScript = document.currentScript;
|
|
const channel = document.documentElement.dataset.svgToolsChannel;
|
|
if (!channel) {
|
|
controllerScript?.remove();
|
|
return;
|
|
}
|
|
|
|
const send = (message) => parent.postMessage({ ...message, channel }, "*");
|
|
const find = (key) =>
|
|
typeof key === "string"
|
|
? document.querySelector(`[data-svg-tools-node="${CSS.escape(key)}"]`)
|
|
: null;
|
|
const reportBox = (key) => {
|
|
const element = find(key);
|
|
let box = null;
|
|
try {
|
|
if (element && typeof element.getBBox === "function") {
|
|
const candidate = element.getBBox();
|
|
if (
|
|
[candidate.x, candidate.y, candidate.width, candidate.height].every(
|
|
Number.isFinite,
|
|
)
|
|
) {
|
|
box = {
|
|
x: candidate.x,
|
|
y: candidate.y,
|
|
width: candidate.width,
|
|
height: candidate.height,
|
|
};
|
|
}
|
|
}
|
|
} catch {
|
|
// Some SVG elements do not expose geometry in every browser.
|
|
}
|
|
send({ type: "selection-box", key, box });
|
|
};
|
|
|
|
document.addEventListener("click", (event) => {
|
|
const target =
|
|
event.target instanceof Element
|
|
? event.target.closest("[data-svg-tools-node]")
|
|
: null;
|
|
const key = target?.getAttribute("data-svg-tools-node");
|
|
if (key) send({ type: "select", key });
|
|
if (event.target instanceof Element && event.target.closest("a")) {
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
|
|
addEventListener("message", (event) => {
|
|
if (event.source !== parent) return;
|
|
const message = event.data;
|
|
if (!message || message.channel !== channel) return;
|
|
if (message.type === "ping") send({ type: "ready" });
|
|
if (message.type === "selection" && typeof message.key === "string") {
|
|
reportBox(message.key);
|
|
}
|
|
if (
|
|
message.type === "path" &&
|
|
typeof message.key === "string" &&
|
|
typeof message.data === "string"
|
|
) {
|
|
find(message.key)?.setAttribute("d", message.data);
|
|
reportBox(message.key);
|
|
}
|
|
if (
|
|
message.type === "transform" &&
|
|
typeof message.key === "string" &&
|
|
(typeof message.value === "string" || message.value === null)
|
|
) {
|
|
const element = find(message.key);
|
|
if (!element) return;
|
|
if (message.value) element.setAttribute("transform", message.value);
|
|
else element.removeAttribute("transform");
|
|
reportBox(message.key);
|
|
}
|
|
});
|
|
|
|
send({ type: "ready" });
|
|
controllerScript?.remove();
|
|
})();
|