devexpress-richedit 25.2.8 → 26.1.3

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 (80) hide show
  1. package/bin/gulpfile.js +1 -1
  2. package/bin/index-custom.js +1 -1
  3. package/bin/localization-builder.js +1 -1
  4. package/bin/nspell-index.js +1 -1
  5. package/bin/nspell.webpack.config.js +1 -1
  6. package/bin/webpack-externals.js +1 -1
  7. package/bin/webpack.config.js +1 -1
  8. package/dist/dx.richedit.css +26 -0
  9. package/dist/dx.richedit.d.ts +1 -1
  10. package/dist/dx.richedit.js +6559 -5654
  11. package/dist/dx.richedit.min.js +3 -3
  12. package/dist/pdfkit.js +21908 -22350
  13. package/dist/pdfkit.min.js +1 -1
  14. package/index.d.ts +1 -1
  15. package/index.js +1 -1
  16. package/lib/client/client-rich-edit.d.ts +0 -1
  17. package/lib/client/client-rich-edit.js +4 -27
  18. package/lib/client/default-localization.js +19 -0
  19. package/lib/client/dialogs/alert-dialog.d.ts +1 -1
  20. package/lib/client/dialogs/bookmark-dialog.d.ts +1 -1
  21. package/lib/client/dialogs/delete-table-cells-dialog.d.ts +1 -1
  22. package/lib/client/dialogs/dialog-base.d.ts +1 -1
  23. package/lib/client/dialogs/find-replace-dialog.d.ts +1 -1
  24. package/lib/client/dialogs/finish-and-merge-dialog.d.ts +1 -1
  25. package/lib/client/dialogs/font-dialog.d.ts +1 -1
  26. package/lib/client/dialogs/hyperlink-dialog.d.ts +1 -1
  27. package/lib/client/dialogs/insert-merge-field-dialog.d.ts +1 -1
  28. package/lib/client/dialogs/insert-table-cells-dialog.d.ts +1 -1
  29. package/lib/client/dialogs/insert-table-dialog.d.ts +1 -1
  30. package/lib/client/dialogs/page-setup-dialog.d.ts +1 -1
  31. package/lib/client/dialogs/paragraph-dialog.d.ts +1 -1
  32. package/lib/client/dialogs/split-table-cells-dialog.d.ts +1 -1
  33. package/lib/client/dialogs/tabs-dialog.d.ts +1 -1
  34. package/lib/client/public/rich-edit.js +2 -0
  35. package/lib/common/canvas/canvas-manager.d.ts +1 -1
  36. package/lib/common/canvas/canvas-manager.js +7 -3
  37. package/lib/common/canvas/double-tap-detector.d.ts +10 -0
  38. package/lib/common/canvas/double-tap-detector.js +28 -0
  39. package/lib/common/canvas/renderer-class-names.d.ts +2 -0
  40. package/lib/common/canvas/renderer-class-names.js +2 -0
  41. package/lib/common/canvas/renderes/common/document-renderer.d.ts +20 -7
  42. package/lib/common/canvas/renderes/common/document-renderer.js +236 -47
  43. package/lib/common/canvas/renderes/common/simple-view-renderer.d.ts +3 -1
  44. package/lib/common/canvas/renderes/common/simple-view-renderer.js +35 -2
  45. package/lib/common/canvas/renderes/view-manager.d.ts +3 -0
  46. package/lib/common/canvas/renderes/view-manager.js +34 -7
  47. package/lib/common/commands/command-manager.d.ts +2 -0
  48. package/lib/common/commands/command-manager.js +6 -0
  49. package/lib/common/commands/dialogs/dialog-custom-numbering-list-command.js +1 -1
  50. package/lib/common/commands/layout/switch-view-command.js +2 -1
  51. package/lib/common/commands/selection/go-to-next-word-command.d.ts +3 -4
  52. package/lib/common/commands/selection/go-to-next-word-command.js +2 -9
  53. package/lib/common/commands/selection/go-to-prev-word-command.d.ts +3 -2
  54. package/lib/common/commands/selection/go-to-prev-word-command.js +2 -2
  55. package/lib/common/commands/selection/select-all-document-command.d.ts +2 -0
  56. package/lib/common/commands/selection/select-all-document-command.js +6 -0
  57. package/lib/common/commands/selection/selection-command-base.d.ts +2 -0
  58. package/lib/common/commands/selection/selection-command-base.js +8 -0
  59. package/lib/common/event-manager.js +6 -12
  60. package/lib/common/formats/txt/txt-exporter.js +1 -1
  61. package/lib/common/input-controller.js +2 -0
  62. package/lib/common/interfaces/i-rich-edit-core.d.ts +2 -0
  63. package/lib/common/layout/main-structures/layout-boxes/layout-box.js +1 -1
  64. package/lib/common/layout/main-structures/layout-column.d.ts +1 -0
  65. package/lib/common/layout/main-structures/layout-column.js +3 -0
  66. package/lib/common/layout/selection/layout-selection-items.d.ts +3 -0
  67. package/lib/common/layout/selection/layout-selection-items.js +5 -0
  68. package/lib/common/layout-engine/selection/selection-formatter.js +7 -3
  69. package/lib/common/layout-formatter/box/generator/box-infos-generator.js +8 -4
  70. package/lib/common/model/sub-document.d.ts +18 -0
  71. package/lib/common/model/sub-document.js +71 -22
  72. package/lib/common/rich-edit-core.d.ts +3 -0
  73. package/lib/common/rich-edit-core.js +18 -0
  74. package/lib/common/screen-reader-manager.d.ts +48 -0
  75. package/lib/common/screen-reader-manager.js +326 -0
  76. package/lib/common/string-resources.d.ts +23 -0
  77. package/lib/common/string-resources.js +43 -0
  78. package/lib/common/utils/interval-utils.d.ts +4 -0
  79. package/lib/common/utils/interval-utils.js +25 -0
  80. package/package.json +3 -3
@@ -44,6 +44,7 @@ import { HorizontalRulerControl } from './ui/ruler/ruler';
44
44
  import { SearchManager } from './ui/search-manager';
45
45
  import { isDefined } from '@devexpress/utils/lib/utils/common';
46
46
  import { ModelScrollManager } from './scroll/model-scroll-manager';
47
+ import { ScreenReaderManager } from './screen-reader-manager';
47
48
  export class RichEditCore {
48
49
  get isReadOnlyPersistent() { return this.readOnly === ReadOnlyMode.Persistent; }
49
50
  get model() { return this.modelManager.model; }
@@ -84,6 +85,7 @@ export class RichEditCore {
84
85
  this.commandManager = this.createCommandManager();
85
86
  this.shortcutManager = this.createShortcutManager();
86
87
  this.searchManager = new SearchManager(this);
88
+ this.screenReaderManager = new ScreenReaderManager(this, this.createAriaLiveElement(element), this.stringResources);
87
89
  this.boxVisualizerManager.initListeners(this.viewManager);
88
90
  this.autoCorrectService = new AutoCorrectService(this, this.modelManager.richOptions.autoCorrect);
89
91
  this.clientSideEvents = new ClientSideEvents(this.owner);
@@ -142,6 +144,7 @@ export class RichEditCore {
142
144
  this.selection.onChanged.add(this.boxVisualizerManager.resizeBoxVisualizer);
143
145
  this.selection.onChanged.add(this.boxVisualizerManager.anchorVisualizer);
144
146
  this.selection.onChanged.add(this.barHolder.contextMenu);
147
+ this.selection.onChanged.add(this.screenReaderManager);
145
148
  if (this.barHolder.ribbon)
146
149
  this.selection.onChanged.add(this.barHolder.ribbon);
147
150
  this.selection.onSearchChanged.add(this.selectionFormatter);
@@ -191,6 +194,7 @@ export class RichEditCore {
191
194
  this.spellChecker.dispose();
192
195
  this.selection.dispose();
193
196
  this.barHolder.dispose?.();
197
+ this.screenReaderManager.dispose?.();
194
198
  this.modelManager = null;
195
199
  this.commandManager = null;
196
200
  this.shortcutManager = null;
@@ -401,6 +405,20 @@ export class RichEditCore {
401
405
  this.layoutFormatterManager.forceFormatPage(this.layout.validPageCount + 1);
402
406
  }
403
407
  }
408
+ createAriaLiveElement(element) {
409
+ const ariaLiveElement = document.createElement("DIV");
410
+ ariaLiveElement.setAttribute('aria-live', 'polite');
411
+ ariaLiveElement.setAttribute('aria-atomic', 'true');
412
+ ariaLiveElement.style.position = 'absolute';
413
+ ariaLiveElement.style.width = '1px';
414
+ ariaLiveElement.style.height = '1px';
415
+ ariaLiveElement.style.overflow = 'hidden';
416
+ ariaLiveElement.style.whiteSpace = 'nowrap';
417
+ ariaLiveElement.style.border = '0';
418
+ ariaLiveElement.style.whiteSpace = 'pre-line';
419
+ element.appendChild(ariaLiveElement);
420
+ return ariaLiveElement;
421
+ }
404
422
  createViewElement(id, element) {
405
423
  const viewElement = document.createElement("DIV");
406
424
  viewElement.id = id + "_View";
@@ -0,0 +1,48 @@
1
+ import { RichEditClientCommand } from "./commands/client-command";
2
+ import { IRichEditControl } from "./interfaces/i-rich-edit-core";
3
+ import { LayoutPosition } from "./layout/layout-position";
4
+ import { ISelectionChangesListener } from "./selection/i-selection-changes-listener";
5
+ import { Selection } from "./selection/selection";
6
+ import { StringResources } from "./string-resources";
7
+ export declare class ScreenReaderManager implements ISelectionChangesListener {
8
+ private static _maxAnnouncedTextLength;
9
+ private static _spaceSeparatorRegex;
10
+ private _charNames;
11
+ readonly _handlers: Map<RichEditClientCommand, (selection: Selection, lp: LayoutPosition) => string>;
12
+ private _selectionIntervals;
13
+ private _commandId;
14
+ private _control;
15
+ private _liveRegion;
16
+ private _announcements;
17
+ private _announceTimeoutId;
18
+ private _pageIndex;
19
+ private _tableInfo;
20
+ private _prevNavInHyperlink;
21
+ constructor(control: IRichEditControl, liveRegion: HTMLDivElement, resources: StringResources);
22
+ private _announce;
23
+ private _clearAnnouncement;
24
+ beginExecute(commandId: RichEditClientCommand): void;
25
+ endExecute(): void;
26
+ NotifySelectionChanged(selection: Selection): void;
27
+ private _processTable;
28
+ private _processExtendSelectionCommand;
29
+ private _getTextByIntervals;
30
+ private _updateHyperlinkState;
31
+ private _getLinkTransitionPrefix;
32
+ private _getCurrentCharacterAnnouncement;
33
+ private _buildContextualAnnouncement;
34
+ private _getCurrentLineAnnouncement;
35
+ private _getCurrentWordAnnouncement;
36
+ private _getCurrentParagraphAnnouncement;
37
+ private _getHyperlinkField;
38
+ private _onHyperlinkFieldStart;
39
+ private _getVisibleText;
40
+ private _tryResolveDocumentElements;
41
+ private _tryResolveSpecialCharacters;
42
+ private _getInlinePictureText;
43
+ private _getPageChangePrefix;
44
+ private _getCharName;
45
+ private _resolveListMarker;
46
+ private _getListItemAnnouncement;
47
+ dispose(): void;
48
+ }
@@ -0,0 +1,326 @@
1
+ import { FixedInterval } from "@devexpress/utils/lib/intervals/fixed";
2
+ import { RichEditClientCommand } from "./commands/client-command";
3
+ import { LayoutPositionCreator } from "./layout-engine/layout-position-creator";
4
+ import { DocumentLayoutDetailsLevel } from "./layout/document-layout-details-level";
5
+ import { LayoutWordBounds } from "./word-bounds-engine/layout-word-bounds";
6
+ import { IntervalUtils } from "./utils/interval-utils";
7
+ import { NumberingType } from "./model/numbering-lists/numbering-list";
8
+ import { TablePositionIndexes } from "./model/tables/main-structures/table";
9
+ import { InlinePictureRun } from "./model/runs/inline-picture-run";
10
+ import { RichUtils } from "./model/rich-utils";
11
+ import { RunType } from "./model/runs/run-type";
12
+ import { SubDocumentPosition, TransformAction } from "./model/sub-document";
13
+ class TableInfo {
14
+ constructor(index, columnIndex, rowIndex) {
15
+ this.index = index;
16
+ this.columnIndex = columnIndex;
17
+ this.rowIndex = rowIndex;
18
+ }
19
+ }
20
+ export class ScreenReaderManager {
21
+ static { this._maxAnnouncedTextLength = 500; }
22
+ static { this._spaceSeparatorRegex = /^\p{Zs}$/u; }
23
+ constructor(control, liveRegion, resources) {
24
+ this._handlers = new Map([
25
+ [RichEditClientCommand.NextCharacter, (selection, lp) => this._getCurrentCharacterAnnouncement(selection, lp)],
26
+ [RichEditClientCommand.PreviousCharacter, (selection, lp) => this._getCurrentCharacterAnnouncement(selection, lp)],
27
+ [RichEditClientCommand.LineUp, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
28
+ [RichEditClientCommand.LineDown, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
29
+ [RichEditClientCommand.GoToNextWord, (selection, lp) => this._getCurrentWordAnnouncement(selection, lp)],
30
+ [RichEditClientCommand.GoToPrevWord, (selection, lp) => this._getCurrentWordAnnouncement(selection, lp)],
31
+ [RichEditClientCommand.GoToStartParagraph, (selection, lp) => this._getCurrentParagraphAnnouncement(selection, lp)],
32
+ [RichEditClientCommand.GoToEndParagraph, (selection, lp) => this._getCurrentParagraphAnnouncement(selection, lp)],
33
+ [RichEditClientCommand.NextPage, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
34
+ [RichEditClientCommand.PreviousPage, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
35
+ [RichEditClientCommand.GoToStartNextPage, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
36
+ [RichEditClientCommand.GoToStartPrevPage, (selection, lp) => this._getCurrentLineAnnouncement(selection, lp)],
37
+ ]);
38
+ this._selectionIntervals = [];
39
+ this._commandId = null;
40
+ this._announceTimeoutId = null;
41
+ this._pageIndex = null;
42
+ this._tableInfo = null;
43
+ this._prevNavInHyperlink = false;
44
+ this._control = control;
45
+ this._liveRegion = liveRegion;
46
+ this._announcements = resources.announcements;
47
+ this._charNames = {
48
+ [RichUtils.specialCharacters.TabMark]: this._announcements.tab,
49
+ [RichUtils.specialCharacters.ParagraphMark]: this._announcements.carriageReturn,
50
+ [RichUtils.specialCharacters.LineBreak]: this._announcements.lineBreak,
51
+ [RichUtils.specialCharacters.PageBreak]: this._announcements.pageBreak,
52
+ [RichUtils.specialCharacters.SectionMark]: this._announcements.pageBreak,
53
+ };
54
+ }
55
+ _announce(...announcment) {
56
+ this._clearAnnouncement();
57
+ this._liveRegion.textContent = '';
58
+ this._announceTimeoutId = setTimeout(() => {
59
+ const textContent = announcment.join(' ');
60
+ this._liveRegion.textContent = textContent;
61
+ this._announceTimeoutId = null;
62
+ }, 50);
63
+ }
64
+ _clearAnnouncement() {
65
+ if (this._announceTimeoutId !== null) {
66
+ clearTimeout(this._announceTimeoutId);
67
+ this._announceTimeoutId = null;
68
+ }
69
+ }
70
+ beginExecute(commandId) {
71
+ this._commandId = commandId;
72
+ }
73
+ endExecute() {
74
+ this._commandId = null;
75
+ }
76
+ NotifySelectionChanged(selection) {
77
+ const currentIntervals = !selection.isCollapsed() ? [...selection.intervals].sort((x, y) => x.start - y.start) : [];
78
+ if (this._commandId != null) {
79
+ let announcments = [];
80
+ const handler = this._handlers.get(this._commandId);
81
+ if (handler) {
82
+ const pos = selection.intervals[0].start;
83
+ const subDocument = selection.activeSubDocument;
84
+ const lp = LayoutPositionCreator.createLightLayoutPosition(this._control.layout, subDocument, pos, selection.pageIndex, DocumentLayoutDetailsLevel.Box, selection.endOfLine, false);
85
+ const pagePrefix = this._getPageChangePrefix(lp.pageIndex);
86
+ if (pagePrefix)
87
+ announcments.push(pagePrefix);
88
+ const tableAnnouncements = this._processTable(selection.tableInfo);
89
+ if (tableAnnouncements.length > 0)
90
+ announcments.push(...tableAnnouncements);
91
+ const content = handler(selection, lp);
92
+ this._updateHyperlinkState(lp);
93
+ if (content)
94
+ announcments.push(content);
95
+ }
96
+ if ((!handler && currentIntervals.length > 0) || this._selectionIntervals.length > 0)
97
+ announcments.push(...this._processExtendSelectionCommand(currentIntervals));
98
+ if (announcments.length > 0)
99
+ this._announce(...announcments);
100
+ }
101
+ this._selectionIntervals = currentIntervals;
102
+ }
103
+ _processTable(tableInfo) {
104
+ const result = [];
105
+ if (!tableInfo.table) {
106
+ if (this._tableInfo) {
107
+ result.push(this._announcements.outOfTable);
108
+ this._tableInfo = null;
109
+ }
110
+ return result;
111
+ }
112
+ const extendedData = tableInfo.extendedData;
113
+ const tableCellGridInfos = tableInfo.gridInfoManager.tableCellGridInfos;
114
+ const cellGridInfo = tableInfo.gridInfoManager.gridInfosByTablePosition(new TablePositionIndexes(extendedData.firstRowInfo.rowIndex, extendedData.firstCellInfo.cellIndex));
115
+ const colIndex = cellGridInfo.getGridCellIndex();
116
+ const rowIndex = cellGridInfo.getStartRowIndex();
117
+ const currentTableInfo = new TableInfo(tableInfo.table.index, colIndex, rowIndex);
118
+ if (!this._tableInfo || this._tableInfo.index !== currentTableInfo.index) {
119
+ if (this._tableInfo) {
120
+ result.push(this._announcements.outOfTable);
121
+ this._tableInfo = null;
122
+ }
123
+ result.push(formatString(this._announcements.inTable, tableCellGridInfos.length, tableCellGridInfos[0].length));
124
+ }
125
+ if (!this._tableInfo || this._tableInfo.rowIndex !== currentTableInfo.rowIndex)
126
+ result.push(formatString(this._announcements.tableRow, rowIndex + 1));
127
+ if (!this._tableInfo || this._tableInfo.columnIndex !== currentTableInfo.columnIndex)
128
+ result.push(formatString(this._announcements.tableColumn, colIndex + 1));
129
+ this._tableInfo = currentTableInfo;
130
+ return result;
131
+ }
132
+ _processExtendSelectionCommand(intervals) {
133
+ let announcments = [];
134
+ if (this._commandId === RichEditClientCommand.SelectAll)
135
+ announcments.push(this._announcements.selectAll, "\n");
136
+ const subDocument = this._control.selection.activeSubDocument;
137
+ const selectedIntervals = IntervalUtils.subtractIntervals(intervals, this._selectionIntervals);
138
+ if (selectedIntervals.length > 0)
139
+ announcments.push(formatString(this._announcements.textSelected, this._getTextByIntervals(subDocument, selectedIntervals)));
140
+ const unselectedIntervals = IntervalUtils.subtractIntervals(this._selectionIntervals, intervals);
141
+ if (unselectedIntervals.length > 0)
142
+ announcments.push(formatString(this._announcements.textUnselected, this._getTextByIntervals(subDocument, unselectedIntervals)));
143
+ return announcments;
144
+ }
145
+ _getTextByIntervals(subDocument, intervals) {
146
+ const length = intervals.reduce((total, interval) => total + interval.length, 0);
147
+ if (length > ScreenReaderManager._maxAnnouncedTextLength)
148
+ return `${length} characters`;
149
+ return intervals.map(i => subDocument.getVisibleText(i, {
150
+ includeNumberedListMarks: true,
151
+ transform: this._tryResolveDocumentElements.bind(this)
152
+ })).join('');
153
+ }
154
+ _updateHyperlinkState(lp) {
155
+ this._prevNavInHyperlink = lp.box?.hyperlinkTip != null;
156
+ }
157
+ _getLinkTransitionPrefix(lp) {
158
+ const inHyperlink = lp.box?.hyperlinkTip != null;
159
+ const prevInHyperlink = this._prevNavInHyperlink;
160
+ if (inHyperlink && !prevInHyperlink)
161
+ return this._announcements.link;
162
+ if (!inHyperlink && prevInHyperlink)
163
+ return this._announcements.outOfLink;
164
+ return null;
165
+ }
166
+ _getCurrentCharacterAnnouncement(selection, lp) {
167
+ const pos = selection.intervals[0].start;
168
+ const subDocument = selection.activeSubDocument;
169
+ const info = subDocument.getRunAndIndexesByPosition(pos);
170
+ if (info.run instanceof InlinePictureRun)
171
+ return this._getInlinePictureText(info.run);
172
+ const isFieldCodeStartRun = info.run.getType() === RunType.FieldCodeStartRun;
173
+ const charInfo = isFieldCodeStartRun
174
+ ? subDocument.getRunAndIndexesByPosition(lp.getLogPosition(DocumentLayoutDetailsLevel.Box))
175
+ : info;
176
+ const char = charInfo.getCurrentChar();
177
+ let content = this._getCharName(char);
178
+ return this._buildContextualAnnouncement(content, new SubDocumentPosition(subDocument, pos), lp);
179
+ }
180
+ _buildContextualAnnouncement(content, pos, lp) {
181
+ const paragraph = pos.subDocument.getParagraphByPosition(pos.position);
182
+ const linkPrefix = this._getLinkTransitionPrefix(lp);
183
+ if (linkPrefix)
184
+ content = `${linkPrefix} ${content}`;
185
+ const listContent = this._getListItemAnnouncement(paragraph, pos.position, lp, content);
186
+ return listContent ? listContent : content;
187
+ }
188
+ _getCurrentLineAnnouncement(selection, lp) {
189
+ const pos = selection.intervals[0].start;
190
+ const subDocument = selection.activeSubDocument;
191
+ const rowStart = lp.getLogPosition(DocumentLayoutDetailsLevel.Row);
192
+ const rowEnd = rowStart + lp.row.getLastBoxEndPositionInRow();
193
+ const intervalStart = rowStart;
194
+ const text = this._getVisibleText(subDocument, FixedInterval.fromPositions(intervalStart, rowEnd));
195
+ const listMarker = lp.row.numberingListBox
196
+ ? this._resolveListMarker(subDocument.getParagraphByPosition(pos))
197
+ : null;
198
+ return listMarker ? `${listMarker} ${text}`.trim() : text;
199
+ }
200
+ _getCurrentWordAnnouncement(selection, lp) {
201
+ const pos = selection.intervals[0].start;
202
+ const subDocument = selection.activeSubDocument;
203
+ const wordEnd = LayoutWordBounds.getLayoutWordEndBound(this._control.layout, subDocument, selection, pos, false);
204
+ let text = subDocument.getVisibleText(FixedInterval.fromPositions(pos, wordEnd), {
205
+ transform: this._tryResolveDocumentElements.bind(this)
206
+ });
207
+ return this._buildContextualAnnouncement(text, new SubDocumentPosition(subDocument, pos), lp);
208
+ }
209
+ _getCurrentParagraphAnnouncement(selection, _lp) {
210
+ const pos = selection.intervals[0].start;
211
+ const subDocument = selection.activeSubDocument;
212
+ const paragraph = subDocument.getParagraphByPosition(pos);
213
+ const text = this._getVisibleText(subDocument, FixedInterval.fromPositions(paragraph.startLogPosition.value, paragraph.getEndPosition()), true);
214
+ return text;
215
+ }
216
+ _getHyperlinkField(fieldIndexes, _subDocument) {
217
+ return fieldIndexes
218
+ .map(index => _subDocument.fields[index])
219
+ .find(field => field.isHyperlinkField());
220
+ }
221
+ _onHyperlinkFieldStart(fieldIndexes, subDocument, pos) {
222
+ const field = this._getHyperlinkField(fieldIndexes, subDocument);
223
+ return field && pos === field.getResultStartPosition() ? ` ${this._announcements.link} ` : null;
224
+ }
225
+ _getVisibleText(subDocument, interval, includeNumberedListMarks = false) {
226
+ const result = subDocument.getVisibleText(interval, {
227
+ includeNumberedListMarks,
228
+ transform: (info, fieldIndexes) => {
229
+ const prefix = this._onHyperlinkFieldStart(fieldIndexes, subDocument, info.getAbsolutePosition());
230
+ const text = this._tryResolveDocumentElements(info);
231
+ if (prefix == null && text == null)
232
+ return null;
233
+ return {
234
+ text: (prefix ?? '') + (text ?? ''),
235
+ action: text != null ? TransformAction.Replace : TransformAction.InsertBefore
236
+ };
237
+ }
238
+ });
239
+ return result === RichUtils.specialCharacters.ParagraphMark
240
+ ? this._announcements.blank
241
+ : result;
242
+ }
243
+ _tryResolveDocumentElements(info) {
244
+ return info.run.getType() === RunType.InlinePictureRun
245
+ ? this._getInlinePictureText(info.run)
246
+ : this._tryResolveSpecialCharacters(info);
247
+ }
248
+ _tryResolveSpecialCharacters(info) {
249
+ const char = info.getCurrentChar();
250
+ if (char === RichUtils.specialCharacters.PageBreak || char === RichUtils.specialCharacters.SectionMark)
251
+ return ` ${this._announcements.pageBreak} `;
252
+ return null;
253
+ }
254
+ _getInlinePictureText(run) {
255
+ const nonVisualProps = run.info.nonVisualDrawingProperties;
256
+ return formatString(this._announcements.picture, nonVisualProps.description ?? nonVisualProps.name ?? '');
257
+ }
258
+ _getPageChangePrefix(pageIndex) {
259
+ if (this._pageIndex === null) {
260
+ this._pageIndex = pageIndex;
261
+ return '';
262
+ }
263
+ if (pageIndex !== this._pageIndex) {
264
+ this._pageIndex = pageIndex;
265
+ return formatString(this._announcements.page, pageIndex + 1);
266
+ }
267
+ return '';
268
+ }
269
+ _getCharName(char) {
270
+ if (char in this._charNames)
271
+ return this._charNames[char];
272
+ return ScreenReaderManager._spaceSeparatorRegex.test(char) ? this._announcements.space : char;
273
+ }
274
+ _resolveListMarker(paragraph) {
275
+ const levelIndex = paragraph.getListLevelIndex();
276
+ const levelType = paragraph.getNumberingList().getLevelType(levelIndex);
277
+ if (levelType === NumberingType.Bullet)
278
+ return this._announcements.bullet;
279
+ return paragraph.getNumberingListText();
280
+ }
281
+ _getListItemAnnouncement(paragraph, pos, lp, content) {
282
+ if (!paragraph.isInList() || pos !== paragraph.startLogPosition.value || !lp?.row?.numberingListBox)
283
+ return null;
284
+ const level = paragraph.getListLevelIndex() + 1;
285
+ const listMarker = this._resolveListMarker(paragraph);
286
+ return `${formatString(this._announcements.listItem, level, listMarker)} ${content}`;
287
+ }
288
+ dispose() {
289
+ this._clearAnnouncement();
290
+ this._liveRegion.remove();
291
+ }
292
+ }
293
+ const stringFormatterCache = {};
294
+ function createFormatter(template) {
295
+ const tokens = [];
296
+ let lastIndex = 0;
297
+ template.replace(/\{(\d+)\}/g, (match, p1, offset) => {
298
+ if (lastIndex < offset)
299
+ tokens.push(template.slice(lastIndex, offset));
300
+ tokens.push(Number(p1));
301
+ lastIndex = offset + match.length;
302
+ return match;
303
+ });
304
+ if (lastIndex < template.length)
305
+ tokens.push(template.slice(lastIndex));
306
+ return (args) => {
307
+ let result = '';
308
+ for (const token of tokens) {
309
+ if (typeof token === 'string')
310
+ result += token;
311
+ else {
312
+ const value = args[token];
313
+ result += value ?? '';
314
+ }
315
+ }
316
+ return result;
317
+ };
318
+ }
319
+ function formatString(template, ...args) {
320
+ let formatter = stringFormatterCache[template];
321
+ if (!formatter) {
322
+ formatter = createFormatter(template);
323
+ stringFormatterCache[template] = formatter;
324
+ }
325
+ return formatter(args);
326
+ }
@@ -3,6 +3,7 @@ export declare class StringResources {
3
3
  seqCaptionPrefixes: SeqCaptionPrefixes;
4
4
  commonLabels: CommonLabels;
5
5
  quickSearchPanel: QuickSearchPanelStringResources;
6
+ announcements: IAnnouncementStringResources;
6
7
  constructor();
7
8
  }
8
9
  export declare class HeaderFooterStringResources {
@@ -31,3 +32,25 @@ export declare class QuickSearchPanelStringResources {
31
32
  noMatches: string;
32
33
  of: string;
33
34
  }
35
+ export interface IAnnouncementStringResources {
36
+ inTable?: string;
37
+ outOfTable?: string;
38
+ tableRow?: string;
39
+ tableColumn?: string;
40
+ selectAll?: string;
41
+ textSelected?: string;
42
+ textUnselected?: string;
43
+ tab?: string;
44
+ carriageReturn?: string;
45
+ lineBreak?: string;
46
+ picture?: string;
47
+ page?: string;
48
+ space?: string;
49
+ bullet?: string;
50
+ listItem?: string;
51
+ link?: string;
52
+ outOfLink?: string;
53
+ blank?: string;
54
+ pageBreak?: string;
55
+ }
56
+ export declare function getStringResources(): StringResources;
@@ -1,9 +1,11 @@
1
+ import { formatMessage } from "devextreme/localization";
1
2
  export class StringResources {
2
3
  constructor() {
3
4
  this.headerFooter = new HeaderFooterStringResources();
4
5
  this.seqCaptionPrefixes = new SeqCaptionPrefixes();
5
6
  this.commonLabels = new CommonLabels();
6
7
  this.quickSearchPanel = new QuickSearchPanelStringResources();
8
+ this.announcements = {};
7
9
  }
8
10
  }
9
11
  export class HeaderFooterStringResources {
@@ -14,3 +16,44 @@ export class CommonLabels {
14
16
  }
15
17
  export class QuickSearchPanelStringResources {
16
18
  }
19
+ export function getStringResources() {
20
+ const sr = new StringResources();
21
+ sr.headerFooter.evenPageFooter = formatMessage('XtraRichEditStringId.Caption_EvenPageFooter');
22
+ sr.headerFooter.evenPageHeader = formatMessage('XtraRichEditStringId.Caption_EvenPageHeader');
23
+ sr.headerFooter.firstPageFooter = formatMessage('XtraRichEditStringId.Caption_FirstPageFooter');
24
+ sr.headerFooter.firstPageHeader = formatMessage('XtraRichEditStringId.Caption_FirstPageHeader');
25
+ sr.headerFooter.footer = formatMessage('XtraRichEditStringId.Caption_PageFooter');
26
+ sr.headerFooter.header = formatMessage('XtraRichEditStringId.Caption_PageHeader');
27
+ sr.headerFooter.oddPageFooter = formatMessage('XtraRichEditStringId.Caption_OddPageFooter');
28
+ sr.headerFooter.oddPageHeader = formatMessage('XtraRichEditStringId.Caption_OddPageHeader');
29
+ sr.headerFooter.sameAsPrevious = formatMessage('XtraRichEditStringId.Caption_SameAsPrevious');
30
+ sr.seqCaptionPrefixes.figurePrefix = formatMessage('XtraRichEditStringId.Caption_CaptionPrefixFigure');
31
+ sr.seqCaptionPrefixes.tablePrefix = formatMessage('XtraRichEditStringId.Caption_CaptionPrefixTable');
32
+ sr.seqCaptionPrefixes.equationPrefix = formatMessage('XtraRichEditStringId.Caption_CaptionPrefixEquation');
33
+ sr.commonLabels.noTocEntriesFound = formatMessage('XtraRichEditStringId.Msg_NoTocEntriesFound');
34
+ sr.commonLabels.clickToFollowHyperlink = formatMessage('XtraRichEditStringId.Msg_ClickToFollowHyperlink');
35
+ sr.commonLabels.currentDocumentHyperlinkTooltip = formatMessage('XtraRichEditStringId.Caption_CurrentDocumentHyperlinkTooltip');
36
+ sr.quickSearchPanel.of = formatMessage('ASPxRichEditStringId.FindReplace_Of');
37
+ sr.quickSearchPanel.items = formatMessage('ASPxRichEditStringId.FindReplace_Items');
38
+ sr.quickSearchPanel.noMatches = formatMessage('ASPxRichEditStringId.FindReplace_NoMatches');
39
+ sr.announcements.inTable = formatMessage('AspNetCoreRichEditStringId.InTableAnnouncement');
40
+ sr.announcements.outOfTable = formatMessage('AspNetCoreRichEditStringId.OutOfTableAnnouncement');
41
+ sr.announcements.tableRow = formatMessage('AspNetCoreRichEditStringId.TableRowAnnouncement');
42
+ sr.announcements.tableColumn = formatMessage('AspNetCoreRichEditStringId.TableColumnAnnouncement');
43
+ sr.announcements.selectAll = formatMessage('AspNetCoreRichEditStringId.SelectAllAnnouncement');
44
+ sr.announcements.textSelected = formatMessage('AspNetCoreRichEditStringId.TextSelectedAnnouncement');
45
+ sr.announcements.textUnselected = formatMessage('AspNetCoreRichEditStringId.TextUnselectedAnnouncement');
46
+ sr.announcements.picture = formatMessage('AspNetCoreRichEditStringId.PictureAnnouncement');
47
+ sr.announcements.page = formatMessage('AspNetCoreRichEditStringId.PageAnnouncement');
48
+ sr.announcements.space = formatMessage('AspNetCoreRichEditStringId.SpaceAnnouncement');
49
+ sr.announcements.bullet = formatMessage('AspNetCoreRichEditStringId.BulletAnnouncement');
50
+ sr.announcements.listItem = formatMessage('AspNetCoreRichEditStringId.ListItemAnnouncement');
51
+ sr.announcements.tab = formatMessage('AspNetCoreRichEditStringId.TabAnnouncement');
52
+ sr.announcements.carriageReturn = formatMessage('AspNetCoreRichEditStringId.CarriageReturnAnnouncement');
53
+ sr.announcements.lineBreak = formatMessage('AspNetCoreRichEditStringId.LineBreakAnnouncement');
54
+ sr.announcements.link = formatMessage('AspNetCoreRichEditStringId.LinkAnnouncement');
55
+ sr.announcements.outOfLink = formatMessage('AspNetCoreRichEditStringId.OutOfLinkAnnouncement');
56
+ sr.announcements.blank = formatMessage('AspNetCoreRichEditStringId.BlankAnnouncement');
57
+ sr.announcements.pageBreak = formatMessage('AspNetCoreRichEditStringId.PageBreakAnnouncement');
58
+ return sr;
59
+ }
@@ -0,0 +1,4 @@
1
+ import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed';
2
+ export declare class IntervalUtils {
3
+ static subtractIntervals(a: FixedInterval[], b: FixedInterval[]): FixedInterval[];
4
+ }
@@ -0,0 +1,25 @@
1
+ import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed';
2
+ export class IntervalUtils {
3
+ static subtractIntervals(a, b) {
4
+ const result = [];
5
+ let bIndex = 0;
6
+ for (const interval of a) {
7
+ let currentFrom = interval.start;
8
+ const currentTo = interval.end;
9
+ for (; bIndex < b.length && b[bIndex].start < currentTo; bIndex++) {
10
+ if (b[bIndex].end <= currentFrom)
11
+ continue;
12
+ if (b[bIndex].start > currentFrom)
13
+ result.push(FixedInterval.fromPositions(currentFrom, Math.min(b[bIndex].start, currentTo)));
14
+ currentFrom = Math.max(currentFrom, b[bIndex].end);
15
+ if (currentFrom >= currentTo) {
16
+ bIndex++;
17
+ break;
18
+ }
19
+ }
20
+ if (currentFrom < currentTo)
21
+ result.push(FixedInterval.fromPositions(currentFrom, currentTo));
22
+ }
23
+ return result;
24
+ }
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devexpress-richedit",
3
- "version": "25.2.8",
3
+ "version": "26.1.3",
4
4
  "homepage": "https://www.devexpress.com/",
5
5
  "bugs": "https://www.devexpress.com/support/",
6
6
  "author": "Developer Express Inc.",
@@ -11,8 +11,8 @@
11
11
  "build-nspell": "webpack --mode production --config=bin/nspell.webpack.config.js"
12
12
  },
13
13
  "peerDependencies": {
14
- "devextreme": "25.2.8",
15
- "devextreme-dist": "25.2.8"
14
+ "devextreme": "26.1.3",
15
+ "devextreme-dist": "26.1.3"
16
16
  },
17
17
  "devDependencies": {
18
18
  "dictionary-en": "3.2.0",