js-draw 1.18.0 → 1.19.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor.css +35 -3
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +20 -1
- package/dist/cjs/Editor.js +6 -0
- package/dist/cjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/cjs/{SVGLoader.js → SVGLoader/index.js} +12 -29
- package/dist/cjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/cjs/SVGLoader/utils/determineFontSize.js +27 -0
- package/dist/cjs/Viewport.d.ts +33 -1
- package/dist/cjs/components/TextComponent.js +3 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.js +20 -15
- package/dist/cjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/cjs/testing/findNodeWithText.js +16 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/cjs/testing/firstElementAncestorOfNode.js +13 -0
- package/dist/cjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/cjs/testing/sendKeyPressRelease.js +8 -0
- package/dist/cjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/cjs/testing/sendPenEvent.js +26 -3
- package/dist/cjs/toolbar/localization.d.ts +2 -0
- package/dist/cjs/toolbar/localization.js +2 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/ImageWrapper.js +58 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/fileToImages.js +21 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget/index.js +281 -0
- package/dist/cjs/toolbar/widgets/TextToolWidget.js +5 -3
- package/dist/cjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/cjs/toolbar/widgets/components/makeFileInput.js +102 -45
- package/dist/cjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +103 -0
- package/dist/cjs/tools/Eraser.d.ts +7 -2
- package/dist/cjs/tools/Eraser.js +54 -1
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/cjs/tools/SelectionTool/Selection.js +20 -20
- package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/cjs/tools/SelectionTool/SelectionHandle.js +6 -0
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +1 -1
- package/dist/cjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/cjs/tools/TextTool.js +2 -1
- package/dist/cjs/tools/TextTool.test.d.ts +1 -0
- package/dist/cjs/tools/ToolController.d.ts +2 -0
- package/dist/cjs/tools/ToolController.js +10 -1
- package/dist/cjs/util/ReactiveValue.d.ts +2 -0
- package/dist/cjs/util/ReactiveValue.js +11 -0
- package/dist/cjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/cjs/util/bytesToSizeString.js +26 -0
- package/dist/cjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/cjs/util/stopPropagationOfScrollingWheelEvents.js +10 -6
- package/dist/cjs/util/waitForAll.d.ts +2 -0
- package/dist/cjs/util/waitForAll.js +2 -0
- package/dist/cjs/util/waitForImageLoaded.js +3 -0
- package/dist/cjs/util/waitForTimeout.d.ts +1 -0
- package/dist/cjs/util/waitForTimeout.js +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +20 -1
- package/dist/mjs/Editor.mjs +6 -0
- package/dist/mjs/{SVGLoader.d.ts → SVGLoader/index.d.ts} +1 -1
- package/dist/mjs/{SVGLoader.mjs → SVGLoader/index.mjs} +12 -29
- package/dist/mjs/SVGLoader/index.test.d.ts +1 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.d.ts +3 -0
- package/dist/mjs/SVGLoader/utils/determineFontSize.mjs +25 -0
- package/dist/mjs/Viewport.d.ts +33 -1
- package/dist/mjs/components/TextComponent.mjs +3 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +20 -15
- package/dist/mjs/testing/findNodeWithText.d.ts +3 -0
- package/dist/mjs/testing/findNodeWithText.mjs +14 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.d.ts +3 -0
- package/dist/mjs/testing/firstElementAncestorOfNode.mjs +11 -0
- package/dist/mjs/testing/sendKeyPressRelease.d.ts +3 -0
- package/dist/mjs/testing/sendKeyPressRelease.mjs +6 -0
- package/dist/mjs/testing/sendPenEvent.d.ts +2 -2
- package/dist/mjs/testing/sendPenEvent.mjs +3 -3
- package/dist/mjs/toolbar/localization.d.ts +2 -0
- package/dist/mjs/toolbar/localization.mjs +2 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.d.ts +22 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/ImageWrapper.mjs +54 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.d.ts +3 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/fileToImages.mjs +16 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.d.ts +37 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.mjs +276 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget/index.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/TextToolWidget.mjs +5 -3
- package/dist/mjs/toolbar/widgets/TextToolWidget.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeFileInput.d.ts +12 -2
- package/dist/mjs/toolbar/widgets/components/makeFileInput.mjs +102 -45
- package/dist/mjs/toolbar/widgets/components/makeFileInput.test.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.d.ts +15 -0
- package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +98 -0
- package/dist/mjs/tools/Eraser.d.ts +7 -2
- package/dist/mjs/tools/Eraser.mjs +54 -1
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -2
- package/dist/mjs/tools/SelectionTool/Selection.mjs +20 -20
- package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +8 -2
- package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +6 -0
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +1 -1
- package/dist/mjs/tools/SelectionTool/types.d.ts +19 -0
- package/dist/mjs/tools/TextTool.mjs +2 -1
- package/dist/mjs/tools/TextTool.test.d.ts +1 -0
- package/dist/mjs/tools/ToolController.d.ts +2 -0
- package/dist/mjs/tools/ToolController.mjs +10 -1
- package/dist/mjs/util/ReactiveValue.d.ts +2 -0
- package/dist/mjs/util/ReactiveValue.mjs +11 -0
- package/dist/mjs/util/bytesToSizeString.d.ts +8 -0
- package/dist/mjs/util/bytesToSizeString.mjs +24 -0
- package/dist/mjs/util/bytesToSizeString.test.d.ts +1 -0
- package/dist/mjs/util/stopPropagationOfScrollingWheelEvents.mjs +10 -6
- package/dist/mjs/util/waitForAll.d.ts +2 -0
- package/dist/mjs/util/waitForAll.mjs +2 -0
- package/dist/mjs/util/waitForImageLoaded.mjs +3 -0
- package/dist/mjs/util/waitForTimeout.d.ts +1 -0
- package/dist/mjs/util/waitForTimeout.mjs +1 -1
- package/dist/mjs/version.mjs +1 -1
- package/package.json +4 -4
- package/src/toolbar/toolbar.scss +1 -7
- package/src/toolbar/widgets/{InsertImageWidget.scss → InsertImageWidget/index.scss} +3 -2
- package/src/toolbar/widgets/components/components.scss +2 -1
- package/src/toolbar/widgets/components/makeFileInput.scss +14 -1
- package/src/toolbar/widgets/components/makeSnappedList.scss +28 -0
- package/src/toolbar/widgets/widgets.scss +7 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +0 -269
- package/dist/mjs/toolbar/widgets/InsertImageWidget.d.ts +0 -22
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +0 -264
- /package/dist/cjs/{SVGLoader.test.d.ts → SVGLoader/index.test.d.ts} +0 -0
- /package/dist/{mjs/SVGLoader.test.d.ts → cjs/toolbar/widgets/InsertImageWidget/index.test.d.ts} +0 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.19.1",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -64,11 +64,11 @@
|
|
64
64
|
"postpack": "ts-node tools/copyREADME.ts revert"
|
65
65
|
},
|
66
66
|
"dependencies": {
|
67
|
-
"@js-draw/math": "^1.
|
67
|
+
"@js-draw/math": "^1.19.0",
|
68
68
|
"@melloware/coloris": "0.22.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
71
|
-
"@js-draw/build-tool": "^1.
|
71
|
+
"@js-draw/build-tool": "^1.19.0",
|
72
72
|
"@types/jest": "29.5.5",
|
73
73
|
"@types/jsdom": "21.1.3"
|
74
74
|
},
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "50fa44a2bb68b93d24efea433760a5e45c56293f"
|
90
90
|
}
|
package/src/toolbar/toolbar.scss
CHANGED
@@ -1,10 +1,4 @@
|
|
1
|
-
@use "./widgets/
|
2
|
-
@use "./widgets/OverflowWidget.css";
|
3
|
-
@use "./widgets/PenToolWidget.scss";
|
4
|
-
@use "./widgets/HandToolWidget.scss";
|
5
|
-
@use "./widgets/SelectionToolWidget.scss";
|
6
|
-
@use "./widgets/DocumentPropertiesWidget.scss";
|
7
|
-
@use "./widgets/components/components.scss";
|
1
|
+
@use "./widgets/widgets.scss";
|
8
2
|
|
9
3
|
@use "./AbstractToolbar.scss";
|
10
4
|
@use "./EdgeToolbar.scss";
|
@@ -11,8 +11,8 @@ $image-widget-selector: '.insert-image-widget-dropdown-content';
|
|
11
11
|
}
|
12
12
|
|
13
13
|
img {
|
14
|
-
max-width:
|
15
|
-
max-height:
|
14
|
+
max-width: 100%;
|
15
|
+
max-height: 100%;
|
16
16
|
|
17
17
|
/* Center */
|
18
18
|
display: block;
|
@@ -23,6 +23,7 @@ $image-widget-selector: '.insert-image-widget-dropdown-content';
|
|
23
23
|
.insert-image-image-status-view {
|
24
24
|
display: flex;
|
25
25
|
justify-content: space-between;
|
26
|
+
padding-bottom: 0;
|
26
27
|
}
|
27
28
|
|
28
29
|
.action-button-row {
|
@@ -2,7 +2,11 @@
|
|
2
2
|
.toolbar-element .toolbar--file-input-container {
|
3
3
|
display: flex;
|
4
4
|
|
5
|
-
|
5
|
+
&.-loading {
|
6
|
+
opacity: 0.8;
|
7
|
+
}
|
8
|
+
|
9
|
+
> input.file-input {
|
6
10
|
// Hide in a way such that screen readers can still access the
|
7
11
|
// input.
|
8
12
|
opacity: 0;
|
@@ -11,6 +15,11 @@
|
|
11
15
|
min-width: 0 !important;
|
12
16
|
max-width: 0;
|
13
17
|
height: 0;
|
18
|
+
|
19
|
+
// Needed when the input is a button.
|
20
|
+
overflow: hidden;
|
21
|
+
padding: 0;
|
22
|
+
margin: 0;
|
14
23
|
}
|
15
24
|
|
16
25
|
> label {
|
@@ -28,6 +37,10 @@
|
|
28
37
|
in srgb, var(--foreground-color-1), transparent
|
29
38
|
);
|
30
39
|
|
40
|
+
> .cancel-button {
|
41
|
+
display: block;
|
42
|
+
}
|
43
|
+
|
31
44
|
> .toolbar--file-input-description {
|
32
45
|
background-color: var(--background-color-3);
|
33
46
|
color: var(--foreground-color-3);
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
// Repeat for specificity.
|
3
|
+
// TODO(v2): Refactor everything to use RCSS.
|
4
|
+
:root .toolbar-snapped-scroll-list.toolbar-snapped-scroll-list.toolbar-snapped-scroll-list {
|
5
|
+
overflow-y: auto;
|
6
|
+
scroll-snap-type: y mandatory;
|
7
|
+
height: min(200px, 50vh);
|
8
|
+
display: flex;
|
9
|
+
flex-direction: column;
|
10
|
+
|
11
|
+
> .item {
|
12
|
+
height: 100%;
|
13
|
+
width: 100%;
|
14
|
+
flex-shrink: 0;
|
15
|
+
|
16
|
+
display: flex;
|
17
|
+
justify-content: center;
|
18
|
+
align-items: center;
|
19
|
+
|
20
|
+
scroll-snap-align: start;
|
21
|
+
scroll-snap-stop: always;
|
22
|
+
box-sizing: border-box;
|
23
|
+
}
|
24
|
+
|
25
|
+
&.-empty {
|
26
|
+
display: none;
|
27
|
+
}
|
28
|
+
}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
import Editor from '../../Editor';
|
2
|
-
import { ToolbarLocalization } from '../localization';
|
3
|
-
import BaseWidget from './BaseWidget';
|
4
|
-
export default class InsertImageWidget extends BaseWidget {
|
5
|
-
private imagePreview;
|
6
|
-
private image;
|
7
|
-
private selectedFiles;
|
8
|
-
private imageAltTextInput;
|
9
|
-
private statusView;
|
10
|
-
private submitButton;
|
11
|
-
constructor(editor: Editor, localization?: ToolbarLocalization);
|
12
|
-
protected getTitle(): string;
|
13
|
-
protected createIcon(): Element | null;
|
14
|
-
protected setDropdownVisible(visible: boolean): void;
|
15
|
-
protected handleClick(): void;
|
16
|
-
private static nextInputId;
|
17
|
-
protected fillDropdown(dropdown: HTMLElement): boolean;
|
18
|
-
private onImageDataUpdate;
|
19
|
-
private hideDialog;
|
20
|
-
private updateImageSizeDisplay;
|
21
|
-
private updateInputs;
|
22
|
-
}
|
@@ -1,269 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
const ImageComponent_1 = __importDefault(require("../../components/ImageComponent"));
|
7
|
-
const Erase_1 = __importDefault(require("../../commands/Erase"));
|
8
|
-
const EditorImage_1 = __importDefault(require("../../image/EditorImage"));
|
9
|
-
const uniteCommands_1 = __importDefault(require("../../commands/uniteCommands"));
|
10
|
-
const SelectionTool_1 = __importDefault(require("../../tools/SelectionTool/SelectionTool"));
|
11
|
-
const math_1 = require("@js-draw/math");
|
12
|
-
const fileToBase64Url_1 = __importDefault(require("../../util/fileToBase64Url"));
|
13
|
-
const BaseWidget_1 = __importDefault(require("./BaseWidget"));
|
14
|
-
const types_1 = require("../../types");
|
15
|
-
const constants_1 = require("../constants");
|
16
|
-
const makeFileInput_1 = __importDefault(require("./components/makeFileInput"));
|
17
|
-
class ImageWrapper {
|
18
|
-
constructor(imageBase64Url, preview, onUrlUpdate) {
|
19
|
-
this.imageBase64Url = imageBase64Url;
|
20
|
-
this.preview = preview;
|
21
|
-
this.onUrlUpdate = onUrlUpdate;
|
22
|
-
this.originalSrc = imageBase64Url;
|
23
|
-
preview.src = imageBase64Url;
|
24
|
-
}
|
25
|
-
updateImageData(base64DataUrl) {
|
26
|
-
this.preview.src = base64DataUrl;
|
27
|
-
this.imageBase64Url = base64DataUrl;
|
28
|
-
this.onUrlUpdate();
|
29
|
-
}
|
30
|
-
decreaseSize(resizeFactor = 3 / 4) {
|
31
|
-
const canvas = document.createElement('canvas');
|
32
|
-
canvas.width = this.preview.naturalWidth * resizeFactor;
|
33
|
-
canvas.height = this.preview.naturalHeight * resizeFactor;
|
34
|
-
const ctx = canvas.getContext('2d');
|
35
|
-
ctx?.drawImage(this.preview, 0, 0, canvas.width, canvas.height);
|
36
|
-
// JPEG can be much smaller than PNG for the same image size. Prefer it if
|
37
|
-
// the image is already a JPEG.
|
38
|
-
const format = this.originalSrc?.startsWith('data:image/jpeg;') ? 'image/jpeg' : 'image/png';
|
39
|
-
this.updateImageData(canvas.toDataURL(format));
|
40
|
-
}
|
41
|
-
reset() {
|
42
|
-
this.updateImageData(this.originalSrc);
|
43
|
-
}
|
44
|
-
isChanged() {
|
45
|
-
return this.imageBase64Url !== this.originalSrc;
|
46
|
-
}
|
47
|
-
getBase64Url() {
|
48
|
-
return this.imageBase64Url;
|
49
|
-
}
|
50
|
-
static fromSrcAndPreview(initialBase64Src, preview, onUrlUpdate) {
|
51
|
-
return new ImageWrapper(initialBase64Src, preview, onUrlUpdate);
|
52
|
-
}
|
53
|
-
}
|
54
|
-
class InsertImageWidget extends BaseWidget_1.default {
|
55
|
-
constructor(editor, localization) {
|
56
|
-
localization ??= editor.localization;
|
57
|
-
super(editor, 'insert-image-widget', localization);
|
58
|
-
this.image = null;
|
59
|
-
// Make the dropdown showable
|
60
|
-
this.container.classList.add('dropdownShowable');
|
61
|
-
editor.notifier.on(types_1.EditorEventType.SelectionUpdated, event => {
|
62
|
-
if (event.kind === types_1.EditorEventType.SelectionUpdated && this.isDropdownVisible()) {
|
63
|
-
this.updateInputs();
|
64
|
-
}
|
65
|
-
});
|
66
|
-
}
|
67
|
-
getTitle() {
|
68
|
-
return this.localizationTable.image;
|
69
|
-
}
|
70
|
-
createIcon() {
|
71
|
-
return this.editor.icons.makeInsertImageIcon();
|
72
|
-
}
|
73
|
-
setDropdownVisible(visible) {
|
74
|
-
super.setDropdownVisible(visible);
|
75
|
-
// Update the dropdown just before showing.
|
76
|
-
if (this.isDropdownVisible()) {
|
77
|
-
this.updateInputs();
|
78
|
-
}
|
79
|
-
}
|
80
|
-
handleClick() {
|
81
|
-
this.setDropdownVisible(!this.isDropdownVisible());
|
82
|
-
}
|
83
|
-
fillDropdown(dropdown) {
|
84
|
-
const container = document.createElement('div');
|
85
|
-
container.classList.add('insert-image-widget-dropdown-content', `${constants_1.toolbarCSSPrefix}spacedList`, `${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`);
|
86
|
-
const { container: chooseImageRow, selectedFiles, } = (0, makeFileInput_1.default)(this.localizationTable.chooseFile, this.editor, 'image/*');
|
87
|
-
const altTextRow = document.createElement('div');
|
88
|
-
this.imagePreview = document.createElement('img');
|
89
|
-
this.statusView = document.createElement('div');
|
90
|
-
const actionButtonRow = document.createElement('div');
|
91
|
-
actionButtonRow.classList.add('action-button-row');
|
92
|
-
this.statusView.classList.add('insert-image-image-status-view');
|
93
|
-
this.submitButton = document.createElement('button');
|
94
|
-
this.selectedFiles = selectedFiles;
|
95
|
-
this.imageAltTextInput = document.createElement('input');
|
96
|
-
// Label the alt text input
|
97
|
-
const imageAltTextLabel = document.createElement('label');
|
98
|
-
const altTextInputId = `insert-image-alt-text-input-${InsertImageWidget.nextInputId++}`;
|
99
|
-
this.imageAltTextInput.setAttribute('id', altTextInputId);
|
100
|
-
imageAltTextLabel.htmlFor = altTextInputId;
|
101
|
-
imageAltTextLabel.innerText = this.localizationTable.inputAltText;
|
102
|
-
this.imageAltTextInput.type = 'text';
|
103
|
-
this.imageAltTextInput.placeholder = this.localizationTable.describeTheImage;
|
104
|
-
this.statusView.setAttribute('aria-live', 'polite');
|
105
|
-
this.submitButton.innerText = this.localizationTable.submit;
|
106
|
-
this.selectedFiles.onUpdateAndNow(async (files) => {
|
107
|
-
if (files.length === 0) {
|
108
|
-
this.image = null;
|
109
|
-
this.onImageDataUpdate();
|
110
|
-
return;
|
111
|
-
}
|
112
|
-
this.imagePreview.style.display = 'block';
|
113
|
-
const image = files[0];
|
114
|
-
let data = null;
|
115
|
-
let errorMessage = null;
|
116
|
-
try {
|
117
|
-
data = await (0, fileToBase64Url_1.default)(image);
|
118
|
-
}
|
119
|
-
catch (error) {
|
120
|
-
console.error('Image load error', error);
|
121
|
-
errorMessage = this.localizationTable.imageLoadError(error);
|
122
|
-
}
|
123
|
-
if (data) {
|
124
|
-
this.image = ImageWrapper.fromSrcAndPreview(data, this.imagePreview, () => this.onImageDataUpdate());
|
125
|
-
}
|
126
|
-
else {
|
127
|
-
this.image = null;
|
128
|
-
}
|
129
|
-
this.onImageDataUpdate();
|
130
|
-
// Show the error after image update callbacks to ensure it is
|
131
|
-
// actually shown.
|
132
|
-
if (errorMessage) {
|
133
|
-
this.statusView.innerText = errorMessage;
|
134
|
-
}
|
135
|
-
});
|
136
|
-
altTextRow.replaceChildren(imageAltTextLabel, this.imageAltTextInput);
|
137
|
-
actionButtonRow.replaceChildren(this.submitButton);
|
138
|
-
container.replaceChildren(chooseImageRow, altTextRow, this.imagePreview, this.statusView, actionButtonRow);
|
139
|
-
dropdown.replaceChildren(container);
|
140
|
-
return true;
|
141
|
-
}
|
142
|
-
onImageDataUpdate() {
|
143
|
-
const base64Data = this.image?.getBase64Url();
|
144
|
-
if (base64Data) {
|
145
|
-
this.submitButton.disabled = false;
|
146
|
-
this.submitButton.style.display = '';
|
147
|
-
this.imagePreview.style.display = '';
|
148
|
-
this.updateImageSizeDisplay();
|
149
|
-
}
|
150
|
-
else {
|
151
|
-
this.submitButton.disabled = true;
|
152
|
-
this.submitButton.style.display = 'none';
|
153
|
-
this.statusView.innerText = '';
|
154
|
-
this.imagePreview.style.display = 'none';
|
155
|
-
this.submitButton.disabled = true;
|
156
|
-
}
|
157
|
-
}
|
158
|
-
hideDialog() {
|
159
|
-
this.setDropdownVisible(false);
|
160
|
-
}
|
161
|
-
updateImageSizeDisplay() {
|
162
|
-
const imageData = this.image?.getBase64Url() ?? '';
|
163
|
-
const sizeInKiB = imageData.length / 1024;
|
164
|
-
const sizeInMiB = sizeInKiB / 1024;
|
165
|
-
let units = 'KiB';
|
166
|
-
let size = sizeInKiB;
|
167
|
-
if (sizeInMiB >= 1) {
|
168
|
-
size = sizeInMiB;
|
169
|
-
units = 'MiB';
|
170
|
-
}
|
171
|
-
const sizeText = document.createElement('span');
|
172
|
-
sizeText.innerText = this.localizationTable.imageSize(Math.round(size), units);
|
173
|
-
// Add a button to allow decreasing the size of large images.
|
174
|
-
const decreaseSizeButton = document.createElement('button');
|
175
|
-
decreaseSizeButton.innerText = this.localizationTable.decreaseImageSize;
|
176
|
-
decreaseSizeButton.onclick = () => {
|
177
|
-
this.image?.decreaseSize();
|
178
|
-
};
|
179
|
-
const resetSizeButton = document.createElement('button');
|
180
|
-
resetSizeButton.innerText = this.localizationTable.resetImage;
|
181
|
-
resetSizeButton.onclick = () => {
|
182
|
-
this.image?.reset();
|
183
|
-
};
|
184
|
-
this.statusView.replaceChildren(sizeText);
|
185
|
-
const largeImageThreshold = 0.12; // MiB
|
186
|
-
if (sizeInMiB > largeImageThreshold) {
|
187
|
-
this.statusView.appendChild(decreaseSizeButton);
|
188
|
-
}
|
189
|
-
else if (this.image?.isChanged()) {
|
190
|
-
this.statusView.appendChild(resetSizeButton);
|
191
|
-
}
|
192
|
-
}
|
193
|
-
updateInputs() {
|
194
|
-
const resetInputs = () => {
|
195
|
-
this.selectedFiles?.set([]);
|
196
|
-
this.imageAltTextInput.value = '';
|
197
|
-
this.imagePreview.style.display = 'none';
|
198
|
-
this.submitButton.disabled = true;
|
199
|
-
this.statusView.innerText = '';
|
200
|
-
this.submitButton.style.display = '';
|
201
|
-
this.imageAltTextInput.oninput = null;
|
202
|
-
};
|
203
|
-
resetInputs();
|
204
|
-
const selectionTools = this.editor.toolController.getMatchingTools(SelectionTool_1.default);
|
205
|
-
const selectedObjects = selectionTools.map(tool => tool.getSelectedObjects()).flat();
|
206
|
-
// Check: Is there a selected image that can be edited?
|
207
|
-
let editingImage = null;
|
208
|
-
if (selectedObjects.length === 1 && selectedObjects[0] instanceof ImageComponent_1.default) {
|
209
|
-
editingImage = selectedObjects[0];
|
210
|
-
this.imageAltTextInput.value = editingImage.getAltText() ?? '';
|
211
|
-
this.image = ImageWrapper.fromSrcAndPreview(editingImage.getURL(), this.imagePreview, () => this.onImageDataUpdate());
|
212
|
-
this.onImageDataUpdate();
|
213
|
-
}
|
214
|
-
else if (selectedObjects.length > 0) {
|
215
|
-
// If not, clear the selection.
|
216
|
-
selectionTools.forEach(tool => tool.clearSelection());
|
217
|
-
}
|
218
|
-
// Show the submit button only when there is data to submit.
|
219
|
-
this.submitButton.style.display = 'none';
|
220
|
-
this.imageAltTextInput.oninput = () => {
|
221
|
-
if (this.imagePreview.src?.length > 0) {
|
222
|
-
this.submitButton.style.display = '';
|
223
|
-
}
|
224
|
-
};
|
225
|
-
this.submitButton.onclick = async () => {
|
226
|
-
if (!this.image) {
|
227
|
-
return;
|
228
|
-
}
|
229
|
-
const image = new Image();
|
230
|
-
image.src = this.image.getBase64Url();
|
231
|
-
image.setAttribute('alt', this.imageAltTextInput.value);
|
232
|
-
let component;
|
233
|
-
try {
|
234
|
-
component = await ImageComponent_1.default.fromImage(image, math_1.Mat33.identity);
|
235
|
-
}
|
236
|
-
catch (error) {
|
237
|
-
console.error('Error loading image', error);
|
238
|
-
this.statusView.innerText = this.localizationTable.imageLoadError(error);
|
239
|
-
return;
|
240
|
-
}
|
241
|
-
if (component.getBBox().area === 0) {
|
242
|
-
this.statusView.innerText = this.localizationTable.errorImageHasZeroSize;
|
243
|
-
return;
|
244
|
-
}
|
245
|
-
this.hideDialog();
|
246
|
-
if (editingImage) {
|
247
|
-
const eraseCommand = new Erase_1.default([editingImage]);
|
248
|
-
// Try to preserve the original width
|
249
|
-
const originalTransform = editingImage.getTransformation();
|
250
|
-
// || 1: Prevent division by zero
|
251
|
-
const originalWidth = editingImage.getBBox().width || 1;
|
252
|
-
const newWidth = component.getBBox().transformedBoundingBox(originalTransform).width || 1;
|
253
|
-
const widthAdjustTransform = math_1.Mat33.scaling2D(originalWidth / newWidth);
|
254
|
-
await this.editor.dispatch((0, uniteCommands_1.default)([
|
255
|
-
EditorImage_1.default.addElement(component),
|
256
|
-
component.transformBy(originalTransform.rightMul(widthAdjustTransform)),
|
257
|
-
component.setZIndex(editingImage.getZIndex()),
|
258
|
-
eraseCommand,
|
259
|
-
]));
|
260
|
-
selectionTools[0]?.setSelection([component]);
|
261
|
-
}
|
262
|
-
else {
|
263
|
-
await this.editor.addAndCenterComponents([component]);
|
264
|
-
}
|
265
|
-
};
|
266
|
-
}
|
267
|
-
}
|
268
|
-
InsertImageWidget.nextInputId = 0;
|
269
|
-
exports.default = InsertImageWidget;
|
@@ -1,22 +0,0 @@
|
|
1
|
-
import Editor from '../../Editor';
|
2
|
-
import { ToolbarLocalization } from '../localization';
|
3
|
-
import BaseWidget from './BaseWidget';
|
4
|
-
export default class InsertImageWidget extends BaseWidget {
|
5
|
-
private imagePreview;
|
6
|
-
private image;
|
7
|
-
private selectedFiles;
|
8
|
-
private imageAltTextInput;
|
9
|
-
private statusView;
|
10
|
-
private submitButton;
|
11
|
-
constructor(editor: Editor, localization?: ToolbarLocalization);
|
12
|
-
protected getTitle(): string;
|
13
|
-
protected createIcon(): Element | null;
|
14
|
-
protected setDropdownVisible(visible: boolean): void;
|
15
|
-
protected handleClick(): void;
|
16
|
-
private static nextInputId;
|
17
|
-
protected fillDropdown(dropdown: HTMLElement): boolean;
|
18
|
-
private onImageDataUpdate;
|
19
|
-
private hideDialog;
|
20
|
-
private updateImageSizeDisplay;
|
21
|
-
private updateInputs;
|
22
|
-
}
|