js-draw 1.14.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. package/dist/Editor.css +288 -1
  2. package/dist/bundle.js +2 -2
  3. package/dist/bundledStyles.js +1 -1
  4. package/dist/cjs/Editor.js +5 -0
  5. package/dist/cjs/components/util/StrokeSmoother.js +11 -4
  6. package/dist/cjs/rendering/caching/CacheRecordManager.js +1 -1
  7. package/dist/cjs/rendering/renderers/CanvasRenderer.js +1 -1
  8. package/dist/cjs/testing/sendHtmlSwipe.d.ts +4 -0
  9. package/dist/cjs/testing/sendHtmlSwipe.js +14 -0
  10. package/dist/cjs/toolbar/EdgeToolbar.d.ts +1 -0
  11. package/dist/cjs/toolbar/EdgeToolbar.js +30 -110
  12. package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
  13. package/dist/cjs/toolbar/IconProvider.js +27 -0
  14. package/dist/cjs/toolbar/localization.d.ts +28 -1
  15. package/dist/cjs/toolbar/localization.js +30 -1
  16. package/dist/cjs/toolbar/utils/HelpDisplay.d.ts +37 -0
  17. package/dist/cjs/toolbar/utils/HelpDisplay.js +442 -0
  18. package/dist/cjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
  19. package/dist/cjs/toolbar/utils/localization.d.ts +9 -0
  20. package/dist/cjs/toolbar/utils/localization.js +11 -0
  21. package/dist/cjs/toolbar/utils/makeDraggable.d.ts +16 -0
  22. package/dist/cjs/toolbar/utils/makeDraggable.js +130 -0
  23. package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
  24. package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +14 -2
  25. package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +8 -1
  26. package/dist/cjs/toolbar/widgets/BaseWidget.js +25 -3
  27. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
  28. package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +19 -4
  29. package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
  30. package/dist/cjs/toolbar/widgets/HandToolWidget.js +19 -7
  31. package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -0
  32. package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
  33. package/dist/cjs/toolbar/widgets/PenToolWidget.js +27 -8
  34. package/dist/cjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
  35. package/dist/cjs/toolbar/widgets/SelectionToolWidget.js +19 -5
  36. package/dist/cjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
  37. package/dist/cjs/toolbar/widgets/components/makeColorInput.js +17 -7
  38. package/dist/cjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
  39. package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +3 -0
  40. package/dist/cjs/tools/FindTool.js +18 -5
  41. package/dist/cjs/tools/PanZoom.d.ts +8 -2
  42. package/dist/cjs/tools/PanZoom.js +29 -10
  43. package/dist/cjs/tools/SelectionTool/Selection.js +16 -2
  44. package/dist/cjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
  45. package/dist/cjs/util/addLongPressOrHoverCssClasses.js +2 -1
  46. package/dist/cjs/util/cloneElementWithStyles.d.ts +6 -0
  47. package/dist/cjs/util/cloneElementWithStyles.js +32 -0
  48. package/dist/cjs/version.js +1 -1
  49. package/dist/mjs/Editor.mjs +5 -0
  50. package/dist/mjs/components/util/StrokeSmoother.mjs +11 -4
  51. package/dist/mjs/rendering/caching/CacheRecordManager.mjs +1 -1
  52. package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +1 -1
  53. package/dist/mjs/testing/sendHtmlSwipe.d.ts +4 -0
  54. package/dist/mjs/testing/sendHtmlSwipe.mjs +12 -0
  55. package/dist/mjs/toolbar/EdgeToolbar.d.ts +1 -0
  56. package/dist/mjs/toolbar/EdgeToolbar.mjs +30 -110
  57. package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
  58. package/dist/mjs/toolbar/IconProvider.mjs +27 -0
  59. package/dist/mjs/toolbar/localization.d.ts +28 -1
  60. package/dist/mjs/toolbar/localization.mjs +30 -1
  61. package/dist/mjs/toolbar/utils/HelpDisplay.d.ts +37 -0
  62. package/dist/mjs/toolbar/utils/HelpDisplay.mjs +437 -0
  63. package/dist/mjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
  64. package/dist/mjs/toolbar/utils/localization.d.ts +9 -0
  65. package/dist/mjs/toolbar/utils/localization.mjs +8 -0
  66. package/dist/mjs/toolbar/utils/makeDraggable.d.ts +16 -0
  67. package/dist/mjs/toolbar/utils/makeDraggable.mjs +128 -0
  68. package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
  69. package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +14 -2
  70. package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +8 -1
  71. package/dist/mjs/toolbar/widgets/BaseWidget.mjs +25 -3
  72. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
  73. package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +19 -4
  74. package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
  75. package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +19 -7
  76. package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -0
  77. package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
  78. package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +27 -8
  79. package/dist/mjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
  80. package/dist/mjs/toolbar/widgets/SelectionToolWidget.mjs +19 -5
  81. package/dist/mjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
  82. package/dist/mjs/toolbar/widgets/components/makeColorInput.mjs +17 -7
  83. package/dist/mjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
  84. package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +3 -0
  85. package/dist/mjs/tools/FindTool.mjs +18 -5
  86. package/dist/mjs/tools/PanZoom.d.ts +8 -2
  87. package/dist/mjs/tools/PanZoom.mjs +29 -10
  88. package/dist/mjs/tools/SelectionTool/Selection.mjs +16 -2
  89. package/dist/mjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
  90. package/dist/mjs/util/addLongPressOrHoverCssClasses.mjs +2 -1
  91. package/dist/mjs/util/cloneElementWithStyles.d.ts +6 -0
  92. package/dist/mjs/util/cloneElementWithStyles.mjs +30 -0
  93. package/dist/mjs/version.mjs +1 -1
  94. package/package.json +3 -3
  95. package/src/toolbar/EdgeToolbar.scss +23 -2
  96. package/src/toolbar/toolbar.scss +2 -0
  97. package/src/toolbar/utils/HelpDisplay.scss +315 -0
  98. package/src/toolbar/widgets/components/makeColorInput.scss +7 -0
  99. package/src/tools/SelectionTool/SelectionTool.scss +4 -0
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const math_1 = require("@js-draw/math");
4
+ const makeDraggable = (dragElement, options) => {
5
+ const dragElements = [
6
+ ...options.draggableChildElements,
7
+ dragElement,
8
+ ];
9
+ let lastX = 0;
10
+ let lastY = 0;
11
+ let startX = 0;
12
+ let startY = 0;
13
+ let pointerDown = false;
14
+ let capturedPointerId = null;
15
+ const isDraggableElement = (element) => {
16
+ if (!element) {
17
+ return false;
18
+ }
19
+ if (dragElements.includes(element)) {
20
+ return true;
21
+ }
22
+ // Some inputs handle dragging themselves. Don't also interpret such gestures
23
+ // as dragging the dropdown.
24
+ const undraggableElementTypes = ['INPUT', 'SELECT', 'IMG'];
25
+ let hasSuitableAncestors = false;
26
+ let ancestor = element.parentElement;
27
+ while (ancestor) {
28
+ if (undraggableElementTypes.includes(ancestor.tagName)) {
29
+ break;
30
+ }
31
+ if (dragElements.includes(ancestor)) {
32
+ hasSuitableAncestors = true;
33
+ break;
34
+ }
35
+ ancestor = ancestor.parentElement;
36
+ }
37
+ return !undraggableElementTypes.includes(element.tagName) && hasSuitableAncestors;
38
+ };
39
+ const removeEventListenerCallbacks = [];
40
+ const addEventListener = (listenerType, listener, options) => {
41
+ dragElement.addEventListener(listenerType, listener, options);
42
+ removeEventListenerCallbacks.push(() => {
43
+ dragElement.removeEventListener(listenerType, listener);
44
+ });
45
+ };
46
+ const clickThreshold = 5;
47
+ // Returns whether the current (or if no current, **the last**) gesture is roughly a click.
48
+ // Because this can be called **after** a gesture has just ended, it should not require
49
+ // the gesture to be in progress.
50
+ const isRoughlyClick = () => {
51
+ return Math.hypot(lastX - startX, lastY - startY) < clickThreshold;
52
+ };
53
+ let startedDragging = false;
54
+ addEventListener('pointerdown', event => {
55
+ if (event.defaultPrevented || !isDraggableElement(event.target)) {
56
+ return;
57
+ }
58
+ if (event.isPrimary) {
59
+ startedDragging = false;
60
+ lastX = event.clientX;
61
+ lastY = event.clientY;
62
+ startX = event.clientX;
63
+ startY = event.clientY;
64
+ capturedPointerId = null;
65
+ pointerDown = true;
66
+ }
67
+ }, { passive: true });
68
+ const onGestureEnd = (_event) => {
69
+ // If the pointerup/pointercancel event was for a pointer not being tracked,
70
+ if (!pointerDown) {
71
+ return;
72
+ }
73
+ if (capturedPointerId !== null) {
74
+ dragElement.releasePointerCapture(capturedPointerId);
75
+ capturedPointerId = null;
76
+ }
77
+ options.onDragEnd({
78
+ roughlyClick: isRoughlyClick(),
79
+ endTimestamp: performance.now(),
80
+ displacement: math_1.Vec2.of(lastX - startX, lastY - startY),
81
+ });
82
+ pointerDown = false;
83
+ startedDragging = false;
84
+ };
85
+ addEventListener('pointermove', event => {
86
+ if (!event.isPrimary || !pointerDown) {
87
+ return undefined;
88
+ }
89
+ // Mouse event and no buttons pressed? Cancel the event.
90
+ // This can happen if the event was canceled by a focus change (e.g. by opening a
91
+ // right-click menu).
92
+ if (event.pointerType === 'mouse' && event.buttons === 0) {
93
+ onGestureEnd(event);
94
+ return undefined;
95
+ }
96
+ // Only capture after motion -- capturing early prevents click events in Chrome.
97
+ if (capturedPointerId === null && !isRoughlyClick()) {
98
+ dragElement.setPointerCapture(event.pointerId);
99
+ capturedPointerId = event.pointerId;
100
+ }
101
+ const x = event.clientX;
102
+ const y = event.clientY;
103
+ const dx = x - lastX;
104
+ const dy = y - lastY;
105
+ const isClick = Math.abs(x - startX) <= clickThreshold && Math.abs(y - startY) <= clickThreshold;
106
+ if (!isClick || startedDragging) {
107
+ options.onDrag(dx, dy, math_1.Vec2.of(x - startX, y - startY));
108
+ lastX = x;
109
+ lastY = y;
110
+ startedDragging = true;
111
+ }
112
+ });
113
+ addEventListener('pointerleave', event => {
114
+ // Capture the pointer if it exits the container while dragging.
115
+ if (capturedPointerId === null && pointerDown && event.isPrimary) {
116
+ dragElement.setPointerCapture(event.pointerId);
117
+ capturedPointerId = event.pointerId;
118
+ }
119
+ });
120
+ addEventListener('pointerup', onGestureEnd);
121
+ addEventListener('pointercancel', onGestureEnd);
122
+ return {
123
+ removeListeners: () => {
124
+ for (const removeListenerCallback of removeEventListenerCallbacks) {
125
+ removeListenerCallback();
126
+ }
127
+ },
128
+ };
129
+ };
130
+ exports.default = makeDraggable;
@@ -8,6 +8,13 @@ export default class ActionButtonWidget extends BaseWidget {
8
8
  protected clickAction: () => void;
9
9
  protected mustBeToplevel: boolean;
10
10
  constructor(editor: Editor, id: string, makeIcon: () => Element | null, title: string, clickAction: () => void, localizationTable?: ToolbarLocalization, mustBeToplevel?: boolean, autoDisableInReadOnlyEditors?: boolean);
11
+ /**
12
+ * Sets the text shown in a help overlay for this button.
13
+ *
14
+ * See {@link getHelpText}.
15
+ */
16
+ setHelpText(helpText: string): void;
17
+ protected getHelpText(): string | undefined;
11
18
  protected shouldAutoDisableInReadOnlyEditor(): boolean;
12
19
  protected handleClick(): void;
13
20
  protected getTitle(): string;
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _ActionButtonWidget_autoDisableInReadOnlyEditors;
16
+ var _ActionButtonWidget_autoDisableInReadOnlyEditors, _ActionButtonWidget_helpText;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const BaseWidget_1 = __importDefault(require("./BaseWidget"));
19
19
  class ActionButtonWidget extends BaseWidget_1.default {
@@ -24,8 +24,20 @@ class ActionButtonWidget extends BaseWidget_1.default {
24
24
  this.clickAction = clickAction;
25
25
  this.mustBeToplevel = mustBeToplevel;
26
26
  _ActionButtonWidget_autoDisableInReadOnlyEditors.set(this, void 0);
27
+ _ActionButtonWidget_helpText.set(this, undefined);
27
28
  __classPrivateFieldSet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, autoDisableInReadOnlyEditors, "f");
28
29
  }
30
+ /**
31
+ * Sets the text shown in a help overlay for this button.
32
+ *
33
+ * See {@link getHelpText}.
34
+ */
35
+ setHelpText(helpText) {
36
+ __classPrivateFieldSet(this, _ActionButtonWidget_helpText, helpText, "f");
37
+ }
38
+ getHelpText() {
39
+ return __classPrivateFieldGet(this, _ActionButtonWidget_helpText, "f");
40
+ }
29
41
  shouldAutoDisableInReadOnlyEditor() {
30
42
  return __classPrivateFieldGet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, "f");
31
43
  }
