slate-angular 20.2.0-next.3 → 20.2.0-next.31
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/fesm2022/slate-angular.mjs +1025 -288
- package/fesm2022/slate-angular.mjs.map +1 -1
- package/index.d.ts +64 -31
- package/package.json +1 -1
- package/styles/index.scss +1 -0
|
@@ -353,6 +353,18 @@ const CustomDOMEditor = {
|
|
|
353
353
|
}
|
|
354
354
|
};
|
|
355
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Symbols.
|
|
358
|
+
*/
|
|
359
|
+
const PLACEHOLDER_SYMBOL = Symbol('placeholder');
|
|
360
|
+
/**
|
|
361
|
+
* Weak map for associating the html element with the component.
|
|
362
|
+
*/
|
|
363
|
+
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
364
|
+
const IS_ENABLED_VIRTUAL_SCROLL = new WeakMap();
|
|
365
|
+
const EDITOR_TO_VIRTUAL_SCROLL_SELECTION = new WeakMap();
|
|
366
|
+
const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
|
|
367
|
+
|
|
356
368
|
const AngularEditor = {
|
|
357
369
|
...CustomDOMEditor,
|
|
358
370
|
/**
|
|
@@ -424,19 +436,12 @@ const AngularEditor = {
|
|
|
424
436
|
// FocusedContext is updated to the correct value
|
|
425
437
|
el.focus({ preventScroll: true });
|
|
426
438
|
}
|
|
439
|
+
},
|
|
440
|
+
isEnabledVirtualScroll(editor) {
|
|
441
|
+
return IS_ENABLED_VIRTUAL_SCROLL.get(editor);
|
|
427
442
|
}
|
|
428
443
|
};
|
|
429
444
|
|
|
430
|
-
/**
|
|
431
|
-
* Symbols.
|
|
432
|
-
*/
|
|
433
|
-
const PLACEHOLDER_SYMBOL = Symbol('placeholder');
|
|
434
|
-
/**
|
|
435
|
-
* Weak map for associating the html element with the component.
|
|
436
|
-
*/
|
|
437
|
-
const ELEMENT_TO_COMPONENT = new WeakMap();
|
|
438
|
-
const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
|
|
439
|
-
|
|
440
445
|
const IS_IOS = typeof navigator !== 'undefined' &&
|
|
441
446
|
typeof window !== 'undefined' &&
|
|
442
447
|
/iPad|iPhone|iPod/.test(navigator.userAgent) &&
|
|
@@ -470,9 +475,9 @@ const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
|
|
|
470
475
|
globalThis.InputEvent &&
|
|
471
476
|
// @ts-ignore The `getTargetRanges` property isn't recognized.
|
|
472
477
|
typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
|
|
473
|
-
const
|
|
474
|
-
const VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT = 40;
|
|
478
|
+
const VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT = 30;
|
|
475
479
|
const SLATE_DEBUG_KEY = '__SLATE_DEBUG__';
|
|
480
|
+
const SLATE_DEBUG_KEY_SCROLL_TOP = '__SLATE_DEBUG_SCROLL_TOP__';
|
|
476
481
|
|
|
477
482
|
/**
|
|
478
483
|
* Hotkey mappings for each platform.
|
|
@@ -950,6 +955,586 @@ const fallbackCopyText = async (text) => {
|
|
|
950
955
|
});
|
|
951
956
|
};
|
|
952
957
|
|
|
958
|
+
class VirtualScrollDebugOverlay {
|
|
959
|
+
static { this.storageKey = 'slate_virtual_scroll_debug_overlay_state'; }
|
|
960
|
+
static { this.minWidth = 320; }
|
|
961
|
+
static { this.minHeight = 240; }
|
|
962
|
+
static { this.defaultWidth = 410; }
|
|
963
|
+
static { this.defaultHeight = 480; }
|
|
964
|
+
static getInstance(doc) {
|
|
965
|
+
if (!this.instance) {
|
|
966
|
+
this.instance = new VirtualScrollDebugOverlay(doc);
|
|
967
|
+
}
|
|
968
|
+
this.instance.init();
|
|
969
|
+
return this.instance;
|
|
970
|
+
}
|
|
971
|
+
static log(doc, type, ...args) {
|
|
972
|
+
this.getInstance(doc).log(type, ...args);
|
|
973
|
+
}
|
|
974
|
+
// will trigger selectionchange and clear editor's selection
|
|
975
|
+
static syncScrollTop(doc, value) {
|
|
976
|
+
const instance = this.getInstance(doc);
|
|
977
|
+
instance.setScrollTopValue(value);
|
|
978
|
+
}
|
|
979
|
+
constructor(doc) {
|
|
980
|
+
this.doc = doc;
|
|
981
|
+
this.state = {
|
|
982
|
+
left: 16,
|
|
983
|
+
top: 16,
|
|
984
|
+
collapsed: false,
|
|
985
|
+
width: VirtualScrollDebugOverlay.defaultWidth,
|
|
986
|
+
height: VirtualScrollDebugOverlay.defaultHeight
|
|
987
|
+
};
|
|
988
|
+
this.originalConsoleLog = console.log.bind(console);
|
|
989
|
+
this.originalConsoleWarn = console.warn.bind(console);
|
|
990
|
+
this.dragOffsetX = 0;
|
|
991
|
+
this.dragOffsetY = 0;
|
|
992
|
+
this.isDragging = false;
|
|
993
|
+
this.isResizing = false;
|
|
994
|
+
this.resizeStartX = 0;
|
|
995
|
+
this.resizeStartY = 0;
|
|
996
|
+
this.resizeStartWidth = 0;
|
|
997
|
+
this.resizeStartHeight = 0;
|
|
998
|
+
this.dragMoved = false;
|
|
999
|
+
this.wasDragged = false;
|
|
1000
|
+
this.onDragging = (event) => {
|
|
1001
|
+
if (!this.isDragging || !this.container) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
this.dragMoved = true;
|
|
1005
|
+
const nextLeft = event.clientX - this.dragOffsetX;
|
|
1006
|
+
const nextTop = event.clientY - this.dragOffsetY;
|
|
1007
|
+
this.container.style.left = `${nextLeft}px`;
|
|
1008
|
+
this.container.style.top = `${nextTop}px`;
|
|
1009
|
+
this.container.style.right = 'auto';
|
|
1010
|
+
this.container.style.bottom = 'auto';
|
|
1011
|
+
};
|
|
1012
|
+
this.onDragEnd = () => {
|
|
1013
|
+
if (!this.isDragging) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
this.isDragging = false;
|
|
1017
|
+
this.wasDragged = this.dragMoved;
|
|
1018
|
+
this.dragMoved = false;
|
|
1019
|
+
this.doc.removeEventListener('mousemove', this.onDragging);
|
|
1020
|
+
this.doc.removeEventListener('mouseup', this.onDragEnd);
|
|
1021
|
+
if (this.container) {
|
|
1022
|
+
const rect = this.container.getBoundingClientRect();
|
|
1023
|
+
this.state.left = rect.left;
|
|
1024
|
+
this.state.top = rect.top;
|
|
1025
|
+
this.persistState();
|
|
1026
|
+
this.container.style.transition = '';
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
this.onResizing = (event) => {
|
|
1030
|
+
if (!this.isResizing || !this.container) {
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const deltaX = event.clientX - this.resizeStartX;
|
|
1034
|
+
const deltaY = event.clientY - this.resizeStartY;
|
|
1035
|
+
const nextWidth = Math.max(VirtualScrollDebugOverlay.minWidth, this.resizeStartWidth + deltaX);
|
|
1036
|
+
const nextHeight = Math.max(VirtualScrollDebugOverlay.minHeight, this.resizeStartHeight + deltaY);
|
|
1037
|
+
this.state.width = nextWidth;
|
|
1038
|
+
this.state.height = nextHeight;
|
|
1039
|
+
this.applySize();
|
|
1040
|
+
};
|
|
1041
|
+
this.onResizeEnd = () => {
|
|
1042
|
+
if (!this.isResizing) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
this.isResizing = false;
|
|
1046
|
+
this.doc.removeEventListener('mousemove', this.onResizing);
|
|
1047
|
+
this.doc.removeEventListener('mouseup', this.onResizeEnd);
|
|
1048
|
+
this.persistState();
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
init() {
|
|
1052
|
+
if (!this.container) {
|
|
1053
|
+
this.createContainer();
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
log(type, ...args) {
|
|
1057
|
+
this.init();
|
|
1058
|
+
if (type === 'warn') {
|
|
1059
|
+
this.originalConsoleWarn(...args);
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
this.originalConsoleLog(...args);
|
|
1063
|
+
}
|
|
1064
|
+
this.appendLog(type, ...args);
|
|
1065
|
+
}
|
|
1066
|
+
dispose() {
|
|
1067
|
+
this.container?.remove();
|
|
1068
|
+
this.container = undefined;
|
|
1069
|
+
this.contentWrapper = undefined;
|
|
1070
|
+
this.bubble = undefined;
|
|
1071
|
+
this.logList = undefined;
|
|
1072
|
+
this.selectorInput = undefined;
|
|
1073
|
+
this.distanceInput = undefined;
|
|
1074
|
+
this.collapseToggle = undefined;
|
|
1075
|
+
this.resizeHandle = undefined;
|
|
1076
|
+
this.doc.removeEventListener('mousemove', this.onDragging);
|
|
1077
|
+
this.doc.removeEventListener('mouseup', this.onDragEnd);
|
|
1078
|
+
this.doc.removeEventListener('mousemove', this.onResizing);
|
|
1079
|
+
this.doc.removeEventListener('mouseup', this.onResizeEnd);
|
|
1080
|
+
this.isDragging = false;
|
|
1081
|
+
this.isResizing = false;
|
|
1082
|
+
}
|
|
1083
|
+
createContainer() {
|
|
1084
|
+
this.loadState();
|
|
1085
|
+
const doc = this.doc;
|
|
1086
|
+
const container = doc.createElement('div');
|
|
1087
|
+
container.style.position = 'fixed';
|
|
1088
|
+
container.style.right = 'auto';
|
|
1089
|
+
container.style.bottom = 'auto';
|
|
1090
|
+
container.style.boxSizing = 'border-box';
|
|
1091
|
+
container.style.background = 'rgba(17, 24, 39, 0.95)';
|
|
1092
|
+
container.style.color = '#e5e7eb';
|
|
1093
|
+
container.style.fontSize = '12px';
|
|
1094
|
+
container.style.border = '1px solid #1f2937';
|
|
1095
|
+
container.style.borderRadius = '10px';
|
|
1096
|
+
container.style.fontFamily = 'Menlo, Consolas, monospace';
|
|
1097
|
+
container.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.35)';
|
|
1098
|
+
container.style.zIndex = '9999';
|
|
1099
|
+
container.style.display = 'flex';
|
|
1100
|
+
container.style.flexDirection = 'column';
|
|
1101
|
+
container.style.gap = '10px';
|
|
1102
|
+
container.style.minWidth = `${VirtualScrollDebugOverlay.minWidth}px`;
|
|
1103
|
+
container.style.minHeight = `${VirtualScrollDebugOverlay.minHeight}px`;
|
|
1104
|
+
container.style.maxHeight = '80vh';
|
|
1105
|
+
container.style.cursor = 'default';
|
|
1106
|
+
container.addEventListener('mousedown', event => {
|
|
1107
|
+
if (this.state.collapsed) {
|
|
1108
|
+
this.startDrag(event);
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
const header = doc.createElement('div');
|
|
1112
|
+
header.style.display = 'flex';
|
|
1113
|
+
header.style.alignItems = 'center';
|
|
1114
|
+
header.style.justifyContent = 'space-between';
|
|
1115
|
+
header.style.cursor = 'move';
|
|
1116
|
+
header.addEventListener('mousedown', event => {
|
|
1117
|
+
this.startDrag(event);
|
|
1118
|
+
});
|
|
1119
|
+
const title = doc.createElement('div');
|
|
1120
|
+
title.textContent = 'Virtual Scroll Debug';
|
|
1121
|
+
title.style.fontWeight = '600';
|
|
1122
|
+
title.style.letterSpacing = '0.3px';
|
|
1123
|
+
const actions = doc.createElement('div');
|
|
1124
|
+
actions.style.display = 'flex';
|
|
1125
|
+
actions.style.gap = '6px';
|
|
1126
|
+
const collapseButton = doc.createElement('button');
|
|
1127
|
+
collapseButton.type = 'button';
|
|
1128
|
+
collapseButton.textContent = '折叠';
|
|
1129
|
+
collapseButton.style.background = '#1f2937';
|
|
1130
|
+
collapseButton.style.color = '#e5e7eb';
|
|
1131
|
+
collapseButton.style.border = '1px solid #374151';
|
|
1132
|
+
collapseButton.style.borderRadius = '6px';
|
|
1133
|
+
collapseButton.style.padding = '4px 8px';
|
|
1134
|
+
collapseButton.style.cursor = 'pointer';
|
|
1135
|
+
collapseButton.addEventListener('click', () => {
|
|
1136
|
+
this.setCollapsed(!this.state.collapsed);
|
|
1137
|
+
});
|
|
1138
|
+
const clearButton = doc.createElement('button');
|
|
1139
|
+
clearButton.type = 'button';
|
|
1140
|
+
clearButton.textContent = '清除日志';
|
|
1141
|
+
clearButton.style.background = '#374151';
|
|
1142
|
+
clearButton.style.color = '#e5e7eb';
|
|
1143
|
+
clearButton.style.border = '1px solid #4b5563';
|
|
1144
|
+
clearButton.style.borderRadius = '6px';
|
|
1145
|
+
clearButton.style.padding = '4px 10px';
|
|
1146
|
+
clearButton.style.cursor = 'pointer';
|
|
1147
|
+
clearButton.addEventListener('click', () => {
|
|
1148
|
+
if (this.logList) {
|
|
1149
|
+
this.logList.innerHTML = '';
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
actions.appendChild(collapseButton);
|
|
1153
|
+
actions.appendChild(clearButton);
|
|
1154
|
+
header.appendChild(title);
|
|
1155
|
+
header.appendChild(actions);
|
|
1156
|
+
const scrollForm = doc.createElement('div');
|
|
1157
|
+
scrollForm.style.display = 'grid';
|
|
1158
|
+
scrollForm.style.gridTemplateColumns = '1fr 110px 50px';
|
|
1159
|
+
scrollForm.style.gap = '6px';
|
|
1160
|
+
scrollForm.style.alignItems = 'center';
|
|
1161
|
+
const selectorInput = doc.createElement('input');
|
|
1162
|
+
selectorInput.placeholder = '滚动容器 selector';
|
|
1163
|
+
selectorInput.style.padding = '6px 8px';
|
|
1164
|
+
selectorInput.style.borderRadius = '6px';
|
|
1165
|
+
selectorInput.style.border = '1px solid #4b5563';
|
|
1166
|
+
selectorInput.style.background = '#111827';
|
|
1167
|
+
selectorInput.style.color = '#e5e7eb';
|
|
1168
|
+
selectorInput.autocomplete = 'off';
|
|
1169
|
+
const distanceInput = doc.createElement('input');
|
|
1170
|
+
distanceInput.placeholder = '滚动距离(px)';
|
|
1171
|
+
distanceInput.type = 'number';
|
|
1172
|
+
distanceInput.style.padding = '6px 8px';
|
|
1173
|
+
distanceInput.style.borderRadius = '6px';
|
|
1174
|
+
distanceInput.style.border = '1px solid #4b5563';
|
|
1175
|
+
distanceInput.style.background = '#111827';
|
|
1176
|
+
distanceInput.style.color = '#e5e7eb';
|
|
1177
|
+
const scrollButton = doc.createElement('button');
|
|
1178
|
+
scrollButton.type = 'button';
|
|
1179
|
+
scrollButton.textContent = '滚动';
|
|
1180
|
+
scrollButton.style.background = '#10b981';
|
|
1181
|
+
scrollButton.style.color = '#0b1c15';
|
|
1182
|
+
scrollButton.style.border = 'none';
|
|
1183
|
+
scrollButton.style.borderRadius = '6px';
|
|
1184
|
+
scrollButton.style.padding = '6px 10px';
|
|
1185
|
+
scrollButton.style.cursor = 'pointer';
|
|
1186
|
+
scrollButton.addEventListener('click', () => {
|
|
1187
|
+
const selector = selectorInput.value.trim();
|
|
1188
|
+
const distanceValue = Number(distanceInput.value ?? 0);
|
|
1189
|
+
const distance = Number.isFinite(distanceValue) ? distanceValue : 0;
|
|
1190
|
+
if (!selector) {
|
|
1191
|
+
this.log('warn', '请先填写滚动容器 selector');
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
const target = doc.querySelector(selector);
|
|
1195
|
+
if (!target) {
|
|
1196
|
+
this.log('warn', `未找到滚动容器: ${selector}`);
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
if (typeof target.scrollTo === 'function') {
|
|
1200
|
+
target.scrollTo({ top: distance, behavior: 'auto' });
|
|
1201
|
+
}
|
|
1202
|
+
else if (Object.prototype.hasOwnProperty.call(target, 'scrollTop')) {
|
|
1203
|
+
target.scrollTop = distance;
|
|
1204
|
+
}
|
|
1205
|
+
else {
|
|
1206
|
+
this.log('warn', '目标元素不支持滚动:', selector);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
this.log('log', `已将 ${selector} 滚动到`, distance);
|
|
1210
|
+
});
|
|
1211
|
+
scrollForm.appendChild(selectorInput);
|
|
1212
|
+
scrollForm.appendChild(distanceInput);
|
|
1213
|
+
scrollForm.appendChild(scrollButton);
|
|
1214
|
+
const logList = doc.createElement('div');
|
|
1215
|
+
logList.style.height = '260px';
|
|
1216
|
+
logList.style.overflowY = 'auto';
|
|
1217
|
+
logList.style.background = '#0b1220';
|
|
1218
|
+
logList.style.border = '1px solid #1f2937';
|
|
1219
|
+
logList.style.borderRadius = '8px';
|
|
1220
|
+
logList.style.padding = '8px';
|
|
1221
|
+
logList.style.display = 'flex';
|
|
1222
|
+
logList.style.flexDirection = 'column';
|
|
1223
|
+
logList.style.gap = '6px';
|
|
1224
|
+
logList.style.flex = '1';
|
|
1225
|
+
logList.style.minHeight = '160px';
|
|
1226
|
+
const bubble = doc.createElement('div');
|
|
1227
|
+
bubble.textContent = 'VS';
|
|
1228
|
+
bubble.style.display = 'none';
|
|
1229
|
+
bubble.style.alignItems = 'center';
|
|
1230
|
+
bubble.style.justifyContent = 'center';
|
|
1231
|
+
bubble.style.fontWeight = '700';
|
|
1232
|
+
bubble.style.fontSize = '14px';
|
|
1233
|
+
bubble.style.letterSpacing = '0.5px';
|
|
1234
|
+
bubble.style.width = '100%';
|
|
1235
|
+
bubble.style.height = '100%';
|
|
1236
|
+
bubble.style.userSelect = 'none';
|
|
1237
|
+
bubble.addEventListener('click', () => {
|
|
1238
|
+
if (this.wasDragged) {
|
|
1239
|
+
this.wasDragged = false;
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
this.setCollapsed(false);
|
|
1243
|
+
});
|
|
1244
|
+
const contentWrapper = doc.createElement('div');
|
|
1245
|
+
contentWrapper.style.display = 'flex';
|
|
1246
|
+
contentWrapper.style.flexDirection = 'column';
|
|
1247
|
+
contentWrapper.style.gap = '10px';
|
|
1248
|
+
contentWrapper.style.width = '100%';
|
|
1249
|
+
contentWrapper.style.height = '100%';
|
|
1250
|
+
contentWrapper.appendChild(header);
|
|
1251
|
+
contentWrapper.appendChild(scrollForm);
|
|
1252
|
+
contentWrapper.appendChild(logList);
|
|
1253
|
+
container.appendChild(contentWrapper);
|
|
1254
|
+
container.appendChild(bubble);
|
|
1255
|
+
const resizeHandle = doc.createElement('div');
|
|
1256
|
+
resizeHandle.style.position = 'absolute';
|
|
1257
|
+
resizeHandle.style.right = '6px';
|
|
1258
|
+
resizeHandle.style.bottom = '6px';
|
|
1259
|
+
resizeHandle.style.width = '14px';
|
|
1260
|
+
resizeHandle.style.height = '14px';
|
|
1261
|
+
resizeHandle.style.cursor = 'nwse-resize';
|
|
1262
|
+
resizeHandle.style.borderRight = '2px solid #4b5563';
|
|
1263
|
+
resizeHandle.style.borderBottom = '2px solid #4b5563';
|
|
1264
|
+
resizeHandle.addEventListener('mousedown', event => {
|
|
1265
|
+
this.startResize(event);
|
|
1266
|
+
});
|
|
1267
|
+
container.appendChild(resizeHandle);
|
|
1268
|
+
doc.body.appendChild(container);
|
|
1269
|
+
this.container = container;
|
|
1270
|
+
this.contentWrapper = contentWrapper;
|
|
1271
|
+
this.bubble = bubble;
|
|
1272
|
+
this.logList = logList;
|
|
1273
|
+
this.selectorInput = selectorInput;
|
|
1274
|
+
this.distanceInput = distanceInput;
|
|
1275
|
+
this.collapseToggle = collapseButton;
|
|
1276
|
+
this.resizeHandle = resizeHandle;
|
|
1277
|
+
this.applyState();
|
|
1278
|
+
}
|
|
1279
|
+
startDrag(event) {
|
|
1280
|
+
if (event.button !== 0) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
if (!this.container) {
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
const rect = this.container.getBoundingClientRect();
|
|
1287
|
+
this.isDragging = true;
|
|
1288
|
+
this.wasDragged = false;
|
|
1289
|
+
this.dragMoved = false;
|
|
1290
|
+
this.dragOffsetX = event.clientX - rect.left;
|
|
1291
|
+
this.dragOffsetY = event.clientY - rect.top;
|
|
1292
|
+
this.container.style.transition = 'none';
|
|
1293
|
+
this.doc.addEventListener('mousemove', this.onDragging);
|
|
1294
|
+
this.doc.addEventListener('mouseup', this.onDragEnd);
|
|
1295
|
+
if (!this.state.collapsed) {
|
|
1296
|
+
event.preventDefault();
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
startResize(event) {
|
|
1300
|
+
if (event.button !== 0 || this.state.collapsed) {
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
if (!this.container) {
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
const rect = this.container.getBoundingClientRect();
|
|
1307
|
+
this.isResizing = true;
|
|
1308
|
+
this.resizeStartX = event.clientX;
|
|
1309
|
+
this.resizeStartY = event.clientY;
|
|
1310
|
+
this.resizeStartWidth = rect.width;
|
|
1311
|
+
this.resizeStartHeight = rect.height;
|
|
1312
|
+
this.doc.addEventListener('mousemove', this.onResizing);
|
|
1313
|
+
this.doc.addEventListener('mouseup', this.onResizeEnd);
|
|
1314
|
+
event.preventDefault();
|
|
1315
|
+
event.stopPropagation();
|
|
1316
|
+
}
|
|
1317
|
+
applyPosition() {
|
|
1318
|
+
if (!this.container) {
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
this.container.style.left = `${this.state.left}px`;
|
|
1322
|
+
this.container.style.top = `${this.state.top}px`;
|
|
1323
|
+
}
|
|
1324
|
+
applySize() {
|
|
1325
|
+
if (!this.container) {
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
const width = Math.max(VirtualScrollDebugOverlay.minWidth, this.state.width || VirtualScrollDebugOverlay.defaultWidth);
|
|
1329
|
+
const height = Math.max(VirtualScrollDebugOverlay.minHeight, this.state.height || VirtualScrollDebugOverlay.defaultHeight);
|
|
1330
|
+
this.state.width = width;
|
|
1331
|
+
this.state.height = height;
|
|
1332
|
+
this.container.style.width = `${width}px`;
|
|
1333
|
+
this.container.style.height = `${height}px`;
|
|
1334
|
+
}
|
|
1335
|
+
applyCollapsedState() {
|
|
1336
|
+
if (!this.container || !this.contentWrapper || !this.bubble || !this.collapseToggle) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
if (this.state.collapsed) {
|
|
1340
|
+
this.container.style.width = '36px';
|
|
1341
|
+
this.container.style.height = '36px';
|
|
1342
|
+
this.container.style.minWidth = '';
|
|
1343
|
+
this.container.style.minHeight = '';
|
|
1344
|
+
this.container.style.padding = '0';
|
|
1345
|
+
this.container.style.borderRadius = '50%';
|
|
1346
|
+
this.container.style.display = 'flex';
|
|
1347
|
+
this.container.style.flexDirection = 'row';
|
|
1348
|
+
this.container.style.alignItems = 'center';
|
|
1349
|
+
this.container.style.justifyContent = 'center';
|
|
1350
|
+
this.container.style.cursor = 'move';
|
|
1351
|
+
this.contentWrapper.style.display = 'none';
|
|
1352
|
+
this.bubble.style.display = 'flex';
|
|
1353
|
+
this.collapseToggle.textContent = '展开';
|
|
1354
|
+
this.resizeHandle.style.display = 'none';
|
|
1355
|
+
}
|
|
1356
|
+
else {
|
|
1357
|
+
this.applySize();
|
|
1358
|
+
this.container.style.padding = '12px';
|
|
1359
|
+
this.container.style.borderRadius = '10px';
|
|
1360
|
+
this.container.style.display = 'flex';
|
|
1361
|
+
this.container.style.flexDirection = 'column';
|
|
1362
|
+
this.container.style.gap = '10px';
|
|
1363
|
+
this.container.style.cursor = 'default';
|
|
1364
|
+
this.contentWrapper.style.display = 'flex';
|
|
1365
|
+
this.bubble.style.display = 'none';
|
|
1366
|
+
this.collapseToggle.textContent = '折叠';
|
|
1367
|
+
this.resizeHandle.style.display = 'block';
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
setCollapsed(collapsed) {
|
|
1371
|
+
this.state.collapsed = collapsed;
|
|
1372
|
+
this.applyCollapsedState();
|
|
1373
|
+
this.persistState();
|
|
1374
|
+
}
|
|
1375
|
+
applyState() {
|
|
1376
|
+
this.applyPosition();
|
|
1377
|
+
this.applyCollapsedState();
|
|
1378
|
+
}
|
|
1379
|
+
loadState() {
|
|
1380
|
+
try {
|
|
1381
|
+
const raw = this.doc.defaultView?.localStorage?.getItem(VirtualScrollDebugOverlay.storageKey);
|
|
1382
|
+
if (raw) {
|
|
1383
|
+
const parsed = JSON.parse(raw);
|
|
1384
|
+
if (typeof parsed.left === 'number') {
|
|
1385
|
+
this.state.left = parsed.left;
|
|
1386
|
+
}
|
|
1387
|
+
if (typeof parsed.top === 'number') {
|
|
1388
|
+
this.state.top = parsed.top;
|
|
1389
|
+
}
|
|
1390
|
+
if (typeof parsed.collapsed === 'boolean') {
|
|
1391
|
+
this.state.collapsed = parsed.collapsed;
|
|
1392
|
+
}
|
|
1393
|
+
if (typeof parsed.width === 'number') {
|
|
1394
|
+
this.state.width = parsed.width;
|
|
1395
|
+
}
|
|
1396
|
+
if (typeof parsed.height === 'number') {
|
|
1397
|
+
this.state.height = parsed.height;
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
catch {
|
|
1402
|
+
// ignore storage errors
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
persistState() {
|
|
1406
|
+
try {
|
|
1407
|
+
this.doc.defaultView?.localStorage?.setItem(VirtualScrollDebugOverlay.storageKey, JSON.stringify(this.state));
|
|
1408
|
+
}
|
|
1409
|
+
catch {
|
|
1410
|
+
// ignore storage errors
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
appendLog(type, ...args) {
|
|
1414
|
+
if (!this.logList) {
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
const item = this.doc.createElement('div');
|
|
1418
|
+
item.style.display = 'flex';
|
|
1419
|
+
item.style.gap = '6px';
|
|
1420
|
+
item.style.alignItems = 'flex-start';
|
|
1421
|
+
item.style.wordBreak = 'break-all';
|
|
1422
|
+
item.style.color = type === 'warn' ? '#fbbf24' : '#9ca3af';
|
|
1423
|
+
const time = this.doc.createElement('span');
|
|
1424
|
+
time.textContent = new Date().toLocaleTimeString();
|
|
1425
|
+
time.style.color = '#6b7280';
|
|
1426
|
+
time.style.flexShrink = '0';
|
|
1427
|
+
time.style.width = '72px';
|
|
1428
|
+
const text = this.doc.createElement('span');
|
|
1429
|
+
text.textContent = `[${type}] ${args.map(arg => this.formatValue(arg)).join(' ')}`;
|
|
1430
|
+
item.appendChild(time);
|
|
1431
|
+
item.appendChild(text);
|
|
1432
|
+
this.logList.appendChild(item);
|
|
1433
|
+
}
|
|
1434
|
+
formatValue(value) {
|
|
1435
|
+
if (typeof value === 'string') {
|
|
1436
|
+
return value;
|
|
1437
|
+
}
|
|
1438
|
+
try {
|
|
1439
|
+
return JSON.stringify(value);
|
|
1440
|
+
}
|
|
1441
|
+
catch (error) {
|
|
1442
|
+
return String(value);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
setScrollTopValue(value) {
|
|
1446
|
+
if (this.distanceInput) {
|
|
1447
|
+
this.distanceInput.value = String(value ?? 0);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
const isDebug = localStorage.getItem(SLATE_DEBUG_KEY) === 'true';
|
|
1453
|
+
const isDebugScrollTop = localStorage.getItem(SLATE_DEBUG_KEY_SCROLL_TOP) === 'true';
|
|
1454
|
+
const ELEMENT_KEY_TO_HEIGHTS = new WeakMap();
|
|
1455
|
+
const EDITOR_TO_BUSINESS_TOP = new WeakMap();
|
|
1456
|
+
const debugLog = (type, ...args) => {
|
|
1457
|
+
const doc = document;
|
|
1458
|
+
VirtualScrollDebugOverlay.log(doc, type, ...args);
|
|
1459
|
+
};
|
|
1460
|
+
const measureHeightByElement = (editor, element) => {
|
|
1461
|
+
const key = AngularEditor.findKey(editor, element);
|
|
1462
|
+
const view = ELEMENT_TO_COMPONENT.get(element);
|
|
1463
|
+
if (!view) {
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
const ret = view.getRealHeight();
|
|
1467
|
+
const heights = ELEMENT_KEY_TO_HEIGHTS.get(editor);
|
|
1468
|
+
heights.set(key.id, ret);
|
|
1469
|
+
return ret;
|
|
1470
|
+
};
|
|
1471
|
+
const measureHeightByIndics = (editor, indics, force = false) => {
|
|
1472
|
+
let hasChanged = false;
|
|
1473
|
+
indics.forEach((index, i) => {
|
|
1474
|
+
const element = editor.children[index];
|
|
1475
|
+
const preHeight = getRealHeightByElement(editor, element, 0);
|
|
1476
|
+
if (preHeight && !force) {
|
|
1477
|
+
if (isDebug) {
|
|
1478
|
+
const height = measureHeightByElement(editor, element);
|
|
1479
|
+
if (height !== preHeight) {
|
|
1480
|
+
debugLog('warn', 'measureHeightByElement: height not equal, index: ', index, 'preHeight: ', preHeight, 'height: ', height);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
hasChanged = true;
|
|
1486
|
+
measureHeightByElement(editor, element);
|
|
1487
|
+
});
|
|
1488
|
+
return hasChanged;
|
|
1489
|
+
};
|
|
1490
|
+
const getBusinessTop = (editor) => {
|
|
1491
|
+
return EDITOR_TO_BUSINESS_TOP.get(editor) ?? 0;
|
|
1492
|
+
};
|
|
1493
|
+
const getRealHeightByElement = (editor, element, defaultHeight = VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT) => {
|
|
1494
|
+
const isVisible = editor.isVisible(element);
|
|
1495
|
+
if (!isVisible) {
|
|
1496
|
+
return 0;
|
|
1497
|
+
}
|
|
1498
|
+
const heights = ELEMENT_KEY_TO_HEIGHTS.get(editor);
|
|
1499
|
+
const key = AngularEditor.findKey(editor, element);
|
|
1500
|
+
const height = heights?.get(key.id);
|
|
1501
|
+
if (typeof height === 'number') {
|
|
1502
|
+
return height;
|
|
1503
|
+
}
|
|
1504
|
+
if (heights?.has(key.id)) {
|
|
1505
|
+
console.error('getBlockHeight: invalid height value', key.id, height);
|
|
1506
|
+
}
|
|
1507
|
+
return defaultHeight;
|
|
1508
|
+
};
|
|
1509
|
+
const buildHeightsAndAccumulatedHeights = (editor) => {
|
|
1510
|
+
const children = (editor.children || []);
|
|
1511
|
+
const heights = new Array(children.length);
|
|
1512
|
+
const accumulatedHeights = new Array(children.length + 1);
|
|
1513
|
+
accumulatedHeights[0] = 0;
|
|
1514
|
+
for (let i = 0; i < children.length; i++) {
|
|
1515
|
+
const height = getRealHeightByElement(editor, children[i]);
|
|
1516
|
+
heights[i] = height;
|
|
1517
|
+
accumulatedHeights[i + 1] = accumulatedHeights[i] + height;
|
|
1518
|
+
}
|
|
1519
|
+
return { heights, accumulatedHeights };
|
|
1520
|
+
};
|
|
1521
|
+
const calculateVirtualTopHeight = (editor, startIndex) => {
|
|
1522
|
+
const { accumulatedHeights } = buildHeightsAndAccumulatedHeights(editor);
|
|
1523
|
+
return accumulatedHeights[startIndex] ?? 0;
|
|
1524
|
+
};
|
|
1525
|
+
const scrollToElement = (editor, element, scrollTo) => {
|
|
1526
|
+
const children = editor.children;
|
|
1527
|
+
if (!children.length) {
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
const anchorIndex = children.findIndex(item => item === element);
|
|
1531
|
+
if (anchorIndex < 0) {
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const { accumulatedHeights } = buildHeightsAndAccumulatedHeights(editor);
|
|
1535
|
+
scrollTo((accumulatedHeights[anchorIndex] ?? 0) + getBusinessTop(editor));
|
|
1536
|
+
};
|
|
1537
|
+
|
|
953
1538
|
const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
954
1539
|
let e = editor;
|
|
955
1540
|
let { apply } = e;
|
|
@@ -967,7 +1552,14 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
967
1552
|
}
|
|
968
1553
|
// Create a fake selection so that we can add a Base64-encoded copy of the
|
|
969
1554
|
// fragment to the HTML, to decode on future pastes.
|
|
970
|
-
|
|
1555
|
+
let domRange;
|
|
1556
|
+
if (AngularEditor.isEnabledVirtualScroll(e)) {
|
|
1557
|
+
const virtualScrollSelection = EDITOR_TO_VIRTUAL_SCROLL_SELECTION.get(e);
|
|
1558
|
+
if (virtualScrollSelection) {
|
|
1559
|
+
domRange = AngularEditor.toDOMRange(e, virtualScrollSelection);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
domRange = domRange ?? AngularEditor.toDOMRange(e, selection);
|
|
971
1563
|
let contents = domRange.cloneContents();
|
|
972
1564
|
let attach = contents.childNodes[0];
|
|
973
1565
|
// Make sure attach is non-empty, since empty nodes will not get copied.
|
|
@@ -1135,6 +1727,12 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
|
|
|
1135
1727
|
NODE_TO_KEY.set(node, key);
|
|
1136
1728
|
}
|
|
1137
1729
|
};
|
|
1730
|
+
e.selectAll = () => {
|
|
1731
|
+
Transforms.select(e, []);
|
|
1732
|
+
};
|
|
1733
|
+
e.isVisible = element => {
|
|
1734
|
+
return true;
|
|
1735
|
+
};
|
|
1138
1736
|
return e;
|
|
1139
1737
|
};
|
|
1140
1738
|
|
|
@@ -1795,6 +2393,7 @@ class BaseElementFlavour extends BaseFlavour {
|
|
|
1795
2393
|
if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
|
|
1796
2394
|
ELEMENT_TO_COMPONENT.delete(this.element);
|
|
1797
2395
|
}
|
|
2396
|
+
this.listRender.destroy();
|
|
1798
2397
|
this.nativeElement?.remove();
|
|
1799
2398
|
}
|
|
1800
2399
|
onContextChange() {
|
|
@@ -1835,7 +2434,7 @@ class BaseElementFlavour extends BaseFlavour {
|
|
|
1835
2434
|
const blockCard = getBlockCardByNativeElement(this.nativeElement);
|
|
1836
2435
|
const target = blockCard || this.nativeElement;
|
|
1837
2436
|
const computedStyle = getComputedStyle(target);
|
|
1838
|
-
const height = target.
|
|
2437
|
+
const height = Math.ceil(target.getBoundingClientRect().height) + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom);
|
|
1839
2438
|
if (this.isStableHeight()) {
|
|
1840
2439
|
this.stableHeight = height;
|
|
1841
2440
|
}
|
|
@@ -2191,6 +2790,9 @@ class LeavesRender {
|
|
|
2191
2790
|
});
|
|
2192
2791
|
return { decoratedLeaves, contexts };
|
|
2193
2792
|
}
|
|
2793
|
+
destroy() {
|
|
2794
|
+
this.views.forEach(view => view.destroy());
|
|
2795
|
+
}
|
|
2194
2796
|
}
|
|
2195
2797
|
function getContext$1(index, leafContexts) {
|
|
2196
2798
|
return leafContexts[index];
|
|
@@ -2233,6 +2835,7 @@ class BaseTextFlavour extends BaseFlavour {
|
|
|
2233
2835
|
NODE_TO_ELEMENT.delete(this.text);
|
|
2234
2836
|
}
|
|
2235
2837
|
ELEMENT_TO_NODE.delete(this.nativeElement);
|
|
2838
|
+
this.leavesRender.destroy();
|
|
2236
2839
|
this.nativeElement?.remove();
|
|
2237
2840
|
}
|
|
2238
2841
|
onContextChange() {
|
|
@@ -2273,14 +2876,16 @@ class ListRender {
|
|
|
2273
2876
|
this.viewContainerRef = viewContainerRef;
|
|
2274
2877
|
this.getOutletParent = getOutletParent;
|
|
2275
2878
|
this.getOutletElement = getOutletElement;
|
|
2879
|
+
this.children = [];
|
|
2276
2880
|
this.views = [];
|
|
2277
2881
|
this.blockCards = [];
|
|
2278
2882
|
this.contexts = [];
|
|
2279
2883
|
this.viewTypes = [];
|
|
2280
2884
|
this.differ = null;
|
|
2281
2885
|
this.initialized = false;
|
|
2886
|
+
this.preRenderingHTMLElement = [];
|
|
2282
2887
|
}
|
|
2283
|
-
initialize(children, parent, childrenContext) {
|
|
2888
|
+
initialize(children, parent, childrenContext, preRenderingCount = 0) {
|
|
2284
2889
|
this.initialized = true;
|
|
2285
2890
|
this.children = children;
|
|
2286
2891
|
const isRoot = parent === this.viewContext.editor;
|
|
@@ -2306,15 +2911,26 @@ class ListRender {
|
|
|
2306
2911
|
executeAfterViewInit(this.viewContext.editor);
|
|
2307
2912
|
}
|
|
2308
2913
|
}
|
|
2309
|
-
update(children, parent, childrenContext) {
|
|
2914
|
+
update(children, parent, childrenContext, preRenderingCount = 0) {
|
|
2310
2915
|
if (!this.initialized || this.children.length === 0) {
|
|
2311
|
-
this.initialize(children, parent, childrenContext);
|
|
2916
|
+
this.initialize(children, parent, childrenContext, preRenderingCount);
|
|
2312
2917
|
return;
|
|
2313
2918
|
}
|
|
2314
2919
|
if (!this.differ) {
|
|
2315
2920
|
throw new Error('Exception: Can not find differ ');
|
|
2316
2921
|
}
|
|
2317
2922
|
const outletParent = this.getOutletParent();
|
|
2923
|
+
if (this.preRenderingHTMLElement.length > 0) {
|
|
2924
|
+
const preRenderingElement = [...this.preRenderingHTMLElement];
|
|
2925
|
+
preRenderingElement.forEach((rootNodes, index) => {
|
|
2926
|
+
rootNodes.forEach(rootNode => {
|
|
2927
|
+
rootNode.style.position = '';
|
|
2928
|
+
rootNode.style.top = '';
|
|
2929
|
+
rootNode.style.width = '';
|
|
2930
|
+
});
|
|
2931
|
+
});
|
|
2932
|
+
this.preRenderingHTMLElement = [];
|
|
2933
|
+
}
|
|
2318
2934
|
const diffResult = this.differ.diff(children);
|
|
2319
2935
|
const parentPath = AngularEditor.findPath(this.viewContext.editor, parent);
|
|
2320
2936
|
const isRoot = parent === this.viewContext.editor;
|
|
@@ -2412,6 +3028,17 @@ class ListRender {
|
|
|
2412
3028
|
});
|
|
2413
3029
|
this.contexts = newContexts;
|
|
2414
3030
|
}
|
|
3031
|
+
if (preRenderingCount > 0) {
|
|
3032
|
+
for (let i = 0; i < preRenderingCount; i++) {
|
|
3033
|
+
const rootNodes = [...getRootNodes(this.views[i], this.blockCards[i])];
|
|
3034
|
+
rootNodes.forEach(rootNode => {
|
|
3035
|
+
rootNode.style.top = '-100%';
|
|
3036
|
+
rootNode.style.position = 'absolute';
|
|
3037
|
+
rootNode.style.width = '100%';
|
|
3038
|
+
});
|
|
3039
|
+
this.preRenderingHTMLElement.push(rootNodes);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2415
3042
|
}
|
|
2416
3043
|
destroy() {
|
|
2417
3044
|
this.children.forEach((element, index) => {
|
|
@@ -2422,6 +3049,7 @@ class ListRender {
|
|
|
2422
3049
|
this.blockCards[index].destroy();
|
|
2423
3050
|
}
|
|
2424
3051
|
});
|
|
3052
|
+
this.children = [];
|
|
2425
3053
|
this.views = [];
|
|
2426
3054
|
this.blockCards = [];
|
|
2427
3055
|
this.contexts = [];
|
|
@@ -2564,36 +3192,18 @@ function executeAfterViewInit(editor) {
|
|
|
2564
3192
|
clearAfterViewInitQueue(editor);
|
|
2565
3193
|
}
|
|
2566
3194
|
|
|
2567
|
-
const JUST_NOW_UPDATED_VIRTUAL_VIEW = new WeakMap();
|
|
2568
3195
|
// not correctly clipboardData on beforeinput
|
|
2569
3196
|
const forceOnDOMPaste = IS_SAFARI;
|
|
2570
|
-
const isDebug = localStorage.getItem(SLATE_DEBUG_KEY) === 'true';
|
|
2571
3197
|
class SlateEditable {
|
|
2572
3198
|
set virtualScroll(config) {
|
|
2573
|
-
this.
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
if (diff.isMissingTop) {
|
|
2582
|
-
const result = this.remeasureHeightByIndics([...diff.diffTopRenderedIndexes]);
|
|
2583
|
-
if (result) {
|
|
2584
|
-
virtualView = this.refreshVirtualView();
|
|
2585
|
-
diff = this.diffVirtualView(virtualView, 'second');
|
|
2586
|
-
if (!diff.isDiff) {
|
|
2587
|
-
return;
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
this.applyVirtualView(virtualView);
|
|
2592
|
-
if (this.listRender.initialized) {
|
|
2593
|
-
this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
|
|
2594
|
-
}
|
|
2595
|
-
this.scheduleMeasureVisibleHeights();
|
|
2596
|
-
});
|
|
3199
|
+
this.virtualScrollConfig = config;
|
|
3200
|
+
if (isDebugScrollTop) {
|
|
3201
|
+
debugLog('log', 'virtualScrollConfig scrollTop:', config.scrollTop);
|
|
3202
|
+
}
|
|
3203
|
+
IS_ENABLED_VIRTUAL_SCROLL.set(this.editor, config.enabled);
|
|
3204
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3205
|
+
this.tryUpdateVirtualViewport();
|
|
3206
|
+
}
|
|
2597
3207
|
}
|
|
2598
3208
|
get hasBeforeInputSupport() {
|
|
2599
3209
|
return HAS_BEFORE_INPUT_SUPPORT;
|
|
@@ -2638,15 +3248,16 @@ class SlateEditable {
|
|
|
2638
3248
|
return null;
|
|
2639
3249
|
}
|
|
2640
3250
|
};
|
|
2641
|
-
this.
|
|
3251
|
+
this.virtualScrollConfig = {
|
|
2642
3252
|
enabled: false,
|
|
2643
3253
|
scrollTop: 0,
|
|
2644
|
-
viewportHeight: 0
|
|
3254
|
+
viewportHeight: 0,
|
|
3255
|
+
viewportBoundingTop: 0,
|
|
3256
|
+
scrollContainer: null
|
|
2645
3257
|
};
|
|
2646
|
-
this.
|
|
2647
|
-
this.
|
|
2648
|
-
this.
|
|
2649
|
-
this.measurePending = false;
|
|
3258
|
+
this.inViewportChildren = [];
|
|
3259
|
+
this.inViewportIndics = [];
|
|
3260
|
+
this.keyHeightMap = new Map();
|
|
2650
3261
|
this.virtualScrollInitialized = false;
|
|
2651
3262
|
}
|
|
2652
3263
|
ngOnInit() {
|
|
@@ -2658,6 +3269,7 @@ class SlateEditable {
|
|
|
2658
3269
|
NODE_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
|
|
2659
3270
|
ELEMENT_TO_NODE.set(this.elementRef.nativeElement, this.editor);
|
|
2660
3271
|
IS_READ_ONLY.set(this.editor, this.readonly);
|
|
3272
|
+
ELEMENT_KEY_TO_HEIGHTS.set(this.editor, this.keyHeightMap);
|
|
2661
3273
|
EDITOR_TO_ON_CHANGE.set(this.editor, () => {
|
|
2662
3274
|
this.ngZone.run(() => {
|
|
2663
3275
|
this.onChange();
|
|
@@ -2671,7 +3283,7 @@ class SlateEditable {
|
|
|
2671
3283
|
// add browser class
|
|
2672
3284
|
let browserClass = IS_FIREFOX ? 'firefox' : IS_SAFARI ? 'safari' : '';
|
|
2673
3285
|
browserClass && this.elementRef.nativeElement.classList.add(browserClass);
|
|
2674
|
-
this.
|
|
3286
|
+
this.initializeVirtualScroll();
|
|
2675
3287
|
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletParent, this.getOutletElement);
|
|
2676
3288
|
}
|
|
2677
3289
|
ngOnChanges(simpleChanges) {
|
|
@@ -2703,16 +3315,29 @@ class SlateEditable {
|
|
|
2703
3315
|
if (value && value.length) {
|
|
2704
3316
|
this.editor.children = value;
|
|
2705
3317
|
this.initializeContext();
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
3318
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3319
|
+
const virtualView = this.calculateVirtualViewport();
|
|
3320
|
+
this.applyVirtualView(virtualView);
|
|
3321
|
+
const childrenForRender = virtualView.inViewportChildren;
|
|
3322
|
+
if (isDebug) {
|
|
3323
|
+
debugLog('log', 'writeValue calculate: ', virtualView.inViewportIndics, 'initialized: ', this.listRender.initialized);
|
|
3324
|
+
}
|
|
3325
|
+
if (!this.listRender.initialized) {
|
|
3326
|
+
this.listRender.initialize(childrenForRender, this.editor, this.context);
|
|
3327
|
+
}
|
|
3328
|
+
else {
|
|
3329
|
+
const { preRenderingCount, childrenWithPreRendering } = this.handlePreRendering();
|
|
3330
|
+
this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount);
|
|
3331
|
+
}
|
|
2711
3332
|
}
|
|
2712
3333
|
else {
|
|
2713
|
-
this.listRender.
|
|
3334
|
+
if (!this.listRender.initialized) {
|
|
3335
|
+
this.listRender.initialize(this.editor.children, this.editor, this.context);
|
|
3336
|
+
}
|
|
3337
|
+
else {
|
|
3338
|
+
this.listRender.update(this.editor.children, this.editor, this.context);
|
|
3339
|
+
}
|
|
2714
3340
|
}
|
|
2715
|
-
this.scheduleMeasureVisibleHeights();
|
|
2716
3341
|
this.cdr.markForCheck();
|
|
2717
3342
|
}
|
|
2718
3343
|
}
|
|
@@ -2743,9 +3368,46 @@ class SlateEditable {
|
|
|
2743
3368
|
this.addEventListener(event.name, () => { });
|
|
2744
3369
|
});
|
|
2745
3370
|
}
|
|
2746
|
-
|
|
3371
|
+
calculateVirtualScrollSelection(selection) {
|
|
3372
|
+
if (selection) {
|
|
3373
|
+
const isBlockCardCursor = AngularEditor.isBlockCardLeftCursor(this.editor) || AngularEditor.isBlockCardRightCursor(this.editor);
|
|
3374
|
+
const indics = this.inViewportIndics;
|
|
3375
|
+
if (indics.length > 0) {
|
|
3376
|
+
const currentVisibleRange = {
|
|
3377
|
+
anchor: Editor.start(this.editor, [indics[0]]),
|
|
3378
|
+
focus: Editor.end(this.editor, [indics[indics.length - 1]])
|
|
3379
|
+
};
|
|
3380
|
+
const [start, end] = Range.edges(selection);
|
|
3381
|
+
let forwardSelection = { anchor: start, focus: end };
|
|
3382
|
+
if (!isBlockCardCursor) {
|
|
3383
|
+
forwardSelection = { anchor: start, focus: end };
|
|
3384
|
+
}
|
|
3385
|
+
else {
|
|
3386
|
+
forwardSelection = { anchor: { path: start.path, offset: 0 }, focus: { path: end.path, offset: 0 } };
|
|
3387
|
+
}
|
|
3388
|
+
const intersectedSelection = Range.intersection(forwardSelection, currentVisibleRange);
|
|
3389
|
+
if (intersectedSelection && isBlockCardCursor) {
|
|
3390
|
+
return selection;
|
|
3391
|
+
}
|
|
3392
|
+
EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, intersectedSelection);
|
|
3393
|
+
if (!intersectedSelection || !Range.equals(intersectedSelection, forwardSelection)) {
|
|
3394
|
+
if (isDebug) {
|
|
3395
|
+
debugLog('log', `selection is not in visible range, selection: ${JSON.stringify(selection)}, currentVisibleRange: ${JSON.stringify(currentVisibleRange)}, intersectedSelection: ${JSON.stringify(intersectedSelection)}`);
|
|
3396
|
+
}
|
|
3397
|
+
return intersectedSelection;
|
|
3398
|
+
}
|
|
3399
|
+
return selection;
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
|
|
3403
|
+
return selection;
|
|
3404
|
+
}
|
|
3405
|
+
toNativeSelection(autoScroll = true) {
|
|
2747
3406
|
try {
|
|
2748
|
-
|
|
3407
|
+
let { selection } = this.editor;
|
|
3408
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3409
|
+
selection = this.calculateVirtualScrollSelection(selection);
|
|
3410
|
+
}
|
|
2749
3411
|
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
2750
3412
|
const { activeElement } = root;
|
|
2751
3413
|
const domSelection = root.getSelection();
|
|
@@ -2806,13 +3468,23 @@ class SlateEditable {
|
|
|
2806
3468
|
domSelection.removeAllRanges();
|
|
2807
3469
|
}
|
|
2808
3470
|
setTimeout(() => {
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
3471
|
+
if (this.isEnabledVirtualScroll() &&
|
|
3472
|
+
!selection &&
|
|
3473
|
+
this.editor.selection &&
|
|
3474
|
+
autoScroll &&
|
|
3475
|
+
this.virtualScrollConfig.scrollContainer) {
|
|
3476
|
+
this.virtualScrollConfig.scrollContainer.scrollTop = this.virtualScrollConfig.scrollContainer.scrollTop + 100;
|
|
3477
|
+
return;
|
|
3478
|
+
}
|
|
3479
|
+
else {
|
|
3480
|
+
// handle scrolling in setTimeout because of
|
|
3481
|
+
// dom should not have updated immediately after listRender's updating
|
|
3482
|
+
newDomRange && autoScroll && this.scrollSelectionIntoView(this.editor, newDomRange);
|
|
3483
|
+
// COMPAT: In Firefox, it's not enough to create a range, you also need
|
|
3484
|
+
// to focus the contenteditable element too. (2016/11/16)
|
|
3485
|
+
if (newDomRange && IS_FIREFOX) {
|
|
3486
|
+
el.focus();
|
|
3487
|
+
}
|
|
2816
3488
|
}
|
|
2817
3489
|
this.isUpdatingSelection = false;
|
|
2818
3490
|
});
|
|
@@ -2833,10 +3505,12 @@ class SlateEditable {
|
|
|
2833
3505
|
ngDoCheck() { }
|
|
2834
3506
|
forceRender() {
|
|
2835
3507
|
this.updateContext();
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
3508
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3509
|
+
this.updateListRenderAndRemeasureHeights();
|
|
3510
|
+
}
|
|
3511
|
+
else {
|
|
3512
|
+
this.listRender.update(this.editor.children, this.editor, this.context);
|
|
3513
|
+
}
|
|
2840
3514
|
// repair collaborative editing when Chinese input is interrupted by other users' cursors
|
|
2841
3515
|
// when the DOMElement where the selection is located is removed
|
|
2842
3516
|
// the compositionupdate and compositionend events will no longer be fired
|
|
@@ -2875,12 +3549,32 @@ class SlateEditable {
|
|
|
2875
3549
|
render() {
|
|
2876
3550
|
const changed = this.updateContext();
|
|
2877
3551
|
if (changed) {
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
3552
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3553
|
+
this.updateListRenderAndRemeasureHeights();
|
|
3554
|
+
}
|
|
3555
|
+
else {
|
|
3556
|
+
this.listRender.update(this.editor.children, this.editor, this.context);
|
|
3557
|
+
}
|
|
2882
3558
|
}
|
|
2883
3559
|
}
|
|
3560
|
+
updateListRenderAndRemeasureHeights() {
|
|
3561
|
+
const virtualView = this.calculateVirtualViewport();
|
|
3562
|
+
const oldInViewportChildren = this.inViewportChildren;
|
|
3563
|
+
this.applyVirtualView(virtualView);
|
|
3564
|
+
const { preRenderingCount, childrenWithPreRendering } = this.handlePreRendering();
|
|
3565
|
+
this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount);
|
|
3566
|
+
// 新增或者修改的才需要重算,计算出这个结果
|
|
3567
|
+
const remeasureIndics = [];
|
|
3568
|
+
this.inViewportChildren.forEach((child, index) => {
|
|
3569
|
+
if (oldInViewportChildren.indexOf(child) === -1) {
|
|
3570
|
+
remeasureIndics.push(this.inViewportIndics[index]);
|
|
3571
|
+
}
|
|
3572
|
+
});
|
|
3573
|
+
if (isDebug && remeasureIndics.length > 0) {
|
|
3574
|
+
console.log('remeasure height by indics: ', remeasureIndics);
|
|
3575
|
+
}
|
|
3576
|
+
measureHeightByIndics(this.editor, remeasureIndics, true);
|
|
3577
|
+
}
|
|
2884
3578
|
updateContext() {
|
|
2885
3579
|
const decorations = this.generateDecorations();
|
|
2886
3580
|
if (this.context.selection !== this.editor.selection ||
|
|
@@ -2941,154 +3635,271 @@ class SlateEditable {
|
|
|
2941
3635
|
decorations.push(...placeholderDecorations);
|
|
2942
3636
|
return decorations;
|
|
2943
3637
|
}
|
|
2944
|
-
|
|
2945
|
-
return !!(this.
|
|
3638
|
+
isEnabledVirtualScroll() {
|
|
3639
|
+
return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
|
|
2946
3640
|
}
|
|
2947
|
-
|
|
3641
|
+
initializeVirtualScroll() {
|
|
2948
3642
|
if (this.virtualScrollInitialized) {
|
|
2949
3643
|
return;
|
|
2950
3644
|
}
|
|
2951
|
-
if (this.
|
|
3645
|
+
if (this.isEnabledVirtualScroll()) {
|
|
2952
3646
|
this.virtualScrollInitialized = true;
|
|
2953
3647
|
this.virtualTopHeightElement = document.createElement('div');
|
|
2954
3648
|
this.virtualTopHeightElement.classList.add('virtual-top-height');
|
|
3649
|
+
this.virtualTopHeightElement.contentEditable = 'false';
|
|
2955
3650
|
this.virtualBottomHeightElement = document.createElement('div');
|
|
2956
3651
|
this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
|
|
3652
|
+
this.virtualBottomHeightElement.contentEditable = 'false';
|
|
2957
3653
|
this.virtualCenterOutlet = document.createElement('div');
|
|
2958
3654
|
this.virtualCenterOutlet.classList.add('virtual-center-outlet');
|
|
2959
3655
|
this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
|
|
2960
3656
|
this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
|
|
2961
3657
|
this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
|
|
2962
|
-
|
|
3658
|
+
let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect()?.width ?? 0;
|
|
3659
|
+
this.editorResizeObserver = new ResizeObserver(entries => {
|
|
3660
|
+
if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
|
|
3661
|
+
editorResizeObserverRectWidth = entries[0].contentRect.width;
|
|
3662
|
+
this.keyHeightMap.clear();
|
|
3663
|
+
const remeasureIndics = this.inViewportIndics;
|
|
3664
|
+
measureHeightByIndics(this.editor, remeasureIndics, true);
|
|
3665
|
+
}
|
|
3666
|
+
});
|
|
3667
|
+
this.editorResizeObserver.observe(this.elementRef.nativeElement);
|
|
2963
3668
|
}
|
|
2964
3669
|
}
|
|
2965
|
-
|
|
3670
|
+
setVirtualSpaceHeight(topHeight, bottomHeight) {
|
|
2966
3671
|
if (!this.virtualScrollInitialized) {
|
|
2967
3672
|
return;
|
|
2968
3673
|
}
|
|
2969
3674
|
this.virtualTopHeightElement.style.height = `${topHeight}px`;
|
|
2970
|
-
|
|
3675
|
+
if (bottomHeight !== undefined) {
|
|
3676
|
+
this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
|
|
3677
|
+
}
|
|
2971
3678
|
}
|
|
2972
|
-
|
|
3679
|
+
getActualVirtualTopHeight() {
|
|
3680
|
+
if (!this.virtualScrollInitialized) {
|
|
3681
|
+
return 0;
|
|
3682
|
+
}
|
|
3683
|
+
return parseFloat(this.virtualTopHeightElement.style.height.replace('px', ''));
|
|
3684
|
+
}
|
|
3685
|
+
handlePreRendering() {
|
|
3686
|
+
let preRenderingCount = 1;
|
|
3687
|
+
const childrenWithPreRendering = [...this.inViewportChildren];
|
|
3688
|
+
if (this.inViewportIndics[0] !== 0) {
|
|
3689
|
+
childrenWithPreRendering.unshift(this.editor.children[this.inViewportIndics[0] - 1]);
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
preRenderingCount = 0;
|
|
3693
|
+
}
|
|
3694
|
+
const lastIndex = this.inViewportIndics[this.inViewportIndics.length - 1];
|
|
3695
|
+
if (lastIndex !== this.editor.children.length - 1) {
|
|
3696
|
+
childrenWithPreRendering.push(this.editor.children[lastIndex + 1]);
|
|
3697
|
+
}
|
|
3698
|
+
return { preRenderingCount, childrenWithPreRendering };
|
|
3699
|
+
}
|
|
3700
|
+
tryUpdateVirtualViewport() {
|
|
3701
|
+
if (isDebug) {
|
|
3702
|
+
debugLog('log', 'tryUpdateVirtualViewport');
|
|
3703
|
+
}
|
|
3704
|
+
if (this.inViewportIndics.length > 0) {
|
|
3705
|
+
const topHeight = this.getActualVirtualTopHeight();
|
|
3706
|
+
const refreshVirtualTopHeight = calculateVirtualTopHeight(this.editor, this.inViewportIndics[0]);
|
|
3707
|
+
if (topHeight !== refreshVirtualTopHeight) {
|
|
3708
|
+
if (isDebug) {
|
|
3709
|
+
debugLog('log', 'update top height since dirty state(正数减去高度,负数代表增加高度): ', topHeight - refreshVirtualTopHeight);
|
|
3710
|
+
}
|
|
3711
|
+
this.setVirtualSpaceHeight(refreshVirtualTopHeight);
|
|
3712
|
+
return;
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
this.tryUpdateVirtualViewportAnimId && cancelAnimationFrame(this.tryUpdateVirtualViewportAnimId);
|
|
3716
|
+
this.tryUpdateVirtualViewportAnimId = requestAnimationFrame(() => {
|
|
3717
|
+
if (isDebug) {
|
|
3718
|
+
debugLog('log', 'tryUpdateVirtualViewport Anim start');
|
|
3719
|
+
}
|
|
3720
|
+
let virtualView = this.calculateVirtualViewport();
|
|
3721
|
+
let diff = this.diffVirtualViewport(virtualView);
|
|
3722
|
+
if (diff.isDifferent && diff.needRemoveOnTop) {
|
|
3723
|
+
const remeasureIndics = diff.changedIndexesOfTop;
|
|
3724
|
+
const changed = measureHeightByIndics(this.editor, remeasureIndics);
|
|
3725
|
+
if (changed) {
|
|
3726
|
+
virtualView = this.calculateVirtualViewport();
|
|
3727
|
+
diff = this.diffVirtualViewport(virtualView, 'second');
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
if (diff.isDifferent) {
|
|
3731
|
+
this.applyVirtualView(virtualView);
|
|
3732
|
+
if (this.listRender.initialized) {
|
|
3733
|
+
const { preRenderingCount, childrenWithPreRendering } = this.handlePreRendering();
|
|
3734
|
+
this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount);
|
|
3735
|
+
if (diff.needAddOnTop) {
|
|
3736
|
+
const remeasureAddedIndics = diff.changedIndexesOfTop;
|
|
3737
|
+
if (isDebug) {
|
|
3738
|
+
debugLog('log', 'needAddOnTop to remeasure heights: ', remeasureAddedIndics);
|
|
3739
|
+
}
|
|
3740
|
+
const startIndexBeforeAdd = diff.changedIndexesOfTop[diff.changedIndexesOfTop.length - 1] + 1;
|
|
3741
|
+
const topHeightBeforeAdd = virtualView.accumulatedHeights[startIndexBeforeAdd];
|
|
3742
|
+
const changed = measureHeightByIndics(this.editor, remeasureAddedIndics);
|
|
3743
|
+
if (changed) {
|
|
3744
|
+
const newHeights = buildHeightsAndAccumulatedHeights(this.editor);
|
|
3745
|
+
const actualTopHeightAfterAdd = newHeights.accumulatedHeights[startIndexBeforeAdd];
|
|
3746
|
+
const newTopHeight = virtualView.top - (actualTopHeightAfterAdd - topHeightBeforeAdd);
|
|
3747
|
+
this.setVirtualSpaceHeight(newTopHeight);
|
|
3748
|
+
if (isDebug) {
|
|
3749
|
+
debugLog('log', `update top height since will add element in top(正数减去高度,负数代表增加高度): ${actualTopHeightAfterAdd - topHeightBeforeAdd}`);
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
if (!AngularEditor.isReadOnly(this.editor) && this.editor.selection) {
|
|
3754
|
+
this.toNativeSelection(false);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
if (isDebug) {
|
|
3759
|
+
debugLog('log', 'tryUpdateVirtualViewport Anim end');
|
|
3760
|
+
}
|
|
3761
|
+
});
|
|
3762
|
+
}
|
|
3763
|
+
calculateVirtualViewport() {
|
|
2973
3764
|
const children = (this.editor.children || []);
|
|
2974
|
-
if (!children.length || !this.
|
|
3765
|
+
if (!children.length || !this.isEnabledVirtualScroll()) {
|
|
2975
3766
|
return {
|
|
2976
|
-
|
|
2977
|
-
|
|
3767
|
+
inViewportChildren: children,
|
|
3768
|
+
inViewportIndics: [],
|
|
2978
3769
|
top: 0,
|
|
2979
3770
|
bottom: 0,
|
|
2980
3771
|
heights: []
|
|
2981
3772
|
};
|
|
2982
3773
|
}
|
|
2983
|
-
const scrollTop = this.
|
|
2984
|
-
const viewportHeight = this.
|
|
3774
|
+
const scrollTop = this.virtualScrollConfig.scrollTop;
|
|
3775
|
+
const viewportHeight = this.virtualScrollConfig.viewportHeight ?? 0;
|
|
2985
3776
|
if (!viewportHeight) {
|
|
2986
|
-
// 已经启用虚拟滚动,但可视区域高度还未获取到,先置空不渲染
|
|
2987
3777
|
return {
|
|
2988
|
-
|
|
2989
|
-
|
|
3778
|
+
inViewportChildren: [],
|
|
3779
|
+
inViewportIndics: [],
|
|
2990
3780
|
top: 0,
|
|
2991
3781
|
bottom: 0,
|
|
2992
3782
|
heights: []
|
|
2993
3783
|
};
|
|
2994
3784
|
}
|
|
2995
|
-
const
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3785
|
+
const elementLength = children.length;
|
|
3786
|
+
if (!EDITOR_TO_BUSINESS_TOP.has(this.editor)) {
|
|
3787
|
+
EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
|
|
3788
|
+
setTimeout(() => {
|
|
3789
|
+
const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
|
|
3790
|
+
const businessTop = Math.ceil(virtualTopBoundingTop) +
|
|
3791
|
+
Math.ceil(this.virtualScrollConfig.scrollTop) -
|
|
3792
|
+
Math.floor(this.virtualScrollConfig.viewportBoundingTop);
|
|
3793
|
+
EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
|
|
3794
|
+
if (isDebug) {
|
|
3795
|
+
debugLog('log', 'businessTop', businessTop);
|
|
3796
|
+
}
|
|
3797
|
+
}, 100);
|
|
3798
|
+
}
|
|
3799
|
+
const adjustedScrollTop = Math.max(0, scrollTop - getBusinessTop(this.editor));
|
|
3800
|
+
const { heights, accumulatedHeights } = buildHeightsAndAccumulatedHeights(this.editor);
|
|
3801
|
+
const totalHeight = accumulatedHeights[elementLength];
|
|
3802
|
+
const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
|
|
3803
|
+
const limitedScrollTop = Math.min(adjustedScrollTop, maxScrollTop);
|
|
3804
|
+
const viewBottom = limitedScrollTop + viewportHeight;
|
|
3805
|
+
let accumulatedOffset = 0;
|
|
3806
|
+
let inViewportStartIndex = -1;
|
|
3008
3807
|
const visible = [];
|
|
3009
|
-
const
|
|
3010
|
-
let
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3808
|
+
const inViewportIndics = [];
|
|
3809
|
+
for (let i = 0; i < elementLength && accumulatedOffset < viewBottom; i++) {
|
|
3810
|
+
const currentHeight = heights[i];
|
|
3811
|
+
const nextOffset = accumulatedOffset + currentHeight;
|
|
3812
|
+
// 可视区域有交集,加入渲染
|
|
3813
|
+
if (nextOffset > limitedScrollTop && accumulatedOffset < viewBottom) {
|
|
3814
|
+
if (inViewportStartIndex === -1)
|
|
3815
|
+
inViewportStartIndex = i; // 第一个相交起始位置
|
|
3816
|
+
visible.push(children[i]);
|
|
3817
|
+
inViewportIndics.push(i);
|
|
3818
|
+
}
|
|
3819
|
+
accumulatedOffset = nextOffset;
|
|
3820
|
+
}
|
|
3821
|
+
if (inViewportStartIndex === -1 && elementLength) {
|
|
3822
|
+
inViewportStartIndex = elementLength - 1;
|
|
3823
|
+
visible.push(children[inViewportStartIndex]);
|
|
3824
|
+
inViewportIndics.push(inViewportStartIndex);
|
|
3825
|
+
}
|
|
3826
|
+
const inViewportEndIndex = inViewportStartIndex === -1 ? elementLength - 1 : (inViewportIndics[inViewportIndics.length - 1] ?? inViewportStartIndex);
|
|
3827
|
+
const top = inViewportStartIndex === -1 ? 0 : accumulatedHeights[inViewportStartIndex];
|
|
3828
|
+
const bottom = totalHeight - accumulatedHeights[inViewportEndIndex + 1];
|
|
3022
3829
|
return {
|
|
3023
|
-
|
|
3024
|
-
|
|
3830
|
+
inViewportChildren: visible.length ? visible : children,
|
|
3831
|
+
inViewportIndics,
|
|
3025
3832
|
top,
|
|
3026
3833
|
bottom,
|
|
3027
|
-
heights
|
|
3834
|
+
heights,
|
|
3835
|
+
accumulatedHeights
|
|
3028
3836
|
};
|
|
3029
3837
|
}
|
|
3030
3838
|
applyVirtualView(virtualView) {
|
|
3031
|
-
this.
|
|
3032
|
-
this.
|
|
3033
|
-
this.
|
|
3839
|
+
this.inViewportChildren = virtualView.inViewportChildren;
|
|
3840
|
+
this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
|
|
3841
|
+
this.inViewportIndics = virtualView.inViewportIndics;
|
|
3034
3842
|
}
|
|
3035
|
-
|
|
3036
|
-
if (!this.
|
|
3843
|
+
diffVirtualViewport(virtualView, stage = 'first') {
|
|
3844
|
+
if (!this.inViewportChildren.length) {
|
|
3845
|
+
if (isDebug) {
|
|
3846
|
+
debugLog('log', 'diffVirtualViewport', stage, 'empty inViewportChildren', virtualView.inViewportIndics);
|
|
3847
|
+
}
|
|
3037
3848
|
return {
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3849
|
+
isDifferent: true,
|
|
3850
|
+
changedIndexesOfTop: [],
|
|
3851
|
+
changedIndexesOfBottom: []
|
|
3041
3852
|
};
|
|
3042
3853
|
}
|
|
3043
|
-
const
|
|
3044
|
-
const
|
|
3045
|
-
const firstNewIndex =
|
|
3046
|
-
const lastNewIndex =
|
|
3047
|
-
const firstOldIndex =
|
|
3048
|
-
const lastOldIndex =
|
|
3854
|
+
const oldIndexesInViewport = [...this.inViewportIndics];
|
|
3855
|
+
const newIndexesInViewport = [...virtualView.inViewportIndics];
|
|
3856
|
+
const firstNewIndex = newIndexesInViewport[0];
|
|
3857
|
+
const lastNewIndex = newIndexesInViewport[newIndexesInViewport.length - 1];
|
|
3858
|
+
const firstOldIndex = oldIndexesInViewport[0];
|
|
3859
|
+
const lastOldIndex = oldIndexesInViewport[oldIndexesInViewport.length - 1];
|
|
3049
3860
|
if (firstNewIndex !== firstOldIndex || lastNewIndex !== lastOldIndex) {
|
|
3050
|
-
const
|
|
3051
|
-
const
|
|
3052
|
-
const
|
|
3053
|
-
const
|
|
3054
|
-
const
|
|
3055
|
-
const
|
|
3056
|
-
if (
|
|
3861
|
+
const changedIndexesOfTop = [];
|
|
3862
|
+
const changedIndexesOfBottom = [];
|
|
3863
|
+
const needRemoveOnTop = firstNewIndex !== firstOldIndex && firstNewIndex > firstOldIndex;
|
|
3864
|
+
const needAddOnTop = firstNewIndex !== firstOldIndex && firstNewIndex < firstOldIndex;
|
|
3865
|
+
const needRemoveOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex > lastNewIndex;
|
|
3866
|
+
const needAddOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex < lastNewIndex;
|
|
3867
|
+
if (needRemoveOnTop || needAddOnBottom) {
|
|
3057
3868
|
// 向下
|
|
3058
|
-
for (let index = 0; index <
|
|
3059
|
-
const element =
|
|
3060
|
-
if (!
|
|
3061
|
-
|
|
3869
|
+
for (let index = 0; index < oldIndexesInViewport.length; index++) {
|
|
3870
|
+
const element = oldIndexesInViewport[index];
|
|
3871
|
+
if (!newIndexesInViewport.includes(element)) {
|
|
3872
|
+
changedIndexesOfTop.push(element);
|
|
3062
3873
|
}
|
|
3063
3874
|
else {
|
|
3064
3875
|
break;
|
|
3065
3876
|
}
|
|
3066
3877
|
}
|
|
3067
|
-
for (let index =
|
|
3068
|
-
const element =
|
|
3069
|
-
if (!
|
|
3070
|
-
|
|
3878
|
+
for (let index = newIndexesInViewport.length - 1; index >= 0; index--) {
|
|
3879
|
+
const element = newIndexesInViewport[index];
|
|
3880
|
+
if (!oldIndexesInViewport.includes(element)) {
|
|
3881
|
+
changedIndexesOfBottom.push(element);
|
|
3071
3882
|
}
|
|
3072
3883
|
else {
|
|
3073
3884
|
break;
|
|
3074
3885
|
}
|
|
3075
3886
|
}
|
|
3076
3887
|
}
|
|
3077
|
-
else if (
|
|
3888
|
+
else if (needAddOnTop || needRemoveOnBottom) {
|
|
3078
3889
|
// 向上
|
|
3079
|
-
for (let index = 0; index <
|
|
3080
|
-
const element =
|
|
3081
|
-
if (!
|
|
3082
|
-
|
|
3890
|
+
for (let index = 0; index < newIndexesInViewport.length; index++) {
|
|
3891
|
+
const element = newIndexesInViewport[index];
|
|
3892
|
+
if (!oldIndexesInViewport.includes(element)) {
|
|
3893
|
+
changedIndexesOfTop.push(element);
|
|
3083
3894
|
}
|
|
3084
3895
|
else {
|
|
3085
3896
|
break;
|
|
3086
3897
|
}
|
|
3087
3898
|
}
|
|
3088
|
-
for (let index =
|
|
3089
|
-
const element =
|
|
3090
|
-
if (!
|
|
3091
|
-
|
|
3899
|
+
for (let index = oldIndexesInViewport.length - 1; index >= 0; index--) {
|
|
3900
|
+
const element = oldIndexesInViewport[index];
|
|
3901
|
+
if (!newIndexesInViewport.includes(element)) {
|
|
3902
|
+
changedIndexesOfBottom.push(element);
|
|
3092
3903
|
}
|
|
3093
3904
|
else {
|
|
3094
3905
|
break;
|
|
@@ -3096,139 +3907,35 @@ class SlateEditable {
|
|
|
3096
3907
|
}
|
|
3097
3908
|
}
|
|
3098
3909
|
if (isDebug) {
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
const needTop = virtualView.heights.slice(0,
|
|
3910
|
+
debugLog('log', `====== diffVirtualViewport stage: ${stage} ======`);
|
|
3911
|
+
debugLog('log', 'oldIndexesInViewport:', oldIndexesInViewport);
|
|
3912
|
+
debugLog('log', 'newIndexesInViewport:', newIndexesInViewport);
|
|
3913
|
+
debugLog('log', 'changedIndexesOfTop:', needRemoveOnTop ? '-' : needAddOnTop ? '+' : '-', changedIndexesOfTop, changedIndexesOfTop.map(index => getRealHeightByElement(this.editor, this.editor.children[index], 0)));
|
|
3914
|
+
debugLog('log', 'changedIndexesOfBottom:', needAddOnBottom ? '+' : needRemoveOnBottom ? '-' : '+', changedIndexesOfBottom, changedIndexesOfBottom.map(index => getRealHeightByElement(this.editor, this.editor.children[index], 0)));
|
|
3915
|
+
const needTop = virtualView.heights.slice(0, newIndexesInViewport[0]).reduce((acc, height) => acc + height, 0);
|
|
3105
3916
|
const needBottom = virtualView.heights
|
|
3106
|
-
.slice(
|
|
3917
|
+
.slice(newIndexesInViewport[newIndexesInViewport.length - 1] + 1)
|
|
3107
3918
|
.reduce((acc, height) => acc + height, 0);
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3919
|
+
debugLog('log', needTop - parseFloat(this.virtualTopHeightElement.style.height), 'newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
|
|
3920
|
+
debugLog('log', 'newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
|
|
3921
|
+
debugLog('warn', '=========== Dividing line ===========');
|
|
3111
3922
|
}
|
|
3112
3923
|
return {
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3924
|
+
isDifferent: true,
|
|
3925
|
+
needRemoveOnTop,
|
|
3926
|
+
needAddOnTop,
|
|
3927
|
+
needRemoveOnBottom,
|
|
3928
|
+
needAddOnBottom,
|
|
3929
|
+
changedIndexesOfTop,
|
|
3930
|
+
changedIndexesOfBottom
|
|
3120
3931
|
};
|
|
3121
3932
|
}
|
|
3122
3933
|
return {
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3934
|
+
isDifferent: false,
|
|
3935
|
+
changedIndexesOfTop: [],
|
|
3936
|
+
changedIndexesOfBottom: []
|
|
3126
3937
|
};
|
|
3127
3938
|
}
|
|
3128
|
-
getBlockHeight(index, defaultHeight = VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT) {
|
|
3129
|
-
const node = this.editor.children[index];
|
|
3130
|
-
if (!node) {
|
|
3131
|
-
return defaultHeight;
|
|
3132
|
-
}
|
|
3133
|
-
const key = AngularEditor.findKey(this.editor, node);
|
|
3134
|
-
return this.measuredHeights.get(key.id) ?? defaultHeight;
|
|
3135
|
-
}
|
|
3136
|
-
buildAccumulatedHeight(heights) {
|
|
3137
|
-
const accumulatedHeights = new Array(heights.length + 1).fill(0);
|
|
3138
|
-
for (let i = 0; i < heights.length; i++) {
|
|
3139
|
-
// 存储前 i 个的累计高度
|
|
3140
|
-
accumulatedHeights[i + 1] = accumulatedHeights[i] + heights[i];
|
|
3141
|
-
}
|
|
3142
|
-
return accumulatedHeights;
|
|
3143
|
-
}
|
|
3144
|
-
getBufferBelowHeight(viewportHeight, visibleStart, bufferCount) {
|
|
3145
|
-
let blockHeight = 0;
|
|
3146
|
-
let start = visibleStart;
|
|
3147
|
-
// 循环累计高度超出视图高度代表找到向下缓冲区的起始位置
|
|
3148
|
-
while (blockHeight < viewportHeight) {
|
|
3149
|
-
blockHeight += this.getBlockHeight(start);
|
|
3150
|
-
start++;
|
|
3151
|
-
}
|
|
3152
|
-
let bufferHeight = 0;
|
|
3153
|
-
for (let i = start; i < start + bufferCount; i++) {
|
|
3154
|
-
bufferHeight += this.getBlockHeight(i);
|
|
3155
|
-
}
|
|
3156
|
-
return bufferHeight;
|
|
3157
|
-
}
|
|
3158
|
-
scheduleMeasureVisibleHeights() {
|
|
3159
|
-
if (!this.shouldUseVirtual()) {
|
|
3160
|
-
return;
|
|
3161
|
-
}
|
|
3162
|
-
this.measureVisibleHeightsAnimId && cancelAnimationFrame(this.measureVisibleHeightsAnimId);
|
|
3163
|
-
this.measureVisibleHeightsAnimId = requestAnimationFrame(() => {
|
|
3164
|
-
this.measureVisibleHeights();
|
|
3165
|
-
});
|
|
3166
|
-
}
|
|
3167
|
-
measureVisibleHeights() {
|
|
3168
|
-
const children = (this.editor.children || []);
|
|
3169
|
-
this.virtualVisibleIndexes.forEach(index => {
|
|
3170
|
-
const node = children[index];
|
|
3171
|
-
if (!node) {
|
|
3172
|
-
return;
|
|
3173
|
-
}
|
|
3174
|
-
const key = AngularEditor.findKey(this.editor, node);
|
|
3175
|
-
// 跳过已测过的块
|
|
3176
|
-
if (this.measuredHeights.has(key.id)) {
|
|
3177
|
-
return;
|
|
3178
|
-
}
|
|
3179
|
-
const view = ELEMENT_TO_COMPONENT.get(node);
|
|
3180
|
-
if (!view) {
|
|
3181
|
-
return;
|
|
3182
|
-
}
|
|
3183
|
-
const ret = view.getRealHeight();
|
|
3184
|
-
if (ret instanceof Promise) {
|
|
3185
|
-
ret.then(height => {
|
|
3186
|
-
this.measuredHeights.set(key.id, height);
|
|
3187
|
-
});
|
|
3188
|
-
}
|
|
3189
|
-
else {
|
|
3190
|
-
this.measuredHeights.set(key.id, ret);
|
|
3191
|
-
}
|
|
3192
|
-
});
|
|
3193
|
-
}
|
|
3194
|
-
remeasureHeightByIndics(indics) {
|
|
3195
|
-
const children = (this.editor.children || []);
|
|
3196
|
-
let isHeightChanged = false;
|
|
3197
|
-
indics.forEach(index => {
|
|
3198
|
-
const node = children[index];
|
|
3199
|
-
if (!node) {
|
|
3200
|
-
return;
|
|
3201
|
-
}
|
|
3202
|
-
const key = AngularEditor.findKey(this.editor, node);
|
|
3203
|
-
const view = ELEMENT_TO_COMPONENT.get(node);
|
|
3204
|
-
if (!view) {
|
|
3205
|
-
return;
|
|
3206
|
-
}
|
|
3207
|
-
const prevHeight = this.measuredHeights.get(key.id);
|
|
3208
|
-
const ret = view.getRealHeight();
|
|
3209
|
-
if (ret instanceof Promise) {
|
|
3210
|
-
ret.then(height => {
|
|
3211
|
-
if (height !== prevHeight) {
|
|
3212
|
-
this.measuredHeights.set(key.id, height);
|
|
3213
|
-
isHeightChanged = true;
|
|
3214
|
-
if (isDebug) {
|
|
3215
|
-
console.log(`remeasureHeightByIndics, index: ${index} prevHeight: ${prevHeight} newHeight: ${height}`);
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3218
|
-
});
|
|
3219
|
-
}
|
|
3220
|
-
else {
|
|
3221
|
-
if (ret !== prevHeight) {
|
|
3222
|
-
this.measuredHeights.set(key.id, ret);
|
|
3223
|
-
isHeightChanged = true;
|
|
3224
|
-
if (isDebug) {
|
|
3225
|
-
console.log(`remeasureHeightByIndics, index: ${index} prevHeight: ${prevHeight} newHeight: ${ret}`);
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
}
|
|
3229
|
-
});
|
|
3230
|
-
return isHeightChanged;
|
|
3231
|
-
}
|
|
3232
3939
|
//#region event proxy
|
|
3233
3940
|
addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
|
|
3234
3941
|
this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
|
|
@@ -3269,7 +3976,7 @@ class SlateEditable {
|
|
|
3269
3976
|
if (this.editor.selection && Range.equals(range, this.editor.selection) && !hasStringTarget(domSelection)) {
|
|
3270
3977
|
if (!isTargetInsideVoid(this.editor, activeElement)) {
|
|
3271
3978
|
// force adjust DOMSelection
|
|
3272
|
-
this.toNativeSelection();
|
|
3979
|
+
this.toNativeSelection(false);
|
|
3273
3980
|
}
|
|
3274
3981
|
}
|
|
3275
3982
|
else {
|
|
@@ -3753,6 +4460,11 @@ class SlateEditable {
|
|
|
3753
4460
|
Transforms.move(editor, { unit: 'word', reverse: isRTL });
|
|
3754
4461
|
return;
|
|
3755
4462
|
}
|
|
4463
|
+
if (isKeyHotkey('mod+a', event)) {
|
|
4464
|
+
this.editor.selectAll();
|
|
4465
|
+
event.preventDefault();
|
|
4466
|
+
return;
|
|
4467
|
+
}
|
|
3756
4468
|
// COMPAT: Certain browsers don't support the `beforeinput` event, so we
|
|
3757
4469
|
// fall back to guessing at the input intention for hotkeys.
|
|
3758
4470
|
// COMPAT: In iOS, some of these hotkeys are handled in the
|
|
@@ -3920,6 +4632,7 @@ class SlateEditable {
|
|
|
3920
4632
|
}
|
|
3921
4633
|
//#endregion
|
|
3922
4634
|
ngOnDestroy() {
|
|
4635
|
+
this.editorResizeObserver?.disconnect();
|
|
3923
4636
|
NODE_TO_ELEMENT.delete(this.editor);
|
|
3924
4637
|
this.manualListeners.forEach(manualListener => {
|
|
3925
4638
|
manualListener();
|
|
@@ -4108,16 +4821,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
4108
4821
|
}]
|
|
4109
4822
|
}], ctorParameters: () => [{ type: i0.ElementRef }] });
|
|
4110
4823
|
|
|
4824
|
+
class SlateString {
|
|
4825
|
+
ngOnInit() { }
|
|
4826
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateString, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4827
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.12", type: SlateString, isStandalone: true, selector: "span[slateString]", inputs: { context: "context", viewContext: "viewContext" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4828
|
+
}
|
|
4829
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateString, decorators: [{
|
|
4830
|
+
type: Component,
|
|
4831
|
+
args: [{
|
|
4832
|
+
selector: 'span[slateString]',
|
|
4833
|
+
template: '',
|
|
4834
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4835
|
+
standalone: true
|
|
4836
|
+
}]
|
|
4837
|
+
}], propDecorators: { context: [{
|
|
4838
|
+
type: Input
|
|
4839
|
+
}], viewContext: [{
|
|
4840
|
+
type: Input
|
|
4841
|
+
}] } });
|
|
4842
|
+
|
|
4111
4843
|
class SlateModule {
|
|
4112
4844
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
4113
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", ngImport: i0, type: SlateModule, imports: [CommonModule, SlateEditable, SlateChildrenOutlet], exports: [SlateEditable, SlateChildrenOutlet] }); }
|
|
4845
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", ngImport: i0, type: SlateModule, imports: [CommonModule, SlateEditable, SlateChildrenOutlet, SlateString], exports: [SlateEditable, SlateChildrenOutlet, SlateString] }); }
|
|
4114
4846
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateModule, imports: [CommonModule] }); }
|
|
4115
4847
|
}
|
|
4116
4848
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateModule, decorators: [{
|
|
4117
4849
|
type: NgModule,
|
|
4118
4850
|
args: [{
|
|
4119
|
-
imports: [CommonModule, SlateEditable, SlateChildrenOutlet],
|
|
4120
|
-
exports: [SlateEditable, SlateChildrenOutlet],
|
|
4851
|
+
imports: [CommonModule, SlateEditable, SlateChildrenOutlet, SlateString],
|
|
4852
|
+
exports: [SlateEditable, SlateChildrenOutlet, SlateString],
|
|
4121
4853
|
providers: []
|
|
4122
4854
|
}]
|
|
4123
4855
|
}] });
|
|
@@ -4233,6 +4965,7 @@ class BaseElementComponent extends BaseComponent {
|
|
|
4233
4965
|
if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
|
|
4234
4966
|
ELEMENT_TO_COMPONENT.delete(this.element);
|
|
4235
4967
|
}
|
|
4968
|
+
this.listRender.destroy();
|
|
4236
4969
|
}
|
|
4237
4970
|
onContextChange() {
|
|
4238
4971
|
this.childrenContext = this.getChildrenContext();
|
|
@@ -4271,7 +5004,7 @@ class BaseElementComponent extends BaseComponent {
|
|
|
4271
5004
|
const blockCard = getBlockCardByNativeElement(this.nativeElement);
|
|
4272
5005
|
const target = blockCard || this.nativeElement;
|
|
4273
5006
|
const computedStyle = getComputedStyle(target);
|
|
4274
|
-
const height = target.
|
|
5007
|
+
const height = Math.ceil(target.getBoundingClientRect().height) + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom);
|
|
4275
5008
|
if (this.isStableHeight()) {
|
|
4276
5009
|
this.stableHeight = height;
|
|
4277
5010
|
}
|
|
@@ -4320,6 +5053,7 @@ class BaseTextComponent extends BaseComponent {
|
|
|
4320
5053
|
NODE_TO_ELEMENT.delete(this.text);
|
|
4321
5054
|
}
|
|
4322
5055
|
ELEMENT_TO_NODE.delete(this.nativeElement);
|
|
5056
|
+
this.leavesRender.destroy();
|
|
4323
5057
|
}
|
|
4324
5058
|
onContextChange() {
|
|
4325
5059
|
this.updateWeakMap();
|
|
@@ -4345,6 +5079,9 @@ class BaseLeafComponent extends BaseComponent {
|
|
|
4345
5079
|
super(...arguments);
|
|
4346
5080
|
this.stringRender = null;
|
|
4347
5081
|
this.isSlateLeaf = true;
|
|
5082
|
+
this.getOutletParent = () => {
|
|
5083
|
+
return this.elementRef.nativeElement;
|
|
5084
|
+
};
|
|
4348
5085
|
}
|
|
4349
5086
|
get text() {
|
|
4350
5087
|
return this.context && this.context.text;
|
|
@@ -4359,7 +5096,7 @@ class BaseLeafComponent extends BaseComponent {
|
|
|
4359
5096
|
if (!this.initialized) {
|
|
4360
5097
|
this.stringRender = new SlateStringRender(this.context, this.viewContext);
|
|
4361
5098
|
const stringNode = this.stringRender.render();
|
|
4362
|
-
this.
|
|
5099
|
+
this.getOutletParent().appendChild(stringNode);
|
|
4363
5100
|
}
|
|
4364
5101
|
else {
|
|
4365
5102
|
this.stringRender?.update(this.context, this.viewContext);
|
|
@@ -4431,5 +5168,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
4431
5168
|
* Generated bundle index. Do not edit.
|
|
4432
5169
|
*/
|
|
4433
5170
|
|
|
4434
|
-
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER,
|
|
5171
|
+
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_BUSINESS_TOP, EDITOR_TO_VIRTUAL_SCROLL_SELECTION, ELEMENT_KEY_TO_HEIGHTS, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_ENABLED_VIRTUAL_SCROLL, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SLATE_DEBUG_KEY_SCROLL_TOP, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, SlateString, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, calculateVirtualTopHeight, check, completeTable, createClipboardData, createText, createThrottleRAF, debugLog, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getRealHeightByElement, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDebug, isDebugScrollTop, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, measureHeightByElement, measureHeightByIndics, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
4435
5172
|
//# sourceMappingURL=slate-angular.mjs.map
|