From 3579b6a3b61131d58c35e1d9338775ae07431099 Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 6 Aug 2021 02:19:36 +0200 Subject: [PATCH] Introduce WithImageConstrained --- ts/components/WithDropdown.svelte | 2 +- ts/editor/HandleBackground.svelte | 11 +- ts/editor/HandleSelection.svelte | 29 ++-- ts/editor/ImageHandle.svelte | 142 ++++++++--------- ts/editor/ImageHandleFloat.svelte | 16 +- ts/editor/ImageHandleSizeSelect.svelte | 209 ++----------------------- ts/editor/WithImageConstrained.svelte | 199 +++++++++++++++++++++++ 7 files changed, 302 insertions(+), 306 deletions(-) create mode 100644 ts/editor/WithImageConstrained.svelte diff --git a/ts/components/WithDropdown.svelte b/ts/components/WithDropdown.svelte index c50008fdb..487f7fa61 100644 --- a/ts/components/WithDropdown.svelte +++ b/ts/components/WithDropdown.svelte @@ -28,7 +28,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +{/if} diff --git a/ts/editor/ImageHandleFloat.svelte b/ts/editor/ImageHandleFloat.svelte index bf000d7de..769721d88 100644 --- a/ts/editor/ImageHandleFloat.svelte +++ b/ts/editor/ImageHandleFloat.svelte @@ -11,7 +11,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import { floatNoneIcon, floatLeftIcon, floatRightIcon } from "./icons"; - export let activeImage: HTMLImageElement; + export let image: HTMLImageElement; export let isRtl: boolean; const leftValues = { @@ -33,20 +33,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html (activeImage.style.float = "")} - >{@html floatNoneIcon} (image.style.float = "")}>{@html floatNoneIcon} (activeImage.style.float = inlineStart.position)} + on:click={() => (image.style.float = inlineStart.position)} >{@html floatLeftIcon} @@ -54,9 +52,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html (activeImage.style.float = inlineEnd.position)} + on:click={() => (image.style.float = inlineEnd.position)} >{@html floatRightIcon} diff --git a/ts/editor/ImageHandleSizeSelect.svelte b/ts/editor/ImageHandleSizeSelect.svelte index 37452a512..bed0d71b2 100644 --- a/ts/editor/ImageHandleSizeSelect.svelte +++ b/ts/editor/ImageHandleSizeSelect.svelte @@ -9,209 +9,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import ButtonGroupItem from "components/ButtonGroupItem.svelte"; import IconButton from "components/IconButton.svelte"; - import { createEventDispatcher, onDestroy } from "svelte"; import { sizeActual, sizeMinimized } from "./icons"; - import { nodeIsElement } from "./helpers"; - - export let container: HTMLElement; - export let sheet: CSSStyleSheet; - - export let activeImage: HTMLImageElement | null; - export let active: boolean = false; - - $: { - const index = images.indexOf(activeImage!); - - if (index >= 0) { - const rule = sheet.cssRules[index] as CSSStyleRule; - active = rule.cssText.endsWith("{ }"); - } else { - activeImage = null; - } - } - $: icon = active ? sizeActual : sizeMinimized; + export let active: boolean; export let isRtl: boolean; - export let maxWidth = 250; - export let maxHeight = 125; - $: restrictionAspectRatio = maxWidth / maxHeight; - - const dispatch = createEventDispatcher(); - - function createPathRecursive(tokens: string[], element: Element): string[] { - const tagName = element.tagName.toLowerCase(); - - if (!element.parentElement) { - const nth = - Array.prototype.indexOf.call( - (element.parentNode! as Document | ShadowRoot).children, - element - ) + 1; - return [`${tagName}:nth-child(${nth})`, ...tokens]; - } else { - const nth = - Array.prototype.indexOf.call(element.parentElement.children, element) + - 1; - return createPathRecursive( - [`${tagName}:nth-child(${nth})`, ...tokens], - element.parentElement - ); - } - } - - function createPath(element: Element): string { - return createPathRecursive([], element).join(" > "); - } - - export const images: HTMLImageElement[] = []; - - $: for (const [index, image] of images.entries()) { - const rule = sheet.cssRules[index] as CSSStyleRule; - rule.selectorText = createPath(image); - } - - function filterImages(nodes: HTMLCollection | Node[]): HTMLImageElement[] { - const result: HTMLImageElement[] = []; - - for (const node of nodes) { - if (!nodeIsElement(node)) { - continue; - } - - if (node.tagName === "IMG") { - result.push(node as HTMLImageElement); - } else { - result.push(...filterImages(node.children)); - } - } - - return result; - } - - function setImageRule(image: HTMLImageElement, rule: CSSStyleRule): void { - const aspectRatio = image.naturalWidth / image.naturalHeight; - - if (restrictionAspectRatio - aspectRatio > 1) { - // restricted by height - rule.style.setProperty("width", "auto", "important"); - - const width = Number(image.getAttribute("width")) || image.width; - const height = Number(image.getAttribute("height")) || width / aspectRatio; - rule.style.setProperty( - "height", - height < maxHeight ? `${height}px` : "auto", - "important" - ); - } else { - // square or restricted by width - const width = Number(image.getAttribute("width")) || image.width; - rule.style.setProperty( - "width", - width < maxWidth ? `${width}px` : "auto", - "important" - ); - - rule.style.setProperty("height", "auto", "important"); - } - - rule.style.setProperty("max-width", `min(${maxWidth}px, 100%)`, "important"); - rule.style.setProperty("max-height", `${maxHeight}px`, "important"); - } - - function resetImageRule(rule: CSSStyleRule): void { - rule.style.removeProperty("width"); - rule.style.removeProperty("height"); - rule.style.removeProperty("max-width"); - rule.style.removeProperty("max-height"); - } - - function addImage(image: HTMLImageElement): void { - if (!container.contains(image)) { - return; - } - - images.push(image); - const index = sheet.insertRule( - `${createPath(image)} {}`, - sheet.cssRules.length - ); - const rule = sheet.cssRules[index] as CSSStyleRule; - setImageRule(image, rule); - } - - function addImageOnLoad(image: HTMLImageElement): void { - if (image.complete && image.naturalWidth !== 0 && image.naturalHeight !== 0) { - addImage(image); - } else { - image.addEventListener("load", () => { - addImage(image); - }); - } - } - - function removeImage(image: HTMLImageElement): void { - const index = images.indexOf(image); - if (index < 0) { - return; - } - - images.splice(index, 1); - sheet.deleteRule(index); - } - - const mutationObserver = new MutationObserver((mutations) => { - const addedImages = mutations.flatMap((mutation) => - filterImages([...mutation.addedNodes]) - ); - - for (const image of addedImages) { - addImageOnLoad(image); - } - - const removedImages = mutations.flatMap((mutation) => - filterImages([...mutation.removedNodes]) - ); - - for (const image of removedImages) { - removeImage(image); - } - }); - - $: if (container) { - mutationObserver.observe(container, { childList: true, subtree: true }); - } - - export function toggleActualSize() { - const index = images.indexOf(activeImage!); - if (index === -1) { - return; - } - - const rule = sheet.cssRules[index] as CSSStyleRule; - active = !active; - - if (active) { - resetImageRule(rule); - } else { - setImageRule(activeImage!, rule); - } - - dispatch("update", active); - } - - onDestroy(() => mutationObserver.disconnect()); + $: icon = active ? sizeActual : sizeMinimized; -{#if activeImage} - - - {@html icon} - - -{/if} + + + {@html icon} + + diff --git a/ts/editor/WithImageConstrained.svelte b/ts/editor/WithImageConstrained.svelte new file mode 100644 index 000000000..a9e303b2d --- /dev/null +++ b/ts/editor/WithImageConstrained.svelte @@ -0,0 +1,199 @@ + + + +{#if activeImage} + +{/if}