@@ -45,5 +57,5 @@ class ActionButtonWidget extends BaseWidget_1.default {
45
57
  return this.mustBeToplevel;
46
58
  }
47
59
  }
48
- _ActionButtonWidget_autoDisableInReadOnlyEditors = new WeakMap();
60
+ _ActionButtonWidget_autoDisableInReadOnlyEditors = new WeakMap(), _ActionButtonWidget_helpText = new WeakMap();
49
61
  exports.default = ActionButtonWidget;
@@ -2,6 +2,7 @@ import Editor from '../../Editor';
2
2
  import { KeyPressEvent } from '../../inputEvents';
3
3
  import { ToolbarLocalization } from '../localization';
4
4
  import { WidgetContentLayoutManager } from './layout/types';
5
+ import HelpDisplay from '../utils/HelpDisplay';
5
6
  export type SavedToolbuttonState = Record<string, any>;
6
7
  /**
7
8
  * A set of labels that allow toolbar themes to treat buttons differently.
@@ -66,7 +67,13 @@ export default abstract class BaseWidget {
66
67
  getUniqueIdIn(container: Record<string, BaseWidget>): string;
67
68
  protected abstract getTitle(): string;
68
69
  protected abstract createIcon(): Element | null;
69
- protected fillDropdown(dropdown: HTMLElement): boolean;
70
+ protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
71
+ /**
72
+ * Should return a 1-2 sentence description of the widget.
73
+ *
74
+ * At present, this is only used if this widget has an associated dropdown.
75
+ */
76
+ protected getHelpText(): undefined | string;
70
77
  /** @deprecated Renamed to `setUpButtonEventListeners`. */
71
78
  protected setupActionBtnClickListener(button: HTMLElement): void;
72
79
  protected setUpButtonEventListeners(button: HTMLElement): void;
@@ -21,6 +21,7 @@ const inputEvents_1 = require("../../inputEvents");
21
21
  const constants_1 = require("../constants");
22
22
  const DropdownLayoutManager_1 = __importDefault(require("./layout/DropdownLayoutManager"));
23
23
  const addLongPressOrHoverCssClasses_1 = __importDefault(require("../../util/addLongPressOrHoverCssClasses"));
24
+ const HelpDisplay_1 = __importDefault(require("../utils/HelpDisplay"));
24
25
  /**
25
26
  * A set of labels that allow toolbar themes to treat buttons differently.
26
27
  */
@@ -133,17 +134,30 @@ class BaseWidget {
133
134
  }
134
135
  // Add content to the widget's associated dropdown menu.
135
136
  // Returns true if such a menu should be created, false otherwise.
136
- fillDropdown(dropdown) {
137
+ fillDropdown(dropdown, helpDisplay) {
137
138
  if (Object.keys(this.subWidgets).length === 0) {
138
139
  return false;
139
140
  }
140
141
  for (const widgetId in this.subWidgets) {
141
142
  const widget = this.subWidgets[widgetId];
142
- widget.addTo(dropdown);
143
+ const widgetElement = widget.addTo(dropdown);
143
144
  widget.setIsToplevel(false);
145
+ // Add help information
146
+ const helpText = widget.getHelpText();
147
+ if (helpText) {
148
+ helpDisplay?.registerTextHelpForElement(widgetElement, helpText);
149
+ }
144
150
  }
145
151
  return true;
146
152
  }
153
+ /**
154
+ * Should return a 1-2 sentence description of the widget.
155
+ *
156
+ * At present, this is only used if this widget has an associated dropdown.
157
+ */
158
+ getHelpText() {
159
+ return undefined;
160
+ }
147
161
  /** @deprecated Renamed to `setUpButtonEventListeners`. */
148
162
  setupActionBtnClickListener(button) {
149
163
  return this.setUpButtonEventListeners(button);
@@ -235,10 +249,15 @@ class BaseWidget {
235
249
  this.container.replaceChildren();
236
250
  this.button.replaceChildren(this.icon, this.label);
237
251
  this.container.appendChild(this.button);
252
+ const helpDisplay = new HelpDisplay_1.default(content => this.editor.createHTMLOverlay(content), this.editor);
253
+ const helpText = this.getHelpText();
254
+ if (helpText) {
255
+ helpDisplay.registerTextHelpForElement(this.dropdownContent, [this.getTitle(), helpText].join('\n\n'));
256
+ }
238
257
  // Clear the dropdownContainer in case this element is being moved to another
239
258
  // parent.
240
259
  this.dropdownContent.replaceChildren();
241
- __classPrivateFieldSet(this, _BaseWidget_hasDropdown, this.fillDropdown(this.dropdownContent), "f");
260
+ __classPrivateFieldSet(this, _BaseWidget_hasDropdown, this.fillDropdown(this.dropdownContent, helpDisplay), "f");
242
261
  if (__classPrivateFieldGet(this, _BaseWidget_hasDropdown, "f")) {
243
262
  this.button.classList.add('has-dropdown');
244
263
  // We're re-creating the dropdown.
@@ -264,6 +283,9 @@ class BaseWidget {
264
283
  this.focus();
265
284
  }
266
285
  });
286
+ if (helpDisplay.hasHelpText()) {
287
+ this.dropdown.appendChild(helpDisplay.createToggleButton());
288
+ }
267
289
  this.dropdown.appendChild(this.dropdownContent);
268
290
  }
269
291
  this.setDropdownVisible(false);
@@ -1,6 +1,7 @@
1
1
  import Editor from '../../Editor';
2
2
  import { ToolbarLocalization } from '../localization';
3
3
  import BaseWidget from './BaseWidget';
4
+ import HelpDisplay from '../utils/HelpDisplay';
4
5
  export default class DocumentPropertiesWidget extends BaseWidget {
5
6
  private updateDropdownContent;
6
7
  constructor(editor: Editor, localizationTable?: ToolbarLocalization);
@@ -18,6 +19,7 @@ export default class DocumentPropertiesWidget extends BaseWidget {
18
19
  /** Returns the type of the topmost background component */
19
20
  private getBackgroundType;
20
21
  private updateImportExportRectSize;
22
+ protected getHelpText(): string;
21
23
  private static idCounter;
22
- protected fillDropdown(dropdown: HTMLElement): boolean;
24
+ protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
23
25
  }
@@ -118,7 +118,10 @@ class DocumentPropertiesWidget extends BaseWidget_1.default {
118
118
  this.editor.dispatch(this.editor.image.setImportExportRect(newRect));
119
119
  this.editor.queueRerender();
120
120
  }
121
- fillDropdown(dropdown) {
121
+ getHelpText() {
122
+ return this.localizationTable.pageDropdown__baseHelpText;
123
+ }
124
+ fillDropdown(dropdown, helpDisplay) {
122
125
  const container = document.createElement('div');
123
126
  container.classList.add(`${constants_1.toolbarCSSPrefix}spacedList`, `${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`, `${constants_1.toolbarCSSPrefix}document-properties-widget`);
124
127
  // Background color input
@@ -126,7 +129,7 @@ class DocumentPropertiesWidget extends BaseWidget_1.default {
126
129
  const backgroundColorRow = document.createElement('div');
127
130
  const backgroundColorLabel = document.createElement('label');
128
131
  backgroundColorLabel.innerText = this.localizationTable.backgroundColor;
129
- const { input: colorInput, container: backgroundColorInputContainer, setValue: setBgColorInputValue } = (0, makeColorInput_1.default)(this.editor, color => {
132
+ const { input: colorInput, container: backgroundColorInputContainer, setValue: setBgColorInputValue, registerWithHelpTextDisplay: registerHelpForInputs, } = (0, makeColorInput_1.default)(this.editor, color => {
130
133
  if (!color.eq(this.getBackgroundColor())) {
131
134
  this.setBackgroundColor(color);
132
135
  }
@@ -134,9 +137,16 @@ class DocumentPropertiesWidget extends BaseWidget_1.default {
134
137
  colorInput.id = `${constants_1.toolbarCSSPrefix}docPropertiesColorInput-${DocumentPropertiesWidget.idCounter++}`;
135
138
  backgroundColorLabel.htmlFor = colorInput.id;
136
139
  backgroundColorRow.replaceChildren(backgroundColorLabel, backgroundColorInputContainer);
137
- return { setBgColorInputValue, backgroundColorRow };
140
+ const registerWithHelp = (helpDisplay) => {
141
+ if (!helpDisplay) {
142
+ return;
143
+ }
144
+ helpDisplay?.registerTextHelpForElement(backgroundColorRow, this.localizationTable.pageDropdown__backgroundColorHelpText);
145
+ registerHelpForInputs(helpDisplay);
146
+ };
147
+ return { setBgColorInputValue, backgroundColorRow, registerWithHelp, };
138
148
  };
139
- const { backgroundColorRow, setBgColorInputValue } = makeBackgroundColorInput();
149
+ const { backgroundColorRow, setBgColorInputValue, registerWithHelp: registerBackgroundRowWithHelp, } = makeBackgroundColorInput();
140
150
  const makeCheckboxRow = (labelText, onChange) => {
141
151
  const rowContainer = document.createElement('div');
142
152
  const labelElement = document.createElement('label');
@@ -217,6 +227,11 @@ class DocumentPropertiesWidget extends BaseWidget_1.default {
217
227
  aboutButton.onclick = () => {
218
228
  this.editor.showAboutDialog();
219
229
  };
230
+ // Add help text
231
+ registerBackgroundRowWithHelp(helpDisplay);
232
+ helpDisplay?.registerTextHelpForElement(useGridRow, this.localizationTable.pageDropdown__gridCheckboxHelpText);
233
+ helpDisplay?.registerTextHelpForElement(auroresizeRow, this.localizationTable.pageDropdown__autoresizeCheckboxHelpText);
234
+ helpDisplay?.registerTextHelpForElement(aboutButton, this.localizationTable.pageDropdown__aboutButtonHelpText);
220
235
  this.updateDropdownContent = () => {
221
236
  setBgColorInputValue(this.getBackgroundColor());
222
237
  const autoresize = this.editor.image.getAutoresizeEnabled();
@@ -3,6 +3,7 @@ import PanZoom from '../../tools/PanZoom';
3
3
  import { ToolbarLocalization } from '../localization';
4
4
  import BaseToolWidget from './BaseToolWidget';
5
5
  import { SavedToolbuttonState } from './BaseWidget';
6
+ import HelpDisplay from '../utils/HelpDisplay';
6
7
  export default class HandToolWidget extends BaseToolWidget {
7
8
  private allowTogglingBaseTool;
8
9
  protected overridePanZoomTool: PanZoom;
@@ -13,7 +14,8 @@ export default class HandToolWidget extends BaseToolWidget {
13
14
  protected getTitle(): string;
14
15
  protected createIcon(): Element;
15
16
  protected handleClick(): void;
16
- protected fillDropdown(dropdown: HTMLElement): boolean;
17
+ protected getHelpText(): string;
18
+ protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
17
19
  setSelected(selected: boolean): void;
18
20
  serializeState(): SavedToolbuttonState;
19
21
  deserializeFrom(state: SavedToolbuttonState): void;
@@ -34,7 +34,7 @@ const constants_1 = require("../constants");
34
34
  const BaseToolWidget_1 = __importDefault(require("./BaseToolWidget"));
35
35
  const BaseWidget_1 = __importDefault(require("./BaseWidget"));
36
36
  const makeSeparator_1 = __importDefault(require("./components/makeSeparator"));
37
- const makeZoomControl = (localizationTable, editor) => {
37
+ const makeZoomControl = (localizationTable, editor, helpDisplay) => {
38
38
  const zoomLevelRow = document.createElement('div');
39
39
  const increaseButton = document.createElement('button');
40
40
  const decreaseButton = document.createElement('button');
@@ -83,15 +83,20 @@ const makeZoomControl = (localizationTable, editor) => {
83
83
  const addToHistory = false;
84
84
  editor.dispatch(Viewport_1.default.transformBy(editor.viewport.canvasToScreenTransform.inverse()), addToHistory);
85
85
  };
86
+ helpDisplay?.registerTextHelpForElement(increaseButton, localizationTable.handDropdown__zoomInHelpText);
87
+ helpDisplay?.registerTextHelpForElement(decreaseButton, localizationTable.handDropdown__zoomOutHelpText);
88
+ helpDisplay?.registerTextHelpForElement(resetViewButton, localizationTable.handDropdown__resetViewHelpText);
89
+ helpDisplay?.registerTextHelpForElement(zoomLevelDisplay, localizationTable.handDropdown__zoomDisplayHelpText);
86
90
  return zoomLevelRow;
87
91
  };
88
92
  class HandModeWidget extends BaseWidget_1.default {
89
- constructor(editor, tool, flag, makeIcon, title, localizationTable) {
93
+ constructor(editor, tool, flag, makeIcon, title, helpText, localizationTable) {
90
94
  super(editor, `pan-mode-${flag}`, localizationTable);
91
95
  this.tool = tool;
92
96
  this.flag = flag;
93
97
  this.makeIcon = makeIcon;
94
98
  this.title = title;
99
+ this.helpText = helpText;
95
100
  editor.notifier.on(types_1.EditorEventType.ToolUpdated, toolEvt => {
96
101
  if (toolEvt.kind === types_1.EditorEventType.ToolUpdated && toolEvt.tool === tool) {
97
102
  const allEnabled = !!(tool.getMode() & PanZoom_1.PanZoomMode.SinglePointerGestures);
@@ -121,6 +126,9 @@ class HandModeWidget extends BaseWidget_1.default {
121
126
  fillDropdown(_dropdown) {
122
127
  return false;
123
128
  }
129
+ getHelpText() {
130
+ return this.helpText;
131
+ }
124
132
  }
125
133
  class HandToolWidget extends BaseToolWidget_1.default {
126
134
  constructor(editor,
@@ -145,8 +153,8 @@ class HandToolWidget extends BaseToolWidget_1.default {
145
153
  this.container.classList.add('dropdownShowable');
146
154
  }
147
155
  // Controls for the overriding hand tool.
148
- const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
149
- const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
156
+ const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable.handDropdown__touchPanningHelpText, localizationTable);
157
+ const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable.handDropdown__lockRotationHelpText, localizationTable);
150
158
  this.addSubWidget(touchPanningWidget);
151
159
  this.addSubWidget(rotationLockWidget);
152
160
  }
@@ -177,13 +185,17 @@ class HandToolWidget extends BaseToolWidget_1.default {
177
185
  this.setDropdownVisible(!this.isDropdownVisible());
178
186
  }
179
187
  }
180
- fillDropdown(dropdown) {
181
- super.fillDropdown(dropdown);
188
+ getHelpText() {
189
+ return this.localizationTable.handDropdown__baseHelpText;
190
+ }
191
+ fillDropdown(dropdown, helpDisplay) {
192
+ super.fillDropdown(dropdown, helpDisplay);
182
193
  // The container for all actions that come after the toolbar buttons.
183
194
  const nonbuttonActionContainer = document.createElement('div');
184
195
  nonbuttonActionContainer.classList.add(`${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`);
185
196
  (0, makeSeparator_1.default)().addTo(nonbuttonActionContainer);
186
- nonbuttonActionContainer.appendChild(makeZoomControl(this.localizationTable, this.editor));
197
+ const zoomControl = makeZoomControl(this.localizationTable, this.editor, helpDisplay);
198
+ nonbuttonActionContainer.appendChild(zoomControl);
187
199
  dropdown.appendChild(nonbuttonActionContainer);
188
200
  return true;
189
201
  }
@@ -100,6 +100,7 @@ class InsertImageWidget extends BaseWidget_1.default {
100
100
  imageAltTextLabel.htmlFor = altTextInputId;
101
101
  imageAltTextLabel.innerText = this.localizationTable.inputAltText;
102
102
  this.imageAltTextInput.type = 'text';
103
+ this.imageAltTextInput.placeholder = this.localizationTable.describeTheImage;
103
104
  this.statusView.setAttribute('aria-live', 'polite');
104
105
  this.submitButton.innerText = this.localizationTable.submit;
105
106
  this.selectedFiles.onUpdateAndNow(async (files) => {
@@ -5,6 +5,7 @@ import { KeyPressEvent } from '../../inputEvents';
5
5
  import { ToolbarLocalization } from '../localization';
6
6
  import BaseToolWidget from './BaseToolWidget';
7
7
  import { SavedToolbuttonState } from './BaseWidget';
8
+ import HelpDisplay from '../utils/HelpDisplay';
8
9
  export interface PenTypeRecord {
9
10
  name: string;
10
11
  id: string;
@@ -24,11 +25,12 @@ export default class PenToolWidget extends BaseToolWidget {
24
25
  private createIconForRecord;
25
26
  protected createIcon(): Element;
26
27
  private createPenTypeSelector;
27
- protected createStrokeCorrectionOptions(): {
28
+ protected createStrokeCorrectionOptions(helpOverlay?: HelpDisplay): {
28
29
  update: () => void;
29
30
  addTo: (parent: HTMLElement) => void;
30
31
  };
31
- protected fillDropdown(dropdown: HTMLElement): boolean;
32
+ protected getHelpText(): string;
33
+ protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
32
34
  protected onKeyPress(event: KeyPressEvent): boolean;
33
35
  serializeState(): SavedToolbuttonState;
34
36
  deserializeFrom(state: SavedToolbuttonState): void;
@@ -121,7 +121,7 @@ class PenToolWidget extends BaseToolWidget_1.default {
121
121
  return this.createIconForRecord(this.getCurrentPenType());
122
122
  }
123
123
  // Creates a widget that allows selecting different pen types
124
- createPenTypeSelector() {
124
+ createPenTypeSelector(helpOverlay) {
125
125
  const allChoices = this.penTypes.map((penType, index) => {
126
126
  return {
127
127
  id: index,
@@ -137,6 +137,7 @@ class PenToolWidget extends BaseToolWidget_1.default {
137
137
  };
138
138
  penSelector.value.onUpdate(onSelectorUpdate);
139
139
  shapeSelector.value.onUpdate(onSelectorUpdate);
140
+ helpOverlay?.registerTextHelpForElements([penSelector.getRootElement(), shapeSelector.getRootElement()], this.localizationTable.penDropdown__penTypeHelpText);
140
141
  return {
141
142
  setValue: (penTypeIndex) => {
142
143
  penSelector.value.set(penTypeIndex);
@@ -152,7 +153,7 @@ class PenToolWidget extends BaseToolWidget_1.default {
152
153
  },
153
154
  };
154
155
  }
155
- createStrokeCorrectionOptions() {
156
+ createStrokeCorrectionOptions(helpOverlay) {
156
157
  const container = document.createElement('div');
157
158
  container.classList.add('action-button-row', `${constants_1.toolbarCSSPrefix}-pen-tool-toggle-buttons`);
158
159
  const addToggleButton = (labelText, icon) => {
@@ -176,6 +177,9 @@ class PenToolWidget extends BaseToolWidget_1.default {
176
177
  setOnInputListener(listener) {
177
178
  onChangeListener = listener;
178
179
  },
180
+ addHelpText(text) {
181
+ helpOverlay?.registerTextHelpForElement(button, text);
182
+ },
179
183
  };
180
184
  button.onclick = () => {
181
185
  result.setChecked(!checked);
@@ -190,6 +194,9 @@ class PenToolWidget extends BaseToolWidget_1.default {
190
194
  autocorrectOption.setOnInputListener(enabled => {
191
195
  this.tool.setStrokeAutocorrectEnabled(enabled);
192
196
  });
197
+ // Help text
198
+ autocorrectOption.addHelpText(this.localizationTable.penDropdown__autocorrectHelpText);
199
+ stabilizationOption.addHelpText(this.localizationTable.penDropdown__stabilizationHelpText);
193
200
  return {
194
201
  update: () => {
195
202
  stabilizationOption.setChecked(!!this.tool.getInputMapper());
@@ -197,30 +204,42 @@ class PenToolWidget extends BaseToolWidget_1.default {
197
204
  },
198
205
  addTo: (parent) => {
199
206
  parent.appendChild(container);
200
- }
207
+ },
201
208
  };
202
209
  }
203
- fillDropdown(dropdown) {
210
+ getHelpText() {
211
+ return this.localizationTable.penDropdown__baseHelpText;
212
+ }
213
+ fillDropdown(dropdown, helpDisplay) {
204
214
  const container = document.createElement('div');
205
215
  container.classList.add(`${constants_1.toolbarCSSPrefix}spacedList`, `${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`);
206
216
  // Thickness: Value of the input is squared to allow for finer control/larger values.
207
217
  const { container: thicknessRow, setValue: setThickness } = (0, makeThicknessSlider_1.default)(this.editor, thickness => {
208
218
  this.tool.setThickness(thickness);
209
219
  });
210
- const penTypeSelect = this.createPenTypeSelector();
211
220
  const colorRow = document.createElement('div');
212
221
  const colorLabel = document.createElement('label');
213
- const { input: colorInput, container: colorInputContainer, setValue: setColorInputValue } = (0, makeColorInput_1.default)(this.editor, color => {
222
+ const colorInputControl = (0, makeColorInput_1.default)(this.editor, color => {
214
223
  this.tool.setColor(color);
215
224
  });
225
+ const { input: colorInput, container: colorInputContainer } = colorInputControl;
216
226
  colorInput.id = `${constants_1.toolbarCSSPrefix}colorInput${PenToolWidget.idCounter++}`;
217
227
  colorLabel.innerText = this.localizationTable.colorLabel;
218
228
  colorLabel.setAttribute('for', colorInput.id);
219
229
  colorRow.appendChild(colorLabel);
220
230
  colorRow.appendChild(colorInputContainer);
221
- const toggleButtonRow = this.createStrokeCorrectionOptions();
231
+ // Autocorrect and stabilization options
232
+ const toggleButtonRow = this.createStrokeCorrectionOptions(helpDisplay);
233
+ const penTypeSelect = this.createPenTypeSelector(helpDisplay);
234
+ // Add help text for color and thickness last, as these are likely to be
235
+ // features users are least interested in.
236
+ helpDisplay?.registerTextHelpForElement(colorRow, this.localizationTable.penDropdown__colorHelpText);
237
+ if (helpDisplay) {
238
+ colorInputControl.registerWithHelpTextDisplay(helpDisplay);
239
+ }
240
+ helpDisplay?.registerTextHelpForElement(thicknessRow, this.localizationTable.penDropdown__thicknessHelpText);
222
241
  this.updateInputs = () => {
223
- setColorInputValue(this.tool.getColor());
242
+ colorInputControl.setValue(this.tool.getColor());
224
243
  setThickness(this.tool.getThickness());
225
244
  penTypeSelect.updateIcons();
226
245
  // Update the selected stroke factory.
@@ -3,6 +3,7 @@ import SelectionTool from '../../tools/SelectionTool/SelectionTool';
3
3
  import { KeyPressEvent } from '../../inputEvents';
4
4
  import { ToolbarLocalization } from '../localization';
5
5
  import BaseToolWidget from './BaseToolWidget';
6
+ import HelpDisplay from '../utils/HelpDisplay';
6
7
  export default class SelectionToolWidget extends BaseToolWidget {
7
8
  private tool;
8
9
  private updateFormatMenu;
@@ -11,5 +12,6 @@ export default class SelectionToolWidget extends BaseToolWidget {
11
12
  protected onKeyPress(event: KeyPressEvent): boolean;
12
13
  protected getTitle(): string;
13
14
  protected createIcon(): Element;
14
- protected fillDropdown(dropdown: HTMLElement): boolean;
15
+ protected getHelpText(): string;
16
+ protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
15
17
  }