First implementation of ImageHandle

This commit is contained in:
Henrik Giesel 2021-07-21 01:32:09 +02:00 committed by Damien Elmes
parent 41c4be2f54
commit 0b06891771
5 changed files with 185 additions and 1 deletions

View file

@ -0,0 +1,118 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import { getContext } from "svelte";
import { nightModeKey } from "components/context-keys";
export let hidden: boolean;
export let top: number = 0;
export let left: number = 0;
export let width: number = 0;
export let height: number = 0;
function setPointerCapture(event: PointerEvent): void {
if (event.pointerId !== 1) {
return;
}
(event.target as Element).setPointerCapture(event.pointerId);
}
function resize(event: PointerEvent): void {
if (!(event.target as Element).hasPointerCapture(event.pointerId)) {
return;
}
}
const nightMode = getContext(nightModeKey);
</script>
<div
style="--top: {top}px; --left: {left}px; --width: {width}px; --height: {height}px;"
class="image-handle-selection"
{hidden}
>
<div class="image-handle-bg" />
<div class:nightMode class="image-handle-control image-handle-control-nw" />
<div class:nightMode class="image-handle-control image-handle-control-ne" />
<div class:nightMode class="image-handle-control image-handle-control-sw" />
<div
class:nightMode
class="image-handle-control image-handle-control-se is-active"
on:pointerdown={setPointerCapture}
on:pointermove={resize}
/>
</div>
<style lang="scss">
div {
position: absolute;
}
.image-handle-selection {
top: var(--top);
left: var(--left);
width: var(--width);
height: var(--height);
}
.image-handle-bg {
width: 100%;
height: 100%;
background-color: black;
opacity: 0.2;
}
.image-handle-control {
width: 7px;
height: 7px;
border: 1px solid black;
&.is-active {
background-color: black;
}
&.nightMode {
border-color: white;
&.is-active {
background-color: white;
}
}
}
.image-handle-control-nw {
top: -5px;
left: -5px;
border-bottom: none;
border-right: none;
}
.image-handle-control-ne {
top: -5px;
right: -5px;
border-bottom: none;
border-left: none;
}
.image-handle-control-sw {
bottom: -5px;
left: -5px;
border-top: none;
border-right: none;
}
.image-handle-control-se {
bottom: -5px;
right: -5px;
border-top: none;
border-left: none;
&.is-active {
cursor: se-resize;
}
}
</style>

View file

@ -0,0 +1,17 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import ImageHandle from "./ImageHandle.svelte";
export let hidden: boolean;
export let top: number;
export let left: number;
export let width: number;
export let height: number;
</script>
<div>
<ImageHandle {hidden} {top} {left} {width} {height} />
</div>

View file

@ -23,7 +23,9 @@ function clearChangeTimer(): void {
export function saveField(currentField: EditingArea, type: "blur" | "key"): void {
clearChangeTimer();
const command = `${type}:${currentField.ord}:${getNoteId()}:${currentField.fieldHTML}`
const command = `${type}:${currentField.ord}:${getNoteId()}:${
currentField.fieldHTML
}`;
bridgeCommand(command);
}

View file

@ -5,6 +5,8 @@
@typescript-eslint/no-non-null-assertion: "off",
*/
import ImageHandleContainer from "./ImageHandleContainer.svelte";
import type { EditableContainer } from "./editable-container";
import type { Editable } from "./editable";
import type { Codable } from "./codable";
@ -13,12 +15,14 @@ import { updateActiveButtons } from "./toolbar";
import { bridgeCommand } from "./lib";
import { onInput, onKey, onKeyUp } from "./input-handlers";
import { onFocus, onBlur } from "./focus-handlers";
import { nightModeKey } from "components/context-keys";
function onCutOrCopy(): void {
bridgeCommand("cutOrCopy");
}
export class EditingArea extends HTMLDivElement {
imageHandle: ImageHandleContainer;
editableContainer: EditableContainer;
editable: Editable;
codable: Codable;
@ -34,12 +38,32 @@ export class EditingArea extends HTMLDivElement {
this.editableContainer.shadowRoot!.appendChild(this.editable);
this.appendChild(this.editableContainer);
const context = new Map();
context.set(
nightModeKey,
document.documentElement.classList.contains("night-mode")
);
this.imageHandle = new ImageHandleContainer({
target: this,
anchor: this.editableContainer,
props: {
hidden: true,
top: 0,
left: 0,
width: 0,
height: 0,
},
context,
} as any);
this.codable = document.createElement("textarea", {
is: "anki-codable",
}) as Codable;
this.appendChild(this.codable);
this.onPaste = this.onPaste.bind(this);
this.showImageHandle = this.showImageHandle.bind(this);
}
get activeInput(): Editable | Codable {
@ -68,6 +92,7 @@ export class EditingArea extends HTMLDivElement {
this.addEventListener("copy", onCutOrCopy);
this.addEventListener("oncut", onCutOrCopy);
this.addEventListener("mouseup", updateActiveButtons);
this.editable.addEventListener("click", this.showImageHandle);
}
disconnectedCallback(): void {
@ -80,6 +105,7 @@ export class EditingArea extends HTMLDivElement {
this.removeEventListener("copy", onCutOrCopy);
this.removeEventListener("oncut", onCutOrCopy);
this.removeEventListener("mouseup", updateActiveButtons);
this.editable.removeEventListener("click", this.showImageHandle);
}
initialize(color: string, content: string): void {
@ -144,6 +170,26 @@ export class EditingArea extends HTMLDivElement {
this.activeInput.onPaste(event);
}
showImageHandle(event: MouseEvent): void {
if (event.target instanceof HTMLImageElement) {
const image = event.target;
const imageRect = image.getBoundingClientRect();
const editableRect = this.editable.getBoundingClientRect();
(this.imageHandle as any).$set({
hidden: false,
top: imageRect.top - editableRect.top,
left: imageRect.left - editableRect.left,
width: image.clientWidth,
height: image.clientHeight,
});
} else {
(this.imageHandle as any).$set({
hidden: true,
});
}
}
toggleHtmlEdit(): void {
const hadFocus = this.hasFocus();

View file

@ -15,6 +15,7 @@
}
.field {
position: relative;
border: 1px solid var(--border);
background: var(--frame-bg);