js-draw 1.30.0 → 1.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +5 -3
  2. package/dist/bundle.js +34 -34
  3. package/dist/cjs/Editor.js +1 -1
  4. package/dist/cjs/components/ImageComponent.js +1 -1
  5. package/dist/cjs/dialogs/makeMessageDialog.js +5 -3
  6. package/dist/cjs/localizations/getLocalizationTable.js +2 -0
  7. package/dist/cjs/localizations/zh.d.ts +3 -0
  8. package/dist/cjs/localizations/zh.js +170 -0
  9. package/dist/cjs/rendering/Display.js +5 -3
  10. package/dist/cjs/toolbar/EdgeToolbar.js +3 -2
  11. package/dist/cjs/toolbar/IconProvider.js +1 -1
  12. package/dist/cjs/toolbar/utils/HelpDisplay.js +7 -6
  13. package/dist/cjs/toolbar/widgets/BaseWidget.js +1 -1
  14. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +5 -3
  15. package/dist/cjs/toolbar/widgets/HandToolWidget.js +4 -3
  16. package/dist/cjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.js +14 -11
  17. package/dist/cjs/toolbar/widgets/PenToolWidget.js +2 -1
  18. package/dist/cjs/toolbar/widgets/components/makeButtonGrid.js +3 -2
  19. package/dist/cjs/toolbar/widgets/components/makeColorInput.js +2 -1
  20. package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +2 -2
  21. package/dist/cjs/toolbar/widgets/components/makeSnappedList.js +1 -1
  22. package/dist/cjs/tools/FindTool.js +3 -2
  23. package/dist/cjs/tools/PanZoom.js +8 -2
  24. package/dist/cjs/tools/SelectionTool/SelectionMenuShortcut.js +7 -2
  25. package/dist/cjs/tools/SoundUITool.js +6 -4
  26. package/dist/cjs/tools/util/createMenuOverlay.js +9 -7
  27. package/dist/cjs/util/dom/createButton.d.ts +7 -0
  28. package/dist/cjs/util/dom/createButton.js +20 -0
  29. package/dist/cjs/util/{createElement.d.ts → dom/createElement.d.ts} +3 -0
  30. package/dist/cjs/version.js +1 -1
  31. package/dist/mjs/Editor.mjs +1 -1
  32. package/dist/mjs/components/ImageComponent.mjs +1 -1
  33. package/dist/mjs/dialogs/makeMessageDialog.mjs +5 -3
  34. package/dist/mjs/localizations/getLocalizationTable.mjs +2 -0
  35. package/dist/mjs/localizations/zh.d.ts +3 -0
  36. package/dist/mjs/localizations/zh.mjs +168 -0
  37. package/dist/mjs/rendering/Display.mjs +5 -3
  38. package/dist/mjs/toolbar/EdgeToolbar.mjs +3 -2
  39. package/dist/mjs/toolbar/IconProvider.mjs +1 -1
  40. package/dist/mjs/toolbar/utils/HelpDisplay.mjs +7 -6
  41. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +1 -1
  42. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +5 -3
  43. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +4 -3
  44. package/dist/mjs/toolbar/widgets/InsertImageWidget/InsertImageWidget.mjs +14 -11
  45. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +2 -1
  46. package/dist/mjs/toolbar/widgets/components/makeButtonGrid.mjs +3 -2
  47. package/dist/mjs/toolbar/widgets/components/makeColorInput.mjs +2 -1
  48. package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +2 -2
  49. package/dist/mjs/toolbar/widgets/components/makeSnappedList.mjs +1 -1
  50. package/dist/mjs/tools/FindTool.mjs +3 -2
  51. package/dist/mjs/tools/PanZoom.mjs +8 -2
  52. package/dist/mjs/tools/SelectionTool/SelectionMenuShortcut.mjs +4 -2
  53. package/dist/mjs/tools/SoundUITool.mjs +6 -4
  54. package/dist/mjs/tools/util/createMenuOverlay.mjs +9 -7
  55. package/dist/mjs/util/dom/createButton.d.ts +7 -0
  56. package/dist/mjs/util/dom/createButton.mjs +15 -0
  57. package/dist/mjs/util/{createElement.d.ts → dom/createElement.d.ts} +3 -0
  58. package/dist/mjs/version.mjs +1 -1
  59. package/package.json +4 -4
  60. /package/dist/cjs/util/{addLongPressOrHoverCssClasses.d.ts → dom/addLongPressOrHoverCssClasses.d.ts} +0 -0
  61. /package/dist/cjs/util/{addLongPressOrHoverCssClasses.js → dom/addLongPressOrHoverCssClasses.js} +0 -0
  62. /package/dist/cjs/util/{cloneElementWithStyles.d.ts → dom/cloneElementWithStyles.d.ts} +0 -0
  63. /package/dist/cjs/util/{cloneElementWithStyles.js → dom/cloneElementWithStyles.js} +0 -0
  64. /package/dist/cjs/util/{createElement.js → dom/createElement.js} +0 -0
  65. /package/dist/cjs/util/{listenForKeyboardEventsFrom.d.ts → dom/listenForKeyboardEventsFrom.d.ts} +0 -0
  66. /package/dist/cjs/util/{listenForKeyboardEventsFrom.js → dom/listenForKeyboardEventsFrom.js} +0 -0
  67. /package/dist/cjs/util/{listenForLongPressOrHover.d.ts → dom/listenForLongPressOrHover.d.ts} +0 -0
  68. /package/dist/cjs/util/{listenForLongPressOrHover.js → dom/listenForLongPressOrHover.js} +0 -0
  69. /package/dist/cjs/util/{listenForLongPressOrHover.test.d.ts → dom/listenForLongPressOrHover.test.d.ts} +0 -0
  70. /package/dist/cjs/util/{stopPropagationOfScrollingWheelEvents.d.ts → dom/stopPropagationOfScrollingWheelEvents.d.ts} +0 -0
  71. /package/dist/cjs/util/{stopPropagationOfScrollingWheelEvents.js → dom/stopPropagationOfScrollingWheelEvents.js} +0 -0
  72. /package/dist/cjs/util/{waitForImageLoaded.d.ts → dom/waitForImageLoaded.d.ts} +0 -0
  73. /package/dist/cjs/util/{waitForImageLoaded.js → dom/waitForImageLoaded.js} +0 -0
  74. /package/dist/mjs/util/{addLongPressOrHoverCssClasses.d.ts → dom/addLongPressOrHoverCssClasses.d.ts} +0 -0
  75. /package/dist/mjs/util/{addLongPressOrHoverCssClasses.mjs → dom/addLongPressOrHoverCssClasses.mjs} +0 -0
  76. /package/dist/mjs/util/{cloneElementWithStyles.d.ts → dom/cloneElementWithStyles.d.ts} +0 -0
  77. /package/dist/mjs/util/{cloneElementWithStyles.mjs → dom/cloneElementWithStyles.mjs} +0 -0
  78. /package/dist/mjs/util/{createElement.mjs → dom/createElement.mjs} +0 -0
  79. /package/dist/mjs/util/{listenForKeyboardEventsFrom.d.ts → dom/listenForKeyboardEventsFrom.d.ts} +0 -0
  80. /package/dist/mjs/util/{listenForKeyboardEventsFrom.mjs → dom/listenForKeyboardEventsFrom.mjs} +0 -0
  81. /package/dist/mjs/util/{listenForLongPressOrHover.d.ts → dom/listenForLongPressOrHover.d.ts} +0 -0
  82. /package/dist/mjs/util/{listenForLongPressOrHover.mjs → dom/listenForLongPressOrHover.mjs} +0 -0
  83. /package/dist/mjs/util/{listenForLongPressOrHover.test.d.ts → dom/listenForLongPressOrHover.test.d.ts} +0 -0
  84. /package/dist/mjs/util/{stopPropagationOfScrollingWheelEvents.d.ts → dom/stopPropagationOfScrollingWheelEvents.d.ts} +0 -0
  85. /package/dist/mjs/util/{stopPropagationOfScrollingWheelEvents.mjs → dom/stopPropagationOfScrollingWheelEvents.mjs} +0 -0
  86. /package/dist/mjs/util/{waitForImageLoaded.d.ts → dom/waitForImageLoaded.d.ts} +0 -0
  87. /package/dist/mjs/util/{waitForImageLoaded.mjs → dom/waitForImageLoaded.mjs} +0 -0
@@ -0,0 +1,7 @@
1
+ interface Options {
2
+ onClick?: (event: MouseEvent) => void;
3
+ text?: string;
4
+ classList?: string[];
5
+ }
6
+ declare const createButton: ({ onClick, text, classList }?: Options) => HTMLButtonElement;
7
+ export default createButton;
@@ -0,0 +1,20 @@
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 createElement_1 = __importDefault(require("./createElement"));
7
+ const createButton = ({ onClick, text, classList = [] } = {}) => {
8
+ const button = (0, createElement_1.default)('button', { type: 'button' });
9
+ if (onClick) {
10
+ button.onclick = onClick;
11
+ }
12
+ if (text) {
13
+ button.textContent = text;
14
+ }
15
+ for (const className of classList) {
16
+ button.classList.add(className);
17
+ }
18
+ return button;
19
+ };
20
+ exports.default = createButton;
@@ -11,6 +11,9 @@ interface ElementToPropertiesMap {
11
11
  'stroke-width': string;
12
12
  transform: string;
13
13
  };
14
+ button: {
15
+ type: 'button';
16
+ };
14
17
  rect: {
15
18
  stroke: string;
16
19
  fill: string;
@@ -7,5 +7,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  */
8
8
  exports.default = {
9
9
  // Note: Auto-updated by prebuild.js:
10
- number: '1.30.0',
10
+ number: '1.31.1',
11
11
  };
@@ -26,7 +26,7 @@ import makeAboutDialog from './dialogs/makeAboutDialog.mjs';
26
26
  import version from './version.mjs';
27
27
  import { editorImageToSVGSync, editorImageToSVGAsync } from './image/export/editorImageToSVG.mjs';
28
28
  import ReactiveValue, { MutableReactiveValue } from './util/ReactiveValue.mjs';
29
- import listenForKeyboardEventsFrom from './util/listenForKeyboardEventsFrom.mjs';
29
+ import listenForKeyboardEventsFrom from './util/dom/listenForKeyboardEventsFrom.mjs';
30
30
  import mitLicenseAttribution from './util/mitLicenseAttribution.mjs';
31
31
  import ClipboardHandler from './util/ClipboardHandler.mjs';
32
32
  import ContextMenuRecognizer from './tools/InputFilter/ContextMenuRecognizer.mjs';
@@ -1,7 +1,7 @@
1
1
  import { Rect2, Mat33 } from '@js-draw/math';
2
2
  import { assertIsNumber, assertIsNumberArray } from '../util/assertions.mjs';
3
3
  import AbstractComponent from './AbstractComponent.mjs';
4
- import waitForImageLoaded from '../util/waitForImageLoaded.mjs';
4
+ import waitForImageLoaded from '../util/dom/waitForImageLoaded.mjs';
5
5
  /**
6
6
  * Represents a raster image.
7
7
  *
@@ -1,3 +1,4 @@
1
+ import createButton from '../util/dom/createButton.mjs';
1
2
  import waitForTimeout from '../util/waitForTimeout.mjs';
2
3
  const makeAboutDialog = (editor, options) => {
3
4
  const overlay = document.createElement('div');
@@ -9,9 +10,10 @@ const makeAboutDialog = (editor, options) => {
9
10
  const heading = document.createElement('h1');
10
11
  heading.textContent = options.title;
11
12
  heading.setAttribute('autofocus', 'true');
12
- const closeButton = document.createElement('button');
13
- closeButton.innerText = editor.localization.closeDialog;
14
- closeButton.classList.add('close');
13
+ const closeButton = createButton({
14
+ text: editor.localization.closeDialog,
15
+ classList: ['close'],
16
+ });
15
17
  const scrollRegion = document.createElement('div');
16
18
  scrollRegion.classList.add('scroll');
17
19
  // Allow scrolling in the scrollable container -- don't forward wheel events.
@@ -1,4 +1,5 @@
1
1
  import { defaultEditorLocalization } from '../localization.mjs';
2
+ import zh from './zh.mjs';
2
3
  import de from './de.mjs';
3
4
  import en from './en.mjs';
4
5
  import es from './es.mjs';
@@ -8,6 +9,7 @@ export const allLocales = {
8
9
  en,
9
10
  es,
10
11
  sk,
12
+ zh,
11
13
  };
12
14
  // [locale]: A string in the format languageCode_Region or just languageCode. For example, en_US.
13
15
  const languageFromLocale = (locale) => {
@@ -0,0 +1,3 @@
1
+ import { EditorLocalization } from '../localization';
2
+ declare const localization: EditorLocalization;
3
+ export default localization;
@@ -0,0 +1,168 @@
1
+ import { defaultEditorLocalization } from '../localization.mjs';
2
+ // Chinese localization
3
+ const localization = {
4
+ ...defaultEditorLocalization,
5
+ help: '帮助',
6
+ helpHidden: '帮助已隐藏',
7
+ next: '下一页',
8
+ previous: '上一页',
9
+ close: '关闭',
10
+ helpScreenNavigationHelp: '点击控件查看更多信息。',
11
+ helpControlsAccessibilityLabel: '控件:激活控件以显示帮助。',
12
+ pen: '画笔',
13
+ eraser: '橡皮擦',
14
+ select: '选择',
15
+ handTool: '平移',
16
+ zoom: '缩放',
17
+ image: '图片',
18
+ reformatSelection: '格式化选区',
19
+ inputAltText: '替代文本',
20
+ decreaseImageSize: '减小尺寸',
21
+ resetImage: '重置',
22
+ chooseFile: '选择文件',
23
+ dragAndDropHereOrBrowse: '将文件拖拽到此处或{{浏览}}',
24
+ submit: '提交',
25
+ addAll: '全部添加',
26
+ cancel: '取消',
27
+ resetView: '重置视图',
28
+ thicknessLabel: '粗细',
29
+ colorLabel: '颜色',
30
+ fontLabel: '字体',
31
+ textSize: '字号',
32
+ resizeImageToSelection: '按选区调整图片大小',
33
+ deleteSelection: '删除选区',
34
+ duplicateSelection: '复制选区',
35
+ exit: '退出',
36
+ save: '保存',
37
+ undo: '撤销',
38
+ redo: '重做',
39
+ fullStrokeEraser: '全笔划橡皮擦',
40
+ selectPenType: '工具类型',
41
+ selectShape: '形状',
42
+ pickColorFromScreen: '从屏幕取色',
43
+ clickToPickColorAnnouncement: '点击屏幕以选取颜色',
44
+ colorSelectionCanceledAnnouncement: '颜色选择已取消',
45
+ selectionTool__lassoSelect: '自由选区',
46
+ selectionTool__lassoSelect__help: '启用后,拖拽将创建自由形式(套索)选区。',
47
+ selectionToolKeyboardShortcuts: '选择工具:使用方向键移动所选项目,使用小写/大写 “i” 和 “o” 调整大小。',
48
+ documentProperties: '页面',
49
+ backgroundColor: '背景色',
50
+ imageWidthOption: '宽度',
51
+ imageHeightOption: '高度',
52
+ useGridOption: '网格',
53
+ enableAutoresizeOption: '自动调整大小',
54
+ toggleOverflow: '更多',
55
+ about: '关于',
56
+ inputStabilization: '稳定',
57
+ strokeAutocorrect: '自动更正',
58
+ pressureSensitivity: '压力',
59
+ touchPanning: '触屏平移',
60
+ roundedTipPen: '自由画笔',
61
+ roundedTipPen2: '折线',
62
+ flatTipPen: '平头笔',
63
+ arrowPen: '箭头',
64
+ linePen: '直线',
65
+ outlinedRectanglePen: '空心矩形',
66
+ filledRectanglePen: '实心矩形',
67
+ outlinedCirclePen: '空心圆',
68
+ lockRotation: '锁定旋转',
69
+ paste: '粘v贴',
70
+ errorImageHasZeroSize: '错误:图片尺寸为零',
71
+ describeTheImage: '图像描述',
72
+ fileInput__loading: '加载中...',
73
+ fileInput__andNMoreFiles: (n) => `(还有 ${n} 个)`,
74
+ closeSidebar: (toolName) => `关闭 ${toolName} 的侧边栏`,
75
+ dropdownShown: (toolName) => `已显示 ${toolName} 下拉菜单`,
76
+ dropdownHidden: (toolName) => `已隐藏 ${toolName} 下拉菜单`,
77
+ zoomLevel: (zoomPercent) => `缩放:${zoomPercent}%`,
78
+ colorChangedAnnouncement: (color) => `颜色已更改为 ${color}`,
79
+ imageSize: (size, units) => `图片尺寸:${size} ${units}`,
80
+ imageLoadError: (message) => `图片加载错误:${message}`,
81
+ penTool: (penId) => `画笔 ${penId}`,
82
+ selectionTool: '选择工具',
83
+ selectAllTool: '全选',
84
+ eraserTool: '橡皮擦工具',
85
+ touchPanTool: '触屏平移工具',
86
+ twoFingerPanZoomTool: '双指平移与缩放',
87
+ undoRedoTool: '撤销/重做工具',
88
+ rightClickDragPanTool: '右键拖拽',
89
+ pipetteTool: '取色器',
90
+ keyboardPanZoom: '键盘平移与缩放快捷键',
91
+ selectionMenu__show: '显示选择菜单',
92
+ selectionMenu__copyToClipboard: '复制到剪贴板',
93
+ selectionMenu__duplicate: '复制',
94
+ selectionMenu__delete: '删除',
95
+ selectionMenu__paste: '粘贴',
96
+ copyPasteError__heading: '复制/粘贴',
97
+ copyPasteError__description: '出错了——此工具可能无法访问剪贴板。',
98
+ copyPasteError__errorDetails: '显示错误',
99
+ copyPasteError__pasteRetry: '请重试:在下方输入框中粘贴:',
100
+ copyPasteError__copyRetry: '请重试:在下方输入框中复制文本:',
101
+ copyPasteError__copyMe: '点我复制!',
102
+ autocorrectedTo: (strokeDescription) => `已自动更正为 ${strokeDescription}`,
103
+ autocorrectionCanceled: '自动更正已取消',
104
+ textTool: '文本工具',
105
+ enterTextToInsert: '输入要插入的文本',
106
+ changeTool: '切换工具',
107
+ pasteHandler: '复制粘贴处理器',
108
+ soundExplorer: '声音探索',
109
+ disableAccessibilityExploreTool: '关闭声音探索',
110
+ enableAccessibilityExploreTool: '开启声音探索',
111
+ soundExplorerUsageAnnouncement: '已启用声音图像探索:点击或拖拽屏幕,即可通过声音感受图像不同区域。',
112
+ findLabel: '查找',
113
+ toNextMatch: '下一个',
114
+ closeDialog: '关闭',
115
+ findDialogShown: '已显示查找对话框',
116
+ findDialogHidden: '已隐藏查找对话框',
117
+ focusedFoundText: (matchIdx, totalMatches) => `第 ${matchIdx} 条结果,共 ${totalMatches} 条`,
118
+ anyDevicePanning: '任意设备平移',
119
+ copied: (count) => `已复制 ${count} 个项目`,
120
+ pasted: (count) => `已粘贴 ${count} 个项目`,
121
+ toolEnabledAnnouncement: (toolName) => `${toolName} 已启用`,
122
+ toolDisabledAnnouncement: (toolName) => `${toolName} 已禁用`,
123
+ updatedViewport: '已更新视口',
124
+ transformedElements: (elemCount, action) => `${elemCount} 个元素已变换 (${action})`,
125
+ resizeOutputCommand: (newSize) => `图片尺寸已更改为 ${newSize.w}×${newSize.h}`,
126
+ enabledAutoresizeOutputCommand: '已启用输出自动调整大小',
127
+ disabledAutoresizeOutputCommand: '已禁用输出自动调整大小',
128
+ addComponentAction: (componentDescription) => `已添加 ${componentDescription}`,
129
+ eraseAction: (componentDescription, countErased) => `已删除 ${countErased} 个 ${componentDescription}`,
130
+ duplicateAction: (componentDescription, countErased) => `已复制 ${countErased} 个 ${componentDescription}`,
131
+ unionOf: (actionDescription, actionCount) => `合并:${actionCount} 个 ${actionDescription}`,
132
+ inverseOf: (actionDescription) => `${actionDescription} 已反向`,
133
+ elements: '元素',
134
+ erasedNoElements: '未v删除任何内容',
135
+ duplicatedNoElements: '未复制任何内容',
136
+ rotatedBy: (degrees) => `已旋转 ${Math.abs(degrees)} 度 ${degrees < 0 ? '顺时针' : '逆时针'}`,
137
+ movedLeft: '已向左移动',
138
+ movedUp: '已向上移动',
139
+ movedDown: '已向下移动',
140
+ movedRight: '已向右移动',
141
+ zoomedOut: '已缩小',
142
+ zoomedIn: '已放大',
143
+ andNMoreCommands: (count) => `还有 ${count} 条命令。`,
144
+ selectedElements: (count) => `已选 ${count} 个元素`,
145
+ unlabeledImageNode: '未命名图片',
146
+ stroke: '笔画',
147
+ svgObject: 'SVG 对象',
148
+ emptyBackground: '空白背景',
149
+ gridBackground: '网格背景',
150
+ filledBackgroundWithColor: (color) => `已填充背景(${color})`,
151
+ text: (text) => `文本对象:${text}`,
152
+ imageNode: (label) => `图片:${label}`,
153
+ restyledElement: (elementDescription) => `已重新样式化 ${elementDescription}`,
154
+ pathNodeCount: (count) => `可见路径对象:${count} 个`,
155
+ textNodeCount: (count) => `可见文本节点:${count} 个`,
156
+ imageNodeCount: (nodeCount) => `可见图片节点:${nodeCount} 个`,
157
+ textNode: (content) => `文本:${content}`,
158
+ rerenderAsText: '以文本形式重绘',
159
+ accessibilityInputInstructions: '按“t”将视口内容朗读为文本。使用方向键移动视口,点击并拖拽绘制笔画。按“w”放大,按“s”缩小。',
160
+ loading: (percentage) => `加载中 ${percentage}%...`,
161
+ imageEditor: '图片编辑器',
162
+ doneLoading: '加载完成',
163
+ undoAnnouncement: (commandDescription) => `已撤销 ${commandDescription}`,
164
+ redoAnnouncement: (commandDescription) => `已重做 ${commandDescription}`,
165
+ softwareLibraries: '软件库',
166
+ developerInformation: '开发者信息',
167
+ };
168
+ export default localization;
@@ -5,6 +5,7 @@ import { Vec2, Color4 } from '@js-draw/math';
5
5
  import RenderingCache from './caching/RenderingCache.mjs';
6
6
  import TextOnlyRenderer from './renderers/TextOnlyRenderer.mjs';
7
7
  import AcceleratedInkingCanvasRenderer from './renderers/AcceleratedInkingCanvasRenderer.mjs';
8
+ import createButton from '../util/dom/createButton.mjs';
8
9
  export var RenderingMode;
9
10
  (function (RenderingMode) {
10
11
  RenderingMode[RenderingMode["DummyRenderer"] = 0] = "DummyRenderer";
@@ -177,9 +178,10 @@ export default class Display {
177
178
  initializeTextRendering() {
178
179
  const textRendererOutputContainer = document.createElement('div');
179
180
  textRendererOutputContainer.classList.add('textRendererOutputContainer');
180
- const rerenderButton = document.createElement('button');
181
- rerenderButton.classList.add('rerenderButton');
182
- rerenderButton.innerText = this.editor.localization.rerenderAsText;
181
+ const rerenderButton = createButton({
182
+ classList: ['rerenderButton'],
183
+ text: this.editor.localization.rerenderAsText,
184
+ });
183
185
  this.textRerenderOutput = document.createElement('div');
184
186
  this.textRerenderOutput.setAttribute('aria-live', 'polite');
185
187
  rerenderButton.onclick = () => {
@@ -3,8 +3,9 @@ import { toolbarCSSPrefix } from './constants.mjs';
3
3
  import EdgeToolbarLayoutManager from './widgets/layout/EdgeToolbarLayoutManager.mjs';
4
4
  import { MutableReactiveValue, ReactiveValue } from '../util/ReactiveValue.mjs';
5
5
  import AbstractToolbar from './AbstractToolbar.mjs';
6
- import stopPropagationOfScrollingWheelEvents from '../util/stopPropagationOfScrollingWheelEvents.mjs';
6
+ import stopPropagationOfScrollingWheelEvents from '../util/dom/stopPropagationOfScrollingWheelEvents.mjs';
7
7
  import makeDraggable from './utils/makeDraggable.mjs';
8
+ import createButton from '../util/dom/createButton.mjs';
8
9
  /**
9
10
  * Creates an `EdgeToolbar`.
10
11
  *
@@ -85,7 +86,7 @@ export default class EdgeToolbar extends AbstractToolbar {
85
86
  this.menuContainer.classList.remove(belowEdgeClassName);
86
87
  }
87
88
  });
88
- this.closeButton = document.createElement('button');
89
+ this.closeButton = createButton();
89
90
  this.closeButton.classList.add('drag-elem');
90
91
  // The close button has default focus -- forward its events to the main editor so that keyboard
91
92
  // shortcuts still work.
@@ -10,7 +10,7 @@ import Viewport from '../Viewport.mjs';
10
10
  import { makeFreehandLineBuilder } from '../components/builders/FreehandLineBuilder.mjs';
11
11
  import { makePolylineBuilder } from '../components/builders/PolylineBuilder.mjs';
12
12
  import { EraserMode } from '../tools/Eraser.mjs';
13
- import { createSvgElement, createSvgElements, createSvgPaths } from '../util/createElement.mjs';
13
+ import { createSvgElement, createSvgElements, createSvgPaths } from '../util/dom/createElement.mjs';
14
14
  import { SelectionMode } from '../tools/SelectionTool/types.mjs';
15
15
  const svgNamespace = 'http://www.w3.org/2000/svg';
16
16
  let checkerboardIdCounter = 0;
@@ -7,8 +7,9 @@ var _HelpDisplay_helpData;
7
7
  import { Rect2 } from '@js-draw/math';
8
8
  import makeDraggable from './makeDraggable.mjs';
9
9
  import { MutableReactiveValue } from '../../util/ReactiveValue.mjs';
10
- import cloneElementWithStyles from '../../util/cloneElementWithStyles.mjs';
11
- import addLongPressOrHoverCssClasses from '../../util/addLongPressOrHoverCssClasses.mjs';
10
+ import cloneElementWithStyles from '../../util/dom/cloneElementWithStyles.mjs';
11
+ import addLongPressOrHoverCssClasses from '../../util/dom/addLongPressOrHoverCssClasses.mjs';
12
+ import createButton from '../../util/dom/createButton.mjs';
12
13
  /**
13
14
  * Creates the main content of the help overlay.
14
15
  *
@@ -214,7 +215,7 @@ class HelpDisplay {
214
215
  }
215
216
  };
216
217
  const makeCloseButton = () => {
217
- const closeButton = document.createElement('button');
218
+ const closeButton = createButton();
218
219
  closeButton.classList.add('close-button');
219
220
  closeButton.appendChild(this.context.icons.makeCloseIcon());
220
221
  const label = this.context.localization.close;
@@ -273,8 +274,8 @@ class HelpDisplay {
273
274
  const makeNavigationButtons = (navigation) => {
274
275
  const navigationButtonContainer = document.createElement('div');
275
276
  navigationButtonContainer.classList.add('navigation-buttons');
276
- const nextButton = document.createElement('button');
277
- const previousButton = document.createElement('button');
277
+ const nextButton = createButton();
278
+ const previousButton = createButton();
278
279
  nextButton.textContent = this.context.localization.next;
279
280
  previousButton.textContent = this.context.localization.previous;
280
281
  nextButton.classList.add('next');
@@ -424,7 +425,7 @@ class HelpDisplay {
424
425
  createToggleButton() {
425
426
  const buttonContainer = document.createElement('div');
426
427
  buttonContainer.classList.add('toolbar-help-overlay-button');
427
- const helpButton = document.createElement('button');
428
+ const helpButton = createButton();
428
429
  helpButton.classList.add('button');
429
430
  const icon = this.context.icons.makeHelpIcon();
430
431
  icon.classList.add('icon');
@@ -14,7 +14,7 @@ import ToolbarShortcutHandler from '../../tools/ToolbarShortcutHandler.mjs';
14
14
  import { keyPressEventFromHTMLEvent, keyUpEventFromHTMLEvent, } from '../../inputEvents.mjs';
15
15
  import { toolbarCSSPrefix } from '../constants.mjs';
16
16
  import DropdownLayoutManager from './layout/DropdownLayoutManager.mjs';
17
- import addLongPressOrHoverCssClasses from '../../util/addLongPressOrHoverCssClasses.mjs';
17
+ import addLongPressOrHoverCssClasses from '../../util/dom/addLongPressOrHoverCssClasses.mjs';
18
18
  import HelpDisplay from '../utils/HelpDisplay.mjs';
19
19
  import { assertIsObject } from '../../util/assertions.mjs';
20
20
  /**
@@ -7,6 +7,7 @@ import { EditorEventType } from '../../types.mjs';
7
7
  import { toolbarCSSPrefix } from '../constants.mjs';
8
8
  import makeColorInput from './components/makeColorInput.mjs';
9
9
  import BaseWidget from './BaseWidget.mjs';
10
+ import createButton from '../../util/dom/createButton.mjs';
10
11
  class DocumentPropertiesWidget extends BaseWidget {
11
12
  constructor(editor, localizationTable) {
12
13
  super(editor, 'document-properties-widget', localizationTable);
@@ -216,9 +217,10 @@ class DocumentPropertiesWidget extends BaseWidget {
216
217
  this.editor.dispatch(image.setAutoresizeEnabled(checked));
217
218
  });
218
219
  // The "About..." button
219
- const aboutButton = document.createElement('button');
220
- aboutButton.classList.add('about-button');
221
- aboutButton.innerText = this.localizationTable.about;
220
+ const aboutButton = createButton({
221
+ classList: ['about-button'],
222
+ text: this.localizationTable.about,
223
+ });
222
224
  aboutButton.onclick = () => {
223
225
  this.editor.showAboutDialog();
224
226
  };
@@ -6,11 +6,12 @@ import { toolbarCSSPrefix } from '../constants.mjs';
6
6
  import BaseToolWidget from './BaseToolWidget.mjs';
7
7
  import BaseWidget from './BaseWidget.mjs';
8
8
  import makeSeparator from './components/makeSeparator.mjs';
9
+ import createButton from '../../util/dom/createButton.mjs';
9
10
  const makeZoomControl = (localizationTable, editor, helpDisplay) => {
10
11
  const zoomLevelRow = document.createElement('div');
11
- const increaseButton = document.createElement('button');
12
- const decreaseButton = document.createElement('button');
13
- const resetViewButton = document.createElement('button');
12
+ const increaseButton = createButton();
13
+ const decreaseButton = createButton();
14
+ const resetViewButton = createButton();
14
15
  const zoomLevelDisplay = document.createElement('span');
15
16
  increaseButton.innerText = '+';
16
17
  decreaseButton.innerText = '-';
@@ -13,6 +13,7 @@ import bytesToSizeString from '../../../util/bytesToSizeString.mjs';
13
13
  import { ImageWrapper } from './ImageWrapper.mjs';
14
14
  import makeSnappedList from '../components/makeSnappedList.mjs';
15
15
  import fileToImages from './fileToImages.mjs';
16
+ import createButton from '../../../util/dom/createButton.mjs';
16
17
  /**
17
18
  * Provides a widget that allows inserting or modifying raster images.
18
19
  *
@@ -78,7 +79,7 @@ class InsertImageWidget extends BaseWidget {
78
79
  const actionButtonRow = document.createElement('div');
79
80
  actionButtonRow.classList.add('action-button-row');
80
81
  this.statusView.classList.add('insert-image-image-status-view');
81
- this.submitButton = document.createElement('button');
82
+ this.submitButton = createButton();
82
83
  this.selectedFiles = selectedFiles;
83
84
  this.imageAltTextInput = document.createElement('input');
84
85
  // Label the alt text input
@@ -165,16 +166,18 @@ class InsertImageWidget extends BaseWidget {
165
166
  const sizeText = document.createElement('span');
166
167
  sizeText.innerText = this.localizationTable.imageSize(Math.round(size), units);
167
168
  // Add a button to allow decreasing the size of large images.
168
- const decreaseSizeButton = document.createElement('button');
169
- decreaseSizeButton.innerText = this.localizationTable.decreaseImageSize;
170
- decreaseSizeButton.onclick = () => {
171
- currentImage?.decreaseSize();
172
- };
173
- const resetSizeButton = document.createElement('button');
174
- resetSizeButton.innerText = this.localizationTable.resetImage;
175
- resetSizeButton.onclick = () => {
176
- currentImage?.reset();
177
- };
169
+ const decreaseSizeButton = createButton({
170
+ text: this.localizationTable.decreaseImageSize,
171
+ onClick: () => {
172
+ currentImage?.decreaseSize();
173
+ },
174
+ });
175
+ const resetSizeButton = createButton({
176
+ text: this.localizationTable.resetImage,
177
+ onClick: () => {
178
+ currentImage?.reset();
179
+ },
180
+ });
178
181
  this.statusView.replaceChildren(sizeText);
179
182
  if (currentImage?.isLarge()) {
180
183
  this.statusView.appendChild(decreaseSizeButton);
@@ -13,6 +13,7 @@ import { toolbarCSSPrefix } from '../constants.mjs';
13
13
  import makeThicknessSlider from './components/makeThicknessSlider.mjs';
14
14
  import makeGridSelector from './components/makeGridSelector.mjs';
15
15
  import { makePolylineBuilder } from '../../components/builders/PolylineBuilder.mjs';
16
+ import createElement from '../../util/dom/createElement.mjs';
16
17
  /**
17
18
  * This toolbar widget allows a user to control a single {@link Pen} tool.
18
19
  *
@@ -179,7 +180,7 @@ class PenToolWidget extends BaseToolWidget {
179
180
  const container = document.createElement('div');
180
181
  container.classList.add('action-button-row', `${toolbarCSSPrefix}-pen-tool-toggle-buttons`);
181
182
  const addToggleButton = (labelText, icon) => {
182
- const button = document.createElement('button');
183
+ const button = createElement('button', { type: 'button' });
183
184
  button.classList.add(`${toolbarCSSPrefix}-toggle-button`);
184
185
  const iconElement = icon.cloneNode(true);
185
186
  iconElement.classList.add('icon');
@@ -1,4 +1,5 @@
1
- import addLongPressOrHoverCssClasses from '../../../util/addLongPressOrHoverCssClasses.mjs';
1
+ import addLongPressOrHoverCssClasses from '../../../util/dom/addLongPressOrHoverCssClasses.mjs';
2
+ import createButton from '../../../util/dom/createButton.mjs';
2
3
  /**
3
4
  * Creates HTML `button` elements from `buttonSpecs` and displays them in a
4
5
  * grid with `columnCount` columns.
@@ -8,7 +9,7 @@ const makeButtonGrid = (buttonSpecs, columnCount) => {
8
9
  container.classList.add('toolbar-button-grid');
9
10
  container.style.setProperty('--column-count', `${columnCount}`);
10
11
  const makeButton = (buttonSpec) => {
11
- const buttonElement = document.createElement('button');
12
+ const buttonElement = createButton();
12
13
  buttonElement.classList.add('button');
13
14
  const iconElement = buttonSpec.icon();
14
15
  iconElement.classList.add('icon');
@@ -1,6 +1,7 @@
1
1
  import { Color4 } from '@js-draw/math';
2
2
  import PipetteTool from '../../../tools/PipetteTool.mjs';
3
3
  import { EditorEventType } from '../../../types.mjs';
4
+ import createButton from '../../../util/dom/createButton.mjs';
4
5
  // Returns [ color input, input container, callback to change the color value ].
5
6
  export const makeColorInput = (editor, onColorChange) => {
6
7
  const container = document.createElement('span');
@@ -93,7 +94,7 @@ export const makeColorInput = (editor, onColorChange) => {
93
94
  };
94
95
  };
95
96
  const addPipetteTool = (editor, container, onColorChange) => {
96
- const pipetteButton = document.createElement('button');
97
+ const pipetteButton = createButton();
97
98
  pipetteButton.classList.add('pipetteButton');
98
99
  pipetteButton.title = editor.localization.pickColorFromScreen;
99
100
  pipetteButton.setAttribute('alt', pipetteButton.title);
@@ -1,6 +1,6 @@
1
1
  import { MutableReactiveValue } from '../../../util/ReactiveValue.mjs';
2
- import stopPropagationOfScrollingWheelEvents from '../../../util/stopPropagationOfScrollingWheelEvents.mjs';
3
- import addLongPressOrHoverCssClasses from '../../../util/addLongPressOrHoverCssClasses.mjs';
2
+ import stopPropagationOfScrollingWheelEvents from '../../../util/dom/stopPropagationOfScrollingWheelEvents.mjs';
3
+ import addLongPressOrHoverCssClasses from '../../../util/dom/addLongPressOrHoverCssClasses.mjs';
4
4
  import { toolbarCSSPrefix } from '../../constants.mjs';
5
5
  let idCounter = 0;
6
6
  /**
@@ -1,4 +1,4 @@
1
- import stopPropagationOfScrollingWheelEvents from '../../../util/stopPropagationOfScrollingWheelEvents.mjs';
1
+ import stopPropagationOfScrollingWheelEvents from '../../../util/dom/stopPropagationOfScrollingWheelEvents.mjs';
2
2
  import { MutableReactiveValue, ReactiveValue } from '../../../util/ReactiveValue.mjs';
3
3
  /**
4
4
  * Creates a list that snaps to each item and reports the selected item.
@@ -5,6 +5,7 @@ import TextComponent from '../components/TextComponent.mjs';
5
5
  import ImageComponent from '../components/ImageComponent.mjs';
6
6
  import BaseTool from './BaseTool.mjs';
7
7
  import { toggleFindVisibleShortcutId } from './keybindings.mjs';
8
+ import createButton from '../util/dom/createButton.mjs';
8
9
  const cssPrefix = 'find-tool';
9
10
  export default class FindTool extends BaseTool {
10
11
  constructor(editor) {
@@ -62,8 +63,8 @@ export default class FindTool extends BaseTool {
62
63
  fillOverlay() {
63
64
  const label = document.createElement('label');
64
65
  this.searchInput = document.createElement('input');
65
- const nextBtn = document.createElement('button');
66
- const closeBtn = document.createElement('button');
66
+ const nextBtn = createButton();
67
+ const closeBtn = createButton();
67
68
  // Math.random() ensures that the ID is unique (to allow us to refer to it
68
69
  // with an htmlFor).
69
70
  this.searchInput.setAttribute('id', `${cssPrefix}-searchInput-${Math.random()}`);
@@ -125,9 +125,15 @@ export default class PanZoom extends BaseTool {
125
125
  this.inertialScroller?.stop();
126
126
  this.velocity = inertialScrollerVelocity;
127
127
  this.lastPointerDownTimestamp = currentPointer.timeStamp;
128
- const allAreTouch = this.allPointersAreOfType(pointers, PointerDevice.Touch);
129
128
  const isRightClick = this.allPointersAreOfType(pointers, PointerDevice.RightButtonMouse);
130
- if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
129
+ // Work around a Chromium bug where touch events are reported to have unknown type.
130
+ // See https://issues.chromium.org/u/1/issues/428153664.
131
+ const allAreTouch = this.allPointersAreOfType(pointers, PointerDevice.Touch);
132
+ const allAreUnknown = this.allPointersAreOfType(pointers, PointerDevice.Other);
133
+ const allAreProbablyTouch = allAreTouch || allAreUnknown;
134
+ if (allAreProbablyTouch &&
135
+ pointers.length === 2 &&
136
+ this.mode & PanZoomMode.TwoFingerTouchGestures) {
131
137
  const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
132
138
  this.lastTouchDist = dist;
133
139
  this.startTouchDist = dist;
@@ -1,5 +1,6 @@
1
1
  import { Rect2, Vec2 } from '@js-draw/math';
2
2
  import { cssPrefix } from './SelectionTool.mjs';
3
+ import createButton from '../../util/dom/createButton.mjs';
3
4
  const verticalOffset = 40;
4
5
  export default class SelectionMenuShortcut {
5
6
  constructor(parent, viewport, icon, showContextMenu, localization) {
@@ -20,8 +21,9 @@ export default class SelectionMenuShortcut {
20
21
  this.updatePosition();
21
22
  }
22
23
  initUI() {
23
- const button = document.createElement('button');
24
- this.icon.classList.add('icon');
24
+ const button = createButton({
25
+ classList: ['icon'],
26
+ });
25
27
  button.replaceChildren(this.icon);
26
28
  button.ariaLabel = this.localization.selectionMenu__show;
27
29
  button.title = button.ariaLabel;
@@ -1,5 +1,6 @@
1
1
  import { LineSegment2, Color4 } from '@js-draw/math';
2
2
  import BaseTool from './BaseTool.mjs';
3
+ import createButton from '../util/dom/createButton.mjs';
3
4
  class SoundFeedback {
4
5
  constructor() {
5
6
  this.closed = false;
@@ -92,10 +93,11 @@ export default class SoundUITool extends BaseTool {
92
93
  // Create a screen-reader-usable method of toggling the tool:
93
94
  this.toggleButtonContainer = document.createElement('div');
94
95
  this.toggleButtonContainer.classList.add('js-draw-sound-ui-toggle');
95
- this.toggleButton = document.createElement('button');
96
- this.toggleButton.onclick = () => {
97
- this.setEnabled(!this.isEnabled());
98
- };
96
+ this.toggleButton = createButton({
97
+ onClick: () => {
98
+ this.setEnabled(!this.isEnabled());
99
+ },
100
+ });
99
101
  this.toggleButtonContainer.appendChild(this.toggleButton);
100
102
  this.updateToggleButtonText();
101
103
  editor.createHTMLOverlay(this.toggleButtonContainer);