@agilemotion/oui-react-js 1.8.57 → 1.8.59
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.
- package/dist/components/DataGrid.css +2 -2
- package/dist/components/DataGridColumn.js +20 -3
- package/dist/components/DocumentTemplateDesigner.js +9 -5
- package/dist/components/DocumentTemplateDesignerComponent.js +48 -548
- package/dist/components/DocumentViewer.js +4 -1
- package/dist/components/Toolbar.js +41 -13
- package/dist/components/WordDocumentViewer.css +7 -1
- package/dist/components/WordDocumentViewer.js +277 -248
- package/dist/components/form/Form.js +1 -1
- package/dist/components/media/ToolbarButton.js +22 -23
- package/package.json +10 -10
- package/dist/components/DocumentTemplateDesignerComponent2.js +0 -584
|
@@ -16,7 +16,7 @@ var _LottieIcon = _interopRequireDefault(require("./LottieIcon"));
|
|
|
16
16
|
require("./WordDocumentViewer.css");
|
|
17
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
19
|
-
const KEY = exports.KEY = '
|
|
19
|
+
const KEY = exports.KEY = 'Ngo9BigBOggjHTQxAR8/V1JGaF5cXGpCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdlWX5ceHVRQ2BYUUdwX0NWYEs=';
|
|
20
20
|
(0, _ej2Base.registerLicense)(KEY);
|
|
21
21
|
const DOCSVC = exports.DOCSVC = "https://document.syncfusion.com/web-services/docx-editor/api/documenteditor/";
|
|
22
22
|
_ej2ReactDocumenteditor.DocumentEditorContainerComponent.Inject(_ej2ReactDocumenteditor.Toolbar);
|
|
@@ -73,90 +73,24 @@ function applyLevel(ed) {
|
|
|
73
73
|
ed.selection.paragraphFormat.listLevelNumber = depth;
|
|
74
74
|
ed.applyNumbering(LEVEL_FMT[depth], 'Arabic');
|
|
75
75
|
}
|
|
76
|
-
const ANCHOR_REGEX = /\[\[(.*?)\]\]/g;
|
|
77
76
|
const WordDocumentViewer = props => {
|
|
78
77
|
const [container, setContainer] = _react.default.useState(null);
|
|
79
78
|
const [items, setItems] = _react.default.useState(null);
|
|
80
|
-
const [height, setHeight] = _react.default.useState(0);
|
|
81
|
-
const [width, setWidth] = _react.default.useState(0);
|
|
82
79
|
const [visible, setVisible] = _react.default.useState(true);
|
|
83
80
|
const [reRendering, setReRendering] = _react.default.useState(false);
|
|
84
81
|
const [json, setJson] = _react.default.useState(null);
|
|
85
82
|
const [errorMessage, setErrorMessage] = _react.default.useState(null);
|
|
86
|
-
const
|
|
83
|
+
const currentText = _react.default.useRef(null);
|
|
84
|
+
const activeAnchorRef = (0, _react.useRef)(null);
|
|
85
|
+
const anchorEnd = (0, _react.useRef)(false);
|
|
86
|
+
const deleteLockRef = (0, _react.useRef)(false);
|
|
87
|
+
const loading = (0, _react.useRef)(true);
|
|
87
88
|
const ref = useOnFullyVisible(el => {
|
|
88
|
-
//console.log('Document fully visible & rendered:', el);
|
|
89
89
|
if (!reRendering) {
|
|
90
90
|
setVisible(false);
|
|
91
91
|
setReRendering(true);
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
|
-
function extractDocumentText() {
|
|
95
|
-
const doc = container.documentEditor;
|
|
96
|
-
doc.selection.selectAll();
|
|
97
|
-
const text = doc.selection.getText();
|
|
98
|
-
doc.selection.clear();
|
|
99
|
-
return text;
|
|
100
|
-
}
|
|
101
|
-
function extractAnchorTokens(text) {
|
|
102
|
-
const tokens = new Set();
|
|
103
|
-
let match;
|
|
104
|
-
while ((match = ANCHOR_REGEX.exec(text)) !== null) {
|
|
105
|
-
tokens.add(match[0]); // exact token string
|
|
106
|
-
}
|
|
107
|
-
return Array.from(tokens);
|
|
108
|
-
}
|
|
109
|
-
function locateTokenRanges(token) {
|
|
110
|
-
var _search$searchResults;
|
|
111
|
-
const doc = container.documentEditor;
|
|
112
|
-
const search = doc.search;
|
|
113
|
-
const ranges = [];
|
|
114
|
-
search.find(token);
|
|
115
|
-
const results = (_search$searchResults = search.searchResults) === null || _search$searchResults === void 0 || (_search$searchResults = _search$searchResults.searchModule) === null || _search$searchResults === void 0 || (_search$searchResults = _search$searchResults.textSearchResults) === null || _search$searchResults === void 0 ? void 0 : _search$searchResults.innerList;
|
|
116
|
-
if (!results || results.length === 0) {
|
|
117
|
-
search.clear();
|
|
118
|
-
return ranges;
|
|
119
|
-
}
|
|
120
|
-
for (let i = 0; i < results.length; i++) {
|
|
121
|
-
const res = results[i];
|
|
122
|
-
ranges.push({
|
|
123
|
-
token,
|
|
124
|
-
start: res.startIn,
|
|
125
|
-
// ✅ SAFE
|
|
126
|
-
end: res.endIn // ✅ SAFE
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
doc.selection.clear();
|
|
130
|
-
return ranges;
|
|
131
|
-
}
|
|
132
|
-
function rebuildRestrictedRanges() {
|
|
133
|
-
if (!(container !== null && container !== void 0 && container.documentEditor)) return;
|
|
134
|
-
const text = extractDocumentText();
|
|
135
|
-
const tokens = extractAnchorTokens(text);
|
|
136
|
-
restrictedRangesRef.current = [];
|
|
137
|
-
tokens.forEach(token => {
|
|
138
|
-
const ranges = locateTokenRanges(token);
|
|
139
|
-
ranges.forEach(r => {
|
|
140
|
-
restrictedRangesRef.current.push({
|
|
141
|
-
id: 'rehydrated-' + restrictedRangesRef.current.length,
|
|
142
|
-
token: r.token,
|
|
143
|
-
start: r.start,
|
|
144
|
-
end: r.end
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/*let items = ['Bold', 'Italic', 'Underline', '|', 'Formats', '|', 'CreateLink', '|',
|
|
151
|
-
{
|
|
152
|
-
template: '' +
|
|
153
|
-
'<button class="e-tbar-btn e-btn" tabindex="-1" id="custom_tbar" style="width:100%"><div class="e-tbar-btn-text" style="font-weight: normal; font-size: inherit;"> Placeholders</div></button>',
|
|
154
|
-
undo: true,
|
|
155
|
-
click: onClick.bind(this),
|
|
156
|
-
tooltipText: 'Insert Placeholders'
|
|
157
|
-
}, '|', 'Undo', 'Redo'
|
|
158
|
-
];*/
|
|
159
|
-
|
|
160
94
|
function isPointInsideElement(x, y, el) {
|
|
161
95
|
if (!el) return false;
|
|
162
96
|
const rect = el.getBoundingClientRect();
|
|
@@ -165,76 +99,40 @@ const WordDocumentViewer = props => {
|
|
|
165
99
|
function getViewerElement() {
|
|
166
100
|
return document.getElementById("".concat(props.id, "-container_editor_viewerContainer"));
|
|
167
101
|
}
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// Focus editor first
|
|
176
|
-
container.documentEditor.focusIn();
|
|
177
|
-
|
|
178
|
-
// IMPORTANT: click the actual element under the pointer (not just viewer)
|
|
179
|
-
const target = document.elementFromPoint(dropPosition.x, dropPosition.y) || viewer;
|
|
180
|
-
const down = new MouseEvent("mousedown", {
|
|
181
|
-
bubbles: true,
|
|
182
|
-
cancelable: true,
|
|
183
|
-
clientX: dropPosition.x,
|
|
184
|
-
clientY: dropPosition.y,
|
|
185
|
-
buttons: 1
|
|
186
|
-
});
|
|
187
|
-
const up = new MouseEvent("mouseup", {
|
|
188
|
-
bubbles: true,
|
|
189
|
-
cancelable: true,
|
|
190
|
-
clientX: dropPosition.x,
|
|
191
|
-
clientY: dropPosition.y
|
|
192
|
-
});
|
|
193
|
-
const click = new MouseEvent("click", {
|
|
194
|
-
bubbles: true,
|
|
195
|
-
cancelable: true,
|
|
196
|
-
clientX: dropPosition.x,
|
|
197
|
-
clientY: dropPosition.y
|
|
198
|
-
});
|
|
199
|
-
target.dispatchEvent(down);
|
|
200
|
-
target.dispatchEvent(up);
|
|
201
|
-
target.dispatchEvent(click);
|
|
202
|
-
return true;
|
|
102
|
+
function isNavigationKey(e) {
|
|
103
|
+
return ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].includes(e.key);
|
|
104
|
+
}
|
|
105
|
+
function normalizeAnchor(value) {
|
|
106
|
+
if (!value) return null;
|
|
107
|
+
return value.replace(/^\[\[|\]\]$/g, '').replace(/^<<|>>$/g, '');
|
|
203
108
|
}
|
|
109
|
+
let viewerElement = getViewerElement();
|
|
204
110
|
function insertReadonlyAnchor(eventData, dropPosition) {
|
|
205
111
|
if (!(container !== null && container !== void 0 && container.documentEditor)) return;
|
|
206
112
|
if (!dropPosition) return;
|
|
207
|
-
|
|
208
|
-
//const moved = moveCaretToDropPoint(dropPosition);
|
|
209
|
-
//if (!moved) return; // drop wasn't inside this document
|
|
210
|
-
|
|
211
|
-
const viewer = getViewerElement();
|
|
212
|
-
if (!isPointInsideElement(dropPosition.x, dropPosition.y, viewer)) {
|
|
113
|
+
if (!isPointInsideElement(dropPosition.x, dropPosition.y, viewerElement)) {
|
|
213
114
|
// Drop did not happen inside this document
|
|
115
|
+
//console.log("DROP NOT INSIDE THIS DOCUMENT : ", dropPosition);
|
|
214
116
|
return;
|
|
215
117
|
}
|
|
216
118
|
const doc = container.documentEditor;
|
|
217
119
|
const ed = doc.editor;
|
|
218
120
|
const sel = doc.selection;
|
|
219
121
|
if (!ed || !sel) return;
|
|
220
|
-
const
|
|
221
|
-
const token = "[[".concat(eventData, "]]");
|
|
122
|
+
const token = "[[".concat(normalizeAnchor(eventData), "]]");
|
|
222
123
|
ed.insertText(token);
|
|
223
|
-
const end = sel.end.clone();
|
|
224
|
-
restrictedRangesRef.current.push({
|
|
225
|
-
id: 'anchor-' + Date.now(),
|
|
226
|
-
start,
|
|
227
|
-
end,
|
|
228
|
-
token
|
|
229
|
-
});
|
|
230
124
|
}
|
|
125
|
+
const dropData = _react.default.useRef(null);
|
|
231
126
|
const api = () => {
|
|
232
127
|
return {
|
|
233
128
|
getValue: () => {
|
|
234
129
|
return saveAsBase64();
|
|
235
130
|
},
|
|
236
|
-
insertReadonlyAnchor: (value, dropPosition) => {
|
|
237
|
-
|
|
131
|
+
insertReadonlyAnchor: async (value, dropPosition) => {
|
|
132
|
+
dropData.current = {
|
|
133
|
+
value,
|
|
134
|
+
dropPosition
|
|
135
|
+
};
|
|
238
136
|
}
|
|
239
137
|
};
|
|
240
138
|
};
|
|
@@ -256,86 +154,6 @@ const WordDocumentViewer = props => {
|
|
|
256
154
|
id: 'clear',
|
|
257
155
|
text: 'Clear list'
|
|
258
156
|
}];
|
|
259
|
-
const onNumberingSelect = args => {
|
|
260
|
-
var _containerRef$current;
|
|
261
|
-
const ed = (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 || (_containerRef$current = _containerRef$current.documentEditor) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.editor;
|
|
262
|
-
if (!ed) return;
|
|
263
|
-
switch (args.item.id) {
|
|
264
|
-
case 'lvl-0':
|
|
265
|
-
applyLevel(ed, 0);
|
|
266
|
-
break;
|
|
267
|
-
case 'lvl-1':
|
|
268
|
-
applyLevel(ed, 1);
|
|
269
|
-
break;
|
|
270
|
-
case 'lvl-2':
|
|
271
|
-
applyLevel(ed, 2);
|
|
272
|
-
break;
|
|
273
|
-
case 'clear':
|
|
274
|
-
ed.clearList();
|
|
275
|
-
break;
|
|
276
|
-
default:
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
const onCreated = () => {
|
|
281
|
-
var _container$toolbarMod;
|
|
282
|
-
const container = containerRef.current;
|
|
283
|
-
const tb = container === null || container === void 0 || (_container$toolbarMod = container.toolbarModule) === null || _container$toolbarMod === void 0 ? void 0 : _container$toolbarMod.toolbar; // EJ2 Toolbar instance
|
|
284
|
-
if (!tb) return;
|
|
285
|
-
|
|
286
|
-
// 1) Add a placeholder button into the toolbar at the end
|
|
287
|
-
tb.addItems([{
|
|
288
|
-
type: 'Separator'
|
|
289
|
-
}, {
|
|
290
|
-
// Use a real HTML template (string) and give it an id
|
|
291
|
-
template: '<button id="numbering-ddb" class="e-btn e-flat" type="button">Numbering</button>',
|
|
292
|
-
tooltipText: 'Numbering styles'
|
|
293
|
-
}], tb.items.length);
|
|
294
|
-
|
|
295
|
-
// 2) Turn that placeholder into a functioning DropDownButton
|
|
296
|
-
const ddb = new DropDownButton({
|
|
297
|
-
content: 'Numbering',
|
|
298
|
-
cssClass: 'e-flat',
|
|
299
|
-
items: [{
|
|
300
|
-
id: 'lvl-0',
|
|
301
|
-
text: '1.'
|
|
302
|
-
}, {
|
|
303
|
-
id: 'lvl-1',
|
|
304
|
-
text: '1.1'
|
|
305
|
-
}, {
|
|
306
|
-
id: 'lvl-2',
|
|
307
|
-
text: '1.1.1'
|
|
308
|
-
}, {
|
|
309
|
-
separator: true
|
|
310
|
-
}, {
|
|
311
|
-
id: 'clear',
|
|
312
|
-
text: 'Clear list'
|
|
313
|
-
}],
|
|
314
|
-
select: args => {
|
|
315
|
-
const ed = container.documentEditor.editor;
|
|
316
|
-
if (!ed) return;
|
|
317
|
-
switch (args.item.id) {
|
|
318
|
-
case 'lvl-0':
|
|
319
|
-
applyLevel(ed, 0);
|
|
320
|
-
break;
|
|
321
|
-
case 'lvl-1':
|
|
322
|
-
applyLevel(ed, 1);
|
|
323
|
-
break;
|
|
324
|
-
case 'lvl-2':
|
|
325
|
-
applyLevel(ed, 2);
|
|
326
|
-
break;
|
|
327
|
-
case 'clear':
|
|
328
|
-
ed.clearList();
|
|
329
|
-
break;
|
|
330
|
-
default:
|
|
331
|
-
break;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}, '#numbering-ddb');
|
|
335
|
-
|
|
336
|
-
// (optional) keep a ref if you want to dispose on unmount
|
|
337
|
-
container._numberingDDB = ddb;
|
|
338
|
-
};
|
|
339
157
|
_react.default.useEffect(() => {
|
|
340
158
|
let toolbarItems = props.commentsOnly ? ["Comments"] : ["Undo", "Redo", "Separator", {
|
|
341
159
|
id: 'bullets',
|
|
@@ -403,11 +221,173 @@ const WordDocumentViewer = props => {
|
|
|
403
221
|
});
|
|
404
222
|
}
|
|
405
223
|
};
|
|
406
|
-
function
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
224
|
+
function extractDocumentText(editor) {
|
|
225
|
+
if (currentText.current) return currentText.current;
|
|
226
|
+
const originalStart = selection.startOffset;
|
|
227
|
+
const originalEnd = selection.endOffset;
|
|
228
|
+
editor.selection.selectAll();
|
|
229
|
+
const text = editor.selection.getText();
|
|
230
|
+
editor.selection.select(originalStart, originalEnd);
|
|
231
|
+
currentText.current = text;
|
|
232
|
+
return text;
|
|
233
|
+
}
|
|
234
|
+
function extractAnchorTokens(text) {
|
|
235
|
+
const regex = /\[\[[^\[\]]+?\]\]/g;
|
|
236
|
+
const tokens = new Set();
|
|
237
|
+
let match;
|
|
238
|
+
while ((match = regex.exec(text)) !== null) {
|
|
239
|
+
tokens.add(match[0]); // exact [[TEXT]]
|
|
240
|
+
}
|
|
241
|
+
return Array.from(tokens);
|
|
242
|
+
}
|
|
243
|
+
function isCaretWithinRange(caret, start, end) {
|
|
244
|
+
if (caret.paragraph !== start.paragraph) return false;
|
|
245
|
+
const x = caret.location.xIn;
|
|
246
|
+
const y = caret.location.yIn;
|
|
247
|
+
|
|
248
|
+
//console.log("CHECKING CARET WITHIN RANGE : ", x, y, start.location.xIn, start.location.yIn, end.location.xIn, end.location.yIn);
|
|
249
|
+
return y === start.location.yIn && x >= start.location.xIn && x <= end.location.xIn;
|
|
250
|
+
}
|
|
251
|
+
function deleteCurrentAnchor(container) {
|
|
252
|
+
const editor = container === null || container === void 0 ? void 0 : container.documentEditor;
|
|
253
|
+
const selection = editor === null || editor === void 0 ? void 0 : editor.selection;
|
|
254
|
+
const docEditor = editor === null || editor === void 0 ? void 0 : editor.editor;
|
|
255
|
+
const anchor = activeAnchorRef.current;
|
|
256
|
+
if (!editor || !selection || !docEditor || !anchor) return;
|
|
257
|
+
|
|
258
|
+
//console.log("END OFFSET : ", anchor.endOffset, bumpOffset(anchor.endOffset, -1))
|
|
259
|
+
//console.log("START - END : ", anchor.startOffset, bumpOffset(anchor.endOffset, -1));
|
|
260
|
+
try {
|
|
261
|
+
selection.select(anchor.startOffset, anchor.endOffset);
|
|
262
|
+
//console.log("SELECTION TEXT : " + selection.text);
|
|
263
|
+
//docEditor.delete();
|
|
264
|
+
//selection.select(anchor.startOffset, anchor.startOffset);
|
|
265
|
+
} finally {
|
|
266
|
+
activeAnchorRef.current = null;
|
|
267
|
+
updateActiveAnchor(container);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function updateActiveAnchor(container) {
|
|
271
|
+
activeAnchorRef.current = grabAnchorWithBounds(container);
|
|
272
|
+
}
|
|
273
|
+
function scanRightUntilAnchor(editor, originOffset) {
|
|
274
|
+
let maxScan = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 500;
|
|
275
|
+
const sel = editor.selection;
|
|
276
|
+
let current = originOffset;
|
|
277
|
+
for (let i = 0; i < maxScan; i++) {
|
|
278
|
+
// move right
|
|
279
|
+
current = bumpOffset(current, +1);
|
|
280
|
+
sel.select(current, current);
|
|
281
|
+
|
|
282
|
+
// select ONE character only
|
|
283
|
+
sel.select(current, bumpOffset(current, +1));
|
|
284
|
+
const ch = sel.text;
|
|
285
|
+
|
|
286
|
+
// ⛔ Bail on whitespace or paragraph break
|
|
287
|
+
if (!ch || /\s/.test(ch)) return null;
|
|
288
|
+
|
|
289
|
+
// Detect closing "]]"
|
|
290
|
+
if (ch === ']') {
|
|
291
|
+
// lookahead one char
|
|
292
|
+
const next = bumpOffset(current, +1);
|
|
293
|
+
sel.select(next, bumpOffset(next, +1));
|
|
294
|
+
if (sel.text === ']') {
|
|
295
|
+
// return position AFTER ]]
|
|
296
|
+
return bumpOffset(current, +2);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
function scanLeftUntilAnchor(editor, originOffset) {
|
|
303
|
+
let maxScan = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 500;
|
|
304
|
+
const sel = editor.selection;
|
|
305
|
+
let current = originOffset;
|
|
306
|
+
for (let i = 0; i < maxScan; i++) {
|
|
307
|
+
current = bumpOffset(current, -1);
|
|
308
|
+
|
|
309
|
+
// select one char to the left
|
|
310
|
+
sel.select(bumpOffset(current, -1), current);
|
|
311
|
+
const ch = sel.text;
|
|
312
|
+
if (!ch || /\s/.test(ch)) return null;
|
|
313
|
+
|
|
314
|
+
// detect [[
|
|
315
|
+
if (ch === '[') {
|
|
316
|
+
const prev = bumpOffset(current, -1);
|
|
317
|
+
sel.select(bumpOffset(prev, -1), prev);
|
|
318
|
+
if (sel.text === '[') {
|
|
319
|
+
// 🔑 FIX: go back TWO chars
|
|
320
|
+
return bumpOffset(current, -2);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
function getCharAt(editor, offset) {
|
|
327
|
+
const sel = editor.selection;
|
|
328
|
+
sel.select(offset, bumpOffset(offset, +1));
|
|
329
|
+
return sel.text || null;
|
|
330
|
+
}
|
|
331
|
+
function isCaretImmediatelyBeforeAnchorStart(editor, offset) {
|
|
332
|
+
const c0 = getCharAt(editor, offset);
|
|
333
|
+
const c1 = getCharAt(editor, bumpOffset(offset, +1));
|
|
334
|
+
return c0 === '[' && c1 === '['; // |[[TEXT]]
|
|
335
|
+
}
|
|
336
|
+
function isCaretImmediatelyAfterAnchor(editor, offset) {
|
|
337
|
+
return getCharAt(editor, bumpOffset(offset, -1)) === ']' && getCharAt(editor, bumpOffset(offset, -2)) === ']';
|
|
338
|
+
}
|
|
339
|
+
function grabAnchorWithBounds(container) {
|
|
340
|
+
const editor = container === null || container === void 0 ? void 0 : container.documentEditor;
|
|
341
|
+
const selection = editor === null || editor === void 0 ? void 0 : editor.selection;
|
|
342
|
+
const originalStart = selection.startOffset;
|
|
343
|
+
const originalEnd = selection.endOffset;
|
|
344
|
+
selection.selectCurrentWord();
|
|
345
|
+
selection.select(originalStart, originalEnd);
|
|
346
|
+
|
|
347
|
+
//let word = selection.text;
|
|
348
|
+
//console.log("grabAnchorWithBounds SELECTION TEXT : ", word);
|
|
349
|
+
|
|
350
|
+
let scanStart = originalStart;
|
|
351
|
+
try {
|
|
352
|
+
if (isCaretImmediatelyBeforeAnchorStart(editor, originalStart)) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
let isCaretAtEnd = isCaretImmediatelyAfterAnchor(editor, originalStart);
|
|
356
|
+
if (isCaretAtEnd) {
|
|
357
|
+
//console.log("CARET AT END");
|
|
358
|
+
scanStart = bumpOffset(originalStart, -3);
|
|
359
|
+
}
|
|
360
|
+
const left = scanLeftUntilAnchor(editor, scanStart);
|
|
361
|
+
const right = scanRightUntilAnchor(editor, scanStart);
|
|
362
|
+
if (left && right) {
|
|
363
|
+
selection.select(left, right);
|
|
364
|
+
const text = selection.text;
|
|
365
|
+
anchorEnd.current = isCaretAtEnd;
|
|
366
|
+
|
|
367
|
+
/*console.log("GRAB RESULT : ", {
|
|
368
|
+
token: text,
|
|
369
|
+
startOffset: left,
|
|
370
|
+
endOffset: right
|
|
371
|
+
});*/
|
|
372
|
+
|
|
373
|
+
if (/^\[\[.+?\]\]$/.test(text)) {
|
|
374
|
+
return {
|
|
375
|
+
token: text,
|
|
376
|
+
startOffset: left,
|
|
377
|
+
endOffset: right
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} finally {
|
|
382
|
+
selection.select(originalStart, originalEnd);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function bumpOffset(offset, delta) {
|
|
386
|
+
const parts = offset.split(';');
|
|
387
|
+
const idx = parts.length - 1;
|
|
388
|
+
const value = Math.max(0, parseInt(parts[idx], 10) + delta);
|
|
389
|
+
parts[idx] = value.toString();
|
|
390
|
+
return parts.join(';');
|
|
411
391
|
}
|
|
412
392
|
_react.default.useEffect(() => {
|
|
413
393
|
if (container) {
|
|
@@ -415,64 +395,109 @@ const WordDocumentViewer = props => {
|
|
|
415
395
|
//autoSave();
|
|
416
396
|
|
|
417
397
|
const editor = container.documentEditor;
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
if (!selection) return;
|
|
421
|
-
const insideRestricted = restrictedRangesRef.current.some(range => selectionOverlapsRange(selection, range));
|
|
422
|
-
if (insideRestricted) {
|
|
423
|
-
const e = args.event;
|
|
424
|
-
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
425
|
-
e.preventDefault();
|
|
426
|
-
e.stopPropagation();
|
|
427
|
-
const range = restrictedRangesRef.current.find(r => selectionOverlapsRange(selection, r));
|
|
428
|
-
if (range) {
|
|
429
|
-
// Select only the anchor range
|
|
430
|
-
selection.selectRange(range.start, range.end);
|
|
398
|
+
editor.addEventListener('keyDown', args => {
|
|
399
|
+
const e = args.event;
|
|
431
400
|
|
|
432
|
-
|
|
433
|
-
|
|
401
|
+
// 1️⃣ Navigation keys → inspect only
|
|
402
|
+
if (isNavigationKey(e)) {
|
|
403
|
+
requestAnimationFrame(() => {
|
|
404
|
+
updateActiveAnchor(container);
|
|
405
|
+
//console.log("ACTIVE ANCHOR : ", activeAnchorRef.current);
|
|
406
|
+
});
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
434
409
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
410
|
+
//console.log("DELETE LOCKED : ", deleteLockRef.current);
|
|
411
|
+
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
412
|
+
if (deleteLockRef.current) {
|
|
413
|
+
// Syncfusion already deleted → rewind safely
|
|
414
|
+
editor.editorHistory.undo();
|
|
415
|
+
e.preventDefault();
|
|
416
|
+
e.stopPropagation();
|
|
438
417
|
return;
|
|
439
418
|
}
|
|
440
419
|
|
|
441
|
-
//
|
|
442
|
-
|
|
420
|
+
// Acquire lock
|
|
421
|
+
deleteLockRef.current = true;
|
|
422
|
+
|
|
423
|
+
// Release lock when editor is actually stable
|
|
424
|
+
requestAnimationFrame(() => {
|
|
425
|
+
requestAnimationFrame(() => {
|
|
426
|
+
deleteLockRef.current = false;
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// 2️⃣ If we are inside a restricted anchor
|
|
432
|
+
//console.log("anchorEnd.current : ", anchorEnd.current, activeAnchorRef.current);
|
|
433
|
+
if (activeAnchorRef.current && !isNavigationKey(e) || anchorEnd.current) {
|
|
434
|
+
// Delete / Backspace = delete whole anchor
|
|
435
|
+
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
436
|
+
//editor.editorHistory.undo();
|
|
443
437
|
e.preventDefault();
|
|
444
438
|
e.stopPropagation();
|
|
439
|
+
deleteCurrentAnchor(container, activeAnchorRef.current);
|
|
440
|
+
activeAnchorRef.current = null;
|
|
441
|
+
anchorEnd.current = false;
|
|
442
|
+
deleteLockRef.current = false;
|
|
443
|
+
return;
|
|
445
444
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
445
|
+
|
|
446
|
+
// We do not want to block when we are at the end of an anchor. Input will never damage the anchor
|
|
447
|
+
//console.log("UNBLOCKING : ", anchorEnd.current, activeAnchorRef.current);
|
|
448
|
+
if (!anchorEnd.current) {
|
|
449
|
+
// 🔒 Block typing & paste
|
|
450
|
+
if (e.key.length === 1 ||
|
|
451
|
+
// printable char
|
|
452
|
+
e.ctrlKey || e.metaKey) {
|
|
453
|
+
e.preventDefault();
|
|
454
|
+
e.stopPropagation();
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
activeAnchorRef.current = null;
|
|
455
458
|
}
|
|
459
|
+
anchorEnd.current = false;
|
|
460
|
+
}
|
|
461
|
+
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
462
|
+
requestAnimationFrame(() => {
|
|
463
|
+
updateActiveAnchor(container);
|
|
464
|
+
});
|
|
456
465
|
}
|
|
457
466
|
});
|
|
458
|
-
|
|
459
|
-
if (!
|
|
460
|
-
|
|
467
|
+
const onMouseUp = e => {
|
|
468
|
+
if (!isPointInsideElement(e.clientX, e.clientY, viewerElement)) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (dropData.current) {
|
|
472
|
+
insertReadonlyAnchor(dropData.current.value, dropData.current.dropPosition);
|
|
473
|
+
dropData.current = null;
|
|
461
474
|
}
|
|
475
|
+
updateActiveAnchor(container);
|
|
476
|
+
//viewer.style.overflow = 'auto';
|
|
462
477
|
};
|
|
478
|
+
viewerElement.addEventListener('mouseup', onMouseUp);
|
|
479
|
+
return () => viewerElement.removeEventListener('mouseup', onMouseUp);
|
|
463
480
|
}
|
|
464
481
|
}, [container]);
|
|
465
482
|
_react.default.useEffect(() => {
|
|
466
483
|
if (container && json) {
|
|
467
|
-
container.documentEditor.documentChange = () => {
|
|
484
|
+
container.documentEditor.documentChange = async () => {
|
|
468
485
|
container.documentEditor.enableTrackChanges = !_Utils.default.isNull(props.trackChanges) ? props.trackChanges : true;
|
|
469
486
|
if (props.commentsOnly) {
|
|
470
487
|
container.documentEditor.editor.enforceProtection('password', 'CommentsOnly');
|
|
471
488
|
} else if (props.readOnly) {
|
|
472
489
|
container.documentEditor.isReadOnly = props.readOnly;
|
|
473
490
|
}
|
|
491
|
+
if (loading.current) {
|
|
492
|
+
let file = await saveAsBase64();
|
|
493
|
+
if (props.valueChangeHandler) {
|
|
494
|
+
props.valueChangeHandler(file);
|
|
495
|
+
}
|
|
496
|
+
loading.current = false;
|
|
497
|
+
}
|
|
498
|
+
currentText.current = extractDocumentText(container.documentEditor.editor);
|
|
474
499
|
};
|
|
475
|
-
container.documentEditor.addEventListener('contentChange', e => {
|
|
500
|
+
container.documentEditor.addEventListener('contentChange', async e => {
|
|
476
501
|
if (props.disableAcceptChanges) {
|
|
477
502
|
let acceptButtons = document.getElementsByClassName("e-de-track-accept-button");
|
|
478
503
|
for (const acceptButton of acceptButtons) {
|
|
@@ -485,16 +510,18 @@ const WordDocumentViewer = props => {
|
|
|
485
510
|
rejectButton.parentElement.removeChild(rejectButton);
|
|
486
511
|
}
|
|
487
512
|
}
|
|
488
|
-
if (
|
|
489
|
-
|
|
513
|
+
if (loading.current) {
|
|
514
|
+
let file = await saveAsBase64();
|
|
515
|
+
if (props.valueChangeHandler) {
|
|
516
|
+
props.valueChangeHandler(file);
|
|
517
|
+
}
|
|
518
|
+
loading.current = false;
|
|
490
519
|
}
|
|
520
|
+
currentText.current = extractDocumentText(container.documentEditor.editor);
|
|
491
521
|
});
|
|
492
522
|
container.documentEditor.open(json);
|
|
493
523
|
container.documentEditor.enableTrackChanges = !_Utils.default.isNull(props.trackChanges) ? props.trackChanges : true;
|
|
494
524
|
//container.documentEditor.isReadOnly = (props.readOnly || props.commentsOnly);
|
|
495
|
-
setTimeout(() => {
|
|
496
|
-
rebuildRestrictedRanges();
|
|
497
|
-
}, 0);
|
|
498
525
|
}
|
|
499
526
|
}, [json, container]);
|
|
500
527
|
const onToolbarClick = args => {
|
|
@@ -577,6 +604,7 @@ const WordDocumentViewer = props => {
|
|
|
577
604
|
restrictEditing: props.readOnly && !props.commentsOnly,
|
|
578
605
|
showPropertiesPane: false,
|
|
579
606
|
enableTrackChanges: true,
|
|
607
|
+
enableAutoFocus: false,
|
|
580
608
|
serviceUrl: DOCSVC,
|
|
581
609
|
enableToolbar: !props.readOnly || props.commentsOnly
|
|
582
610
|
}), visible && items && props.trackChanges === false && /*#__PURE__*/_react.default.createElement(_ej2ReactDocumenteditor.DocumentEditorContainerComponent, {
|
|
@@ -596,6 +624,7 @@ const WordDocumentViewer = props => {
|
|
|
596
624
|
toolbarItems: items,
|
|
597
625
|
restrictEditing: props.readOnly && !props.commentsOnly,
|
|
598
626
|
showPropertiesPane: false,
|
|
627
|
+
enableAutoFocus: false,
|
|
599
628
|
serviceUrl: DOCSVC,
|
|
600
629
|
enableToolbar: !props.readOnly || props.commentsOnly
|
|
601
630
|
}));
|
|
@@ -238,7 +238,7 @@ const Form = /*#__PURE__*/_react.default.memo(/*#__PURE__*/_react.default.forwar
|
|
|
238
238
|
function loadData(eventConfig, componentConfig) {
|
|
239
239
|
let eventData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
240
240
|
let service = !_Utils.default.isNull(componentConfig.dataService) ? componentConfig.dataService : eventConfig !== null ? eventConfig.dataService : null;
|
|
241
|
-
let componentValue = !_Utils.default.isNull(componentConfig.value) ? _ApplicationManager.default.resolveParameterConfigValue(componentConfig.value, eventData) : eventConfig
|
|
241
|
+
let componentValue = !_Utils.default.isNull(componentConfig.value) ? _ApplicationManager.default.resolveParameterConfigValue(componentConfig.value, eventData) : !_Utils.default.isNull(eventConfig) ? _ApplicationManager.default.resolveParameterConfigValue(eventConfig.value, eventData) : null;
|
|
242
242
|
if (!_Utils.default.isNull(service)) {
|
|
243
243
|
doClear();
|
|
244
244
|
if (service.type === 'rpc') {
|