lakelib 0.1.6 → 0.1.8
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/lake.css +25 -2
- package/dist/lake.min.js +16 -10
- package/dist/lake.min.js.map +1 -1
- package/lib/lake.css +25 -2
- package/lib/lake.js +333 -24
- package/lib/lake.js.map +1 -1
- package/lib/types/editor.d.ts +4 -0
- package/lib/types/models/nodes.d.ts +1 -0
- package/lib/types/models/range.d.ts +1 -0
- package/lib/types/plugins/drop.d.ts +3 -0
- package/lib/types/ui/button.d.ts +2 -1
- package/lib/types/ui/dropdown.d.ts +3 -1
- package/lib/types/ui/toolbar.d.ts +4 -1
- package/lib/types/ui/upload.d.ts +2 -2
- package/package.json +1 -1
package/lib/lake.css
CHANGED
|
@@ -32,9 +32,11 @@
|
|
|
32
32
|
--input-outline: 2px solid #69b1ff;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
.lake-container-wrapper {
|
|
36
|
+
position: relative;
|
|
37
|
+
}
|
|
35
38
|
.lake-container {
|
|
36
39
|
box-sizing: content-box;
|
|
37
|
-
position: relative;
|
|
38
40
|
font-family: var(--font-family);
|
|
39
41
|
font-size: 16px;
|
|
40
42
|
font-weight: normal;
|
|
@@ -73,6 +75,23 @@
|
|
|
73
75
|
color: var(--link-hover-color);
|
|
74
76
|
text-decoration: underline;
|
|
75
77
|
}
|
|
78
|
+
.lake-drop-indication {
|
|
79
|
+
position: absolute;
|
|
80
|
+
height: 2px;
|
|
81
|
+
background-color: #1677ff;
|
|
82
|
+
z-index: 1;
|
|
83
|
+
pointer-events: none;
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
.lake-drop-indication svg {
|
|
87
|
+
position: absolute;
|
|
88
|
+
top: -7.5px;
|
|
89
|
+
left: -10px;
|
|
90
|
+
width: 16px;
|
|
91
|
+
height: 16px;
|
|
92
|
+
fill: #1677ff;
|
|
93
|
+
pointer-events: none;
|
|
94
|
+
}
|
|
76
95
|
|
|
77
96
|
.lake-container strong {
|
|
78
97
|
font-weight: 600;
|
|
@@ -249,6 +268,10 @@ button.lake-text-button span {
|
|
|
249
268
|
box-shadow: var(--popup-shadow);
|
|
250
269
|
display: none;
|
|
251
270
|
}
|
|
271
|
+
.lake-dropdown[placement="top"] .lake-dropdown-menu {
|
|
272
|
+
top: auto;
|
|
273
|
+
bottom: 30px;
|
|
274
|
+
}
|
|
252
275
|
.lake-dropdown .lake-dropdown-menu li {
|
|
253
276
|
display: flex;
|
|
254
277
|
align-items: center;
|
|
@@ -858,7 +881,7 @@ lake-box[name="image"] .lake-box-selected .lake-image-error {
|
|
|
858
881
|
|
|
859
882
|
/* code block */
|
|
860
883
|
lake-box[name="codeBlock"] {
|
|
861
|
-
margin: 16px
|
|
884
|
+
margin-bottom: 16px;
|
|
862
885
|
}
|
|
863
886
|
lake-box[name="codeBlock"] .lake-box-focused .lake-code-block,
|
|
864
887
|
lake-box[name="codeBlock"] .lake-box-activated .lake-code-block {
|
package/lib/lake.js
CHANGED
|
@@ -446,7 +446,7 @@ function debug(...data) {
|
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
-
//
|
|
449
|
+
// A key-value object for storing all events.
|
|
450
450
|
// value is an array which include types and listeners.
|
|
451
451
|
const eventData = {};
|
|
452
452
|
let lastNodeId = 0;
|
|
@@ -733,6 +733,17 @@ class Nodes {
|
|
|
733
733
|
closestContainer() {
|
|
734
734
|
return this.closest('div[contenteditable="true"]');
|
|
735
735
|
}
|
|
736
|
+
// Traverses the first node and its parents until it finds an element which can scroll.
|
|
737
|
+
closestScroller() {
|
|
738
|
+
let parent = this.eq(0);
|
|
739
|
+
while (parent.length > 0 && parent.isElement) {
|
|
740
|
+
if (['scroll', 'auto'].indexOf(parent.computedCSS('overflow-y')) >= 0) {
|
|
741
|
+
return parent;
|
|
742
|
+
}
|
|
743
|
+
parent = parent.parent();
|
|
744
|
+
}
|
|
745
|
+
return new Nodes();
|
|
746
|
+
}
|
|
736
747
|
// Returns the parent of the first node.
|
|
737
748
|
parent() {
|
|
738
749
|
const node = this.get(0);
|
|
@@ -971,8 +982,8 @@ class Nodes {
|
|
|
971
982
|
}
|
|
972
983
|
// Returns the interior width of the first element, which does not include padding.
|
|
973
984
|
innerWidth() {
|
|
974
|
-
const paddingLeft = parseInt(this.computedCSS('padding-left'), 10) || 0;
|
|
975
|
-
const paddingRight = parseInt(this.computedCSS('padding-right'), 10) || 0;
|
|
985
|
+
const paddingLeft = Number.parseInt(this.computedCSS('padding-left'), 10) || 0;
|
|
986
|
+
const paddingRight = Number.parseInt(this.computedCSS('padding-right'), 10) || 0;
|
|
976
987
|
return this.width() - paddingLeft - paddingRight;
|
|
977
988
|
}
|
|
978
989
|
// Returns the height of of the first element.
|
|
@@ -1299,6 +1310,59 @@ class Range {
|
|
|
1299
1310
|
get() {
|
|
1300
1311
|
return this.range;
|
|
1301
1312
|
}
|
|
1313
|
+
// Returns the size and position of the range.
|
|
1314
|
+
getRect() {
|
|
1315
|
+
const range = this.clone();
|
|
1316
|
+
let rect;
|
|
1317
|
+
let x;
|
|
1318
|
+
let width;
|
|
1319
|
+
if (range.isCollapsed) {
|
|
1320
|
+
let reference = 'left';
|
|
1321
|
+
if (range.startNode.isElement) {
|
|
1322
|
+
const children = range.startNode.children();
|
|
1323
|
+
if (children.length === 0) {
|
|
1324
|
+
range.selectNode(range.startNode);
|
|
1325
|
+
}
|
|
1326
|
+
else if (range.startOffset < children.length) {
|
|
1327
|
+
range.setEnd(range.startNode, range.startOffset + 1);
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
range.setStart(range.startNode, range.startOffset - 1);
|
|
1331
|
+
reference = 'right';
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
else {
|
|
1335
|
+
const text = range.startNode.text();
|
|
1336
|
+
if (range.startOffset < text.length) {
|
|
1337
|
+
range.setEnd(range.startNode, range.startOffset + 1);
|
|
1338
|
+
}
|
|
1339
|
+
else {
|
|
1340
|
+
range.setStart(range.startNode, range.startOffset - 1);
|
|
1341
|
+
reference = 'right';
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
rect = range.get().getBoundingClientRect();
|
|
1345
|
+
if (reference === 'left') {
|
|
1346
|
+
x = rect.x;
|
|
1347
|
+
}
|
|
1348
|
+
else {
|
|
1349
|
+
x = rect.right;
|
|
1350
|
+
}
|
|
1351
|
+
width = 1;
|
|
1352
|
+
}
|
|
1353
|
+
else {
|
|
1354
|
+
rect = range.get().getBoundingClientRect();
|
|
1355
|
+
x = rect.x;
|
|
1356
|
+
width = rect.width;
|
|
1357
|
+
}
|
|
1358
|
+
const height = rect.height;
|
|
1359
|
+
return DOMRect.fromRect({
|
|
1360
|
+
x,
|
|
1361
|
+
y: rect.y,
|
|
1362
|
+
width: width > 0 ? width : 1,
|
|
1363
|
+
height: height > 0 ? height : 1,
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1302
1366
|
// Returns −1 if the point is before the range, 0 if the point is in the range, and 1 if the point is after the range.
|
|
1303
1367
|
comparePoint(node, offset) {
|
|
1304
1368
|
return this.range.comparePoint(node.get(0), offset);
|
|
@@ -2797,13 +2861,13 @@ const boxes = new Map();
|
|
|
2797
2861
|
|
|
2798
2862
|
const editors = new Map();
|
|
2799
2863
|
|
|
2800
|
-
//
|
|
2864
|
+
// A key-value object for storing data about box.
|
|
2801
2865
|
const boxData = {};
|
|
2802
|
-
//
|
|
2866
|
+
// A key-value object for storing all effects.
|
|
2803
2867
|
const effectData = {};
|
|
2804
2868
|
const framework = safeTemplate `
|
|
2805
2869
|
<span class="lake-box-strip"><br /></span>
|
|
2806
|
-
<div class="lake-box-container" contenteditable="false"></div>
|
|
2870
|
+
<div class="lake-box-container" contenteditable="false" draggable="true"></div>
|
|
2807
2871
|
<span class="lake-box-strip"><br /></span>
|
|
2808
2872
|
`;
|
|
2809
2873
|
class Box {
|
|
@@ -2853,10 +2917,6 @@ class Box {
|
|
|
2853
2917
|
container.off('mouseleave');
|
|
2854
2918
|
container.off('click');
|
|
2855
2919
|
}
|
|
2856
|
-
// fix: should not activate box when clicking box
|
|
2857
|
-
container.on('mousedown', event => {
|
|
2858
|
-
event.preventDefault();
|
|
2859
|
-
});
|
|
2860
2920
|
container.on('mouseenter', () => {
|
|
2861
2921
|
if (container.hasClass('lake-box-selected') ||
|
|
2862
2922
|
container.hasClass('lake-box-focused') ||
|
|
@@ -4380,8 +4440,9 @@ class Dropdown {
|
|
|
4380
4440
|
this.config = config;
|
|
4381
4441
|
this.root = config.root;
|
|
4382
4442
|
this.locale = config.locale || i18nObject('en-US');
|
|
4443
|
+
const placement = config.placement || 'bottom';
|
|
4383
4444
|
this.node = query(safeTemplate `
|
|
4384
|
-
<div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}">
|
|
4445
|
+
<div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}" placement="${placement}">
|
|
4385
4446
|
<button type="button" name="${config.name}" class="lake-dropdown-title">
|
|
4386
4447
|
<div class="lake-dropdown-${config.icon ? 'icon' : 'text'}"></div>
|
|
4387
4448
|
<div class="lake-dropdown-down-icon"></div>
|
|
@@ -4481,7 +4542,11 @@ class Dropdown {
|
|
|
4481
4542
|
menuNode.show(config.menuType === 'color' ? 'flex' : 'block');
|
|
4482
4543
|
const dropdownNativeNode = dropdownNode.get(0);
|
|
4483
4544
|
const dropdownRect = dropdownNativeNode.getBoundingClientRect();
|
|
4484
|
-
|
|
4545
|
+
// A overflow width on the left side, greater than 0 indicates an overflow.
|
|
4546
|
+
const leftOverflow = menuNode.width() - (dropdownRect.x + dropdownRect.width);
|
|
4547
|
+
// A overflow width on the right side, greater than 0 indicates an overflow.
|
|
4548
|
+
const rightOverflow = dropdownRect.x + menuNode.width() - window.innerWidth;
|
|
4549
|
+
if (rightOverflow + 50 > 0 && (leftOverflow < 0 || leftOverflow < rightOverflow)) {
|
|
4485
4550
|
menuNode.css('left', 'auto');
|
|
4486
4551
|
menuNode.css('right', '0');
|
|
4487
4552
|
}
|
|
@@ -4608,7 +4673,7 @@ class Dropdown {
|
|
|
4608
4673
|
}
|
|
4609
4674
|
}
|
|
4610
4675
|
|
|
4611
|
-
var version = "0.1.
|
|
4676
|
+
var version = "0.1.8";
|
|
4612
4677
|
|
|
4613
4678
|
// Inserts a box into the specified range.
|
|
4614
4679
|
function insertBox(range, boxName, boxValue) {
|
|
@@ -5226,6 +5291,27 @@ class Editor {
|
|
|
5226
5291
|
this.isComposing = false;
|
|
5227
5292
|
this.event = new EventEmitter();
|
|
5228
5293
|
this.box = Editor.box;
|
|
5294
|
+
this.copyListener = event => {
|
|
5295
|
+
const range = this.selection.range;
|
|
5296
|
+
if (range.commonAncestor.closestContainer().get(0) !== this.container.get(0)) {
|
|
5297
|
+
return;
|
|
5298
|
+
}
|
|
5299
|
+
this.event.emit('copy', event);
|
|
5300
|
+
};
|
|
5301
|
+
this.cutListener = event => {
|
|
5302
|
+
const range = this.selection.range;
|
|
5303
|
+
if (range.commonAncestor.closestContainer().get(0) !== this.container.get(0)) {
|
|
5304
|
+
return;
|
|
5305
|
+
}
|
|
5306
|
+
this.event.emit('cut', event);
|
|
5307
|
+
};
|
|
5308
|
+
this.pasteListener = event => {
|
|
5309
|
+
const range = this.selection.range;
|
|
5310
|
+
if (range.commonAncestor.closestContainer().get(0) !== this.container.get(0)) {
|
|
5311
|
+
return;
|
|
5312
|
+
}
|
|
5313
|
+
this.event.emit('paste', event);
|
|
5314
|
+
};
|
|
5229
5315
|
this.beforeunloadListener = () => {
|
|
5230
5316
|
this.history.save();
|
|
5231
5317
|
};
|
|
@@ -5340,6 +5426,7 @@ class Editor {
|
|
|
5340
5426
|
this.rectifyContent();
|
|
5341
5427
|
this.emitStateChangeEvent();
|
|
5342
5428
|
this.togglePlaceholderClass(value);
|
|
5429
|
+
this.scrollToCaret();
|
|
5343
5430
|
this.event.emit('change', value);
|
|
5344
5431
|
};
|
|
5345
5432
|
if (!config.root) {
|
|
@@ -5555,6 +5642,66 @@ class Editor {
|
|
|
5555
5642
|
blur() {
|
|
5556
5643
|
this.container.blur();
|
|
5557
5644
|
}
|
|
5645
|
+
// Scrolls to the caret or the range of the selection.
|
|
5646
|
+
scrollToCaret() {
|
|
5647
|
+
// Creates an artificial caret that is the same size as the caret at the current caret position.
|
|
5648
|
+
const rangeRect = this.selection.range.getRect();
|
|
5649
|
+
const containerRect = this.container.get(0).getBoundingClientRect();
|
|
5650
|
+
const artificialCaret = query('<div class="lake-artificial-caret" />');
|
|
5651
|
+
const left = rangeRect.x - containerRect.x;
|
|
5652
|
+
const top = rangeRect.y - containerRect.y;
|
|
5653
|
+
artificialCaret.css({
|
|
5654
|
+
position: 'absolute',
|
|
5655
|
+
top: `${top}px`,
|
|
5656
|
+
left: `${left}px`,
|
|
5657
|
+
width: `${rangeRect.width}px`,
|
|
5658
|
+
height: `${rangeRect.height}px`,
|
|
5659
|
+
// background: 'red',
|
|
5660
|
+
'z-index': '-1',
|
|
5661
|
+
});
|
|
5662
|
+
this.overlayContainer.find('.lake-artificial-caret').remove();
|
|
5663
|
+
this.overlayContainer.append(artificialCaret);
|
|
5664
|
+
// Scrolls the artificial caret element into the visible area of the browser window
|
|
5665
|
+
// if it's not already within the visible area of the browser window.
|
|
5666
|
+
// If the element is already within the visible area of the browser window, then no scrolling takes place.
|
|
5667
|
+
let scrollX;
|
|
5668
|
+
let scrollY;
|
|
5669
|
+
let viewportWidth;
|
|
5670
|
+
let viewportHeight;
|
|
5671
|
+
const viewport = this.container.closestScroller();
|
|
5672
|
+
if (viewport.length > 0) {
|
|
5673
|
+
const nativeViewport = viewport.get(0);
|
|
5674
|
+
const viewportRect = nativeViewport.getBoundingClientRect();
|
|
5675
|
+
scrollX = nativeViewport.scrollLeft;
|
|
5676
|
+
scrollY = nativeViewport.scrollTop;
|
|
5677
|
+
viewportWidth = viewportRect.width;
|
|
5678
|
+
viewportHeight = viewportRect.height;
|
|
5679
|
+
}
|
|
5680
|
+
else {
|
|
5681
|
+
const nativeContainerWrapper = this.containerWrapper.get(0);
|
|
5682
|
+
scrollX = window.scrollX;
|
|
5683
|
+
scrollY = window.scrollY;
|
|
5684
|
+
viewportWidth = window.innerWidth - nativeContainerWrapper.offsetLeft;
|
|
5685
|
+
viewportHeight = window.innerHeight - nativeContainerWrapper.offsetTop;
|
|
5686
|
+
}
|
|
5687
|
+
let needScroll = false;
|
|
5688
|
+
let alignToTop = true;
|
|
5689
|
+
if (left < scrollX || left > scrollX + viewportWidth) {
|
|
5690
|
+
needScroll = true;
|
|
5691
|
+
}
|
|
5692
|
+
if (top < scrollY) {
|
|
5693
|
+
needScroll = true;
|
|
5694
|
+
alignToTop = true;
|
|
5695
|
+
}
|
|
5696
|
+
else if (top > scrollY + viewportHeight) {
|
|
5697
|
+
needScroll = true;
|
|
5698
|
+
alignToTop = false;
|
|
5699
|
+
}
|
|
5700
|
+
if (needScroll) {
|
|
5701
|
+
artificialCaret.get(0).scrollIntoView(alignToTop);
|
|
5702
|
+
}
|
|
5703
|
+
artificialCaret.remove();
|
|
5704
|
+
}
|
|
5558
5705
|
// Sets the specified HTML string to the editor area.
|
|
5559
5706
|
setValue(value) {
|
|
5560
5707
|
value = normalizeValue(value);
|
|
@@ -5614,7 +5761,10 @@ class Editor {
|
|
|
5614
5761
|
if (this.toolbar) {
|
|
5615
5762
|
this.toolbar.render(this);
|
|
5616
5763
|
}
|
|
5764
|
+
document.addEventListener('copy', this.copyListener);
|
|
5617
5765
|
if (!this.readonly) {
|
|
5766
|
+
document.addEventListener('cut', this.cutListener);
|
|
5767
|
+
document.addEventListener('paste', this.pasteListener);
|
|
5618
5768
|
window.addEventListener('beforeunload', this.beforeunloadListener);
|
|
5619
5769
|
document.addEventListener('selectionchange', this.selectionchangeListener);
|
|
5620
5770
|
document.addEventListener('click', this.clickListener);
|
|
@@ -5630,7 +5780,10 @@ class Editor {
|
|
|
5630
5780
|
this.history.event.removeAllListeners();
|
|
5631
5781
|
this.root.empty();
|
|
5632
5782
|
this.popupContainer.remove();
|
|
5783
|
+
document.removeEventListener('copy', this.copyListener);
|
|
5633
5784
|
if (!this.readonly) {
|
|
5785
|
+
document.removeEventListener('cut', this.cutListener);
|
|
5786
|
+
document.removeEventListener('paste', this.pasteListener);
|
|
5634
5787
|
window.removeEventListener('beforeunload', this.beforeunloadListener);
|
|
5635
5788
|
document.removeEventListener('selectionchange', this.selectionchangeListener);
|
|
5636
5789
|
document.removeEventListener('click', this.clickListener);
|
|
@@ -6345,11 +6498,15 @@ toolbarItems.forEach(item => {
|
|
|
6345
6498
|
});
|
|
6346
6499
|
class Toolbar {
|
|
6347
6500
|
constructor(config) {
|
|
6501
|
+
this.placement = 'top';
|
|
6348
6502
|
this.allMenuMap = new Map();
|
|
6349
6503
|
this.buttonItemList = [];
|
|
6350
6504
|
this.dropdownItemList = [];
|
|
6351
|
-
this.items = config.items || defaultItems;
|
|
6352
6505
|
this.root = query(config.root);
|
|
6506
|
+
this.items = config.items || defaultItems;
|
|
6507
|
+
if (config.placement) {
|
|
6508
|
+
this.placement = config.placement;
|
|
6509
|
+
}
|
|
6353
6510
|
this.container = query('<div class="lake-toolbar" />');
|
|
6354
6511
|
this.root.addClass('lake-custom-properties');
|
|
6355
6512
|
}
|
|
@@ -6384,6 +6541,7 @@ class Toolbar {
|
|
|
6384
6541
|
menuType: item.menuType,
|
|
6385
6542
|
menuItems: item.menuItems,
|
|
6386
6543
|
tabIndex: -1,
|
|
6544
|
+
placement: this.placement === 'top' ? 'bottom' : 'top',
|
|
6387
6545
|
onSelect: value => {
|
|
6388
6546
|
editor.focus();
|
|
6389
6547
|
item.onSelect(editor, value);
|
|
@@ -6754,11 +6912,18 @@ function openFullScreen(box) {
|
|
|
6754
6912
|
}
|
|
6755
6913
|
return placeholderSrc;
|
|
6756
6914
|
});
|
|
6915
|
+
let savedRange;
|
|
6757
6916
|
lightbox.on('openingAnimationEnd', () => {
|
|
6917
|
+
savedRange = editor.selection.range;
|
|
6758
6918
|
box.event.emit('openfullscreen');
|
|
6759
6919
|
});
|
|
6760
6920
|
lightbox.on('destroy', () => {
|
|
6761
6921
|
window.setTimeout(() => {
|
|
6922
|
+
if (savedRange) {
|
|
6923
|
+
// fix(image): lose focus when zooming in the iOS
|
|
6924
|
+
editor.selection.range = savedRange;
|
|
6925
|
+
editor.selection.addRangeToNativeSelection();
|
|
6926
|
+
}
|
|
6762
6927
|
box.event.emit('closefullscreen');
|
|
6763
6928
|
}, 0);
|
|
6764
6929
|
});
|
|
@@ -6970,7 +7135,7 @@ const imageBox = {
|
|
|
6970
7135
|
}
|
|
6971
7136
|
}
|
|
6972
7137
|
if (container.first().length === 0) {
|
|
6973
|
-
// The code
|
|
7138
|
+
// The following code is for unit testing because some test cases need to
|
|
6974
7139
|
// select the content of the box before it is completely loaded.
|
|
6975
7140
|
// Example:
|
|
6976
7141
|
// range.setStart(box.getContainer(), 1);
|
|
@@ -7209,10 +7374,7 @@ const codeBlockBox = {
|
|
|
7209
7374
|
};
|
|
7210
7375
|
|
|
7211
7376
|
var copy = (editor) => {
|
|
7212
|
-
|
|
7213
|
-
return;
|
|
7214
|
-
}
|
|
7215
|
-
editor.container.on('copy', event => {
|
|
7377
|
+
editor.event.on('copy', event => {
|
|
7216
7378
|
const range = editor.selection.range;
|
|
7217
7379
|
if (range.isInsideBox) {
|
|
7218
7380
|
return;
|
|
@@ -7239,7 +7401,7 @@ var cut = (editor) => {
|
|
|
7239
7401
|
if (editor.readonly) {
|
|
7240
7402
|
return;
|
|
7241
7403
|
}
|
|
7242
|
-
editor.
|
|
7404
|
+
editor.event.on('cut', event => {
|
|
7243
7405
|
const range = editor.selection.range;
|
|
7244
7406
|
if (range.isInsideBox) {
|
|
7245
7407
|
return;
|
|
@@ -7423,7 +7585,7 @@ var paste = (editor) => {
|
|
|
7423
7585
|
if (editor.readonly) {
|
|
7424
7586
|
return;
|
|
7425
7587
|
}
|
|
7426
|
-
editor.
|
|
7588
|
+
editor.event.on('paste', event => {
|
|
7427
7589
|
const { requestTypes } = editor.config.image;
|
|
7428
7590
|
const range = editor.selection.range;
|
|
7429
7591
|
if (range.isInsideBox) {
|
|
@@ -7468,6 +7630,154 @@ var paste = (editor) => {
|
|
|
7468
7630
|
});
|
|
7469
7631
|
};
|
|
7470
7632
|
|
|
7633
|
+
var drop = (editor) => {
|
|
7634
|
+
if (editor.readonly) {
|
|
7635
|
+
return;
|
|
7636
|
+
}
|
|
7637
|
+
let draggedNode = null;
|
|
7638
|
+
let dropIndication = null;
|
|
7639
|
+
let targetBlock = null;
|
|
7640
|
+
let dropPosition = 'bottom';
|
|
7641
|
+
// The dragstart event is fired when the user starts dragging an element or text selection.
|
|
7642
|
+
editor.container.on('dragstart', event => {
|
|
7643
|
+
draggedNode = null;
|
|
7644
|
+
const dragEvent = event;
|
|
7645
|
+
const dataTransfer = dragEvent.dataTransfer;
|
|
7646
|
+
if (!dataTransfer) {
|
|
7647
|
+
return;
|
|
7648
|
+
}
|
|
7649
|
+
dataTransfer.effectAllowed = 'move';
|
|
7650
|
+
// set the dragged node
|
|
7651
|
+
const targetNode = query(dragEvent.target);
|
|
7652
|
+
const boxNode = targetNode.closest('lake-box');
|
|
7653
|
+
if (boxNode.length === 0) {
|
|
7654
|
+
dragEvent.preventDefault();
|
|
7655
|
+
return;
|
|
7656
|
+
}
|
|
7657
|
+
const box = new Box(boxNode);
|
|
7658
|
+
if (box.type === 'inline') {
|
|
7659
|
+
dragEvent.preventDefault();
|
|
7660
|
+
return;
|
|
7661
|
+
}
|
|
7662
|
+
draggedNode = boxNode;
|
|
7663
|
+
// prepare an indication rod
|
|
7664
|
+
dropIndication = query(safeTemplate `
|
|
7665
|
+
<div class="lake-drop-indication">
|
|
7666
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256">
|
|
7667
|
+
<path d="M181.66,133.66l-80,80A8,8,0,0,1,88,208V48a8,8,0,0,1,13.66-5.66l80,80A8,8,0,0,1,181.66,133.66Z"></path>
|
|
7668
|
+
</svg>
|
|
7669
|
+
</div>
|
|
7670
|
+
`);
|
|
7671
|
+
editor.overlayContainer.append(dropIndication);
|
|
7672
|
+
});
|
|
7673
|
+
// The dragover event is fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds).
|
|
7674
|
+
editor.container.on('dragover', event => {
|
|
7675
|
+
const dragEvent = event;
|
|
7676
|
+
dragEvent.preventDefault();
|
|
7677
|
+
const dataTransfer = dragEvent.dataTransfer;
|
|
7678
|
+
if (!dataTransfer) {
|
|
7679
|
+
return;
|
|
7680
|
+
}
|
|
7681
|
+
dataTransfer.dropEffect = 'move';
|
|
7682
|
+
if (!dropIndication) {
|
|
7683
|
+
return;
|
|
7684
|
+
}
|
|
7685
|
+
const targetNode = query(dragEvent.target);
|
|
7686
|
+
if (targetNode.isContainer) {
|
|
7687
|
+
return;
|
|
7688
|
+
}
|
|
7689
|
+
const targetBoxNode = targetNode.closest('lake-box');
|
|
7690
|
+
if (targetBoxNode.length > 0) {
|
|
7691
|
+
if (targetBoxNode.isBlockBox) {
|
|
7692
|
+
targetBlock = targetBoxNode;
|
|
7693
|
+
}
|
|
7694
|
+
else {
|
|
7695
|
+
targetBlock = targetBoxNode.closestBlock();
|
|
7696
|
+
}
|
|
7697
|
+
}
|
|
7698
|
+
else {
|
|
7699
|
+
targetBlock = targetNode.closestBlock();
|
|
7700
|
+
}
|
|
7701
|
+
const containerRect = editor.container.get(0).getBoundingClientRect();
|
|
7702
|
+
let targetBlcokRect = targetBlock.get(0).getBoundingClientRect();
|
|
7703
|
+
dropPosition = 'bottom';
|
|
7704
|
+
let left = targetBlcokRect.x - containerRect.x;
|
|
7705
|
+
let top = targetBlcokRect.y + targetBlcokRect.height - containerRect.y + (parseInt(targetBlock.computedCSS('margin-bottom'), 10) / 2);
|
|
7706
|
+
if (dragEvent.clientY < targetBlcokRect.y + (targetBlcokRect.height / 2)) {
|
|
7707
|
+
const prevBlock = targetBlock.prev();
|
|
7708
|
+
if (prevBlock.length > 0 && prevBlock.isBlock || prevBlock.isBlockBox) {
|
|
7709
|
+
targetBlock = prevBlock;
|
|
7710
|
+
targetBlcokRect = targetBlock.get(0).getBoundingClientRect();
|
|
7711
|
+
left = targetBlcokRect.x - containerRect.x;
|
|
7712
|
+
top = targetBlcokRect.y + targetBlcokRect.height - containerRect.y + (parseInt(targetBlock.computedCSS('margin-bottom'), 10) / 2);
|
|
7713
|
+
}
|
|
7714
|
+
else {
|
|
7715
|
+
dropPosition = 'top';
|
|
7716
|
+
top = targetBlcokRect.y - containerRect.y - (parseInt(editor.container.computedCSS('padding-top'), 10) / 2);
|
|
7717
|
+
}
|
|
7718
|
+
}
|
|
7719
|
+
dropIndication.css({
|
|
7720
|
+
top: `${top}px`,
|
|
7721
|
+
left: `${left}px`,
|
|
7722
|
+
width: `${targetBlcokRect.width}px`,
|
|
7723
|
+
display: 'block',
|
|
7724
|
+
});
|
|
7725
|
+
});
|
|
7726
|
+
// The dragend event is fired when a drag operation ends (by releasing a mouse button or hitting the escape key).
|
|
7727
|
+
editor.container.on('dragend', () => {
|
|
7728
|
+
if (!dropIndication) {
|
|
7729
|
+
return;
|
|
7730
|
+
}
|
|
7731
|
+
dropIndication.remove();
|
|
7732
|
+
dropIndication = null;
|
|
7733
|
+
});
|
|
7734
|
+
// The drop event is fired when an element or text selection is dropped on a valid drop target.
|
|
7735
|
+
editor.container.on('drop', event => {
|
|
7736
|
+
const dragEvent = event;
|
|
7737
|
+
const dataTransfer = dragEvent.dataTransfer;
|
|
7738
|
+
if (!dataTransfer) {
|
|
7739
|
+
return;
|
|
7740
|
+
}
|
|
7741
|
+
if (!dropIndication) {
|
|
7742
|
+
return;
|
|
7743
|
+
}
|
|
7744
|
+
dropIndication.remove();
|
|
7745
|
+
dropIndication = null;
|
|
7746
|
+
// drop a box
|
|
7747
|
+
if (draggedNode && targetBlock && draggedNode.isBox) {
|
|
7748
|
+
if (draggedNode.get(0) === targetBlock.get(0)) {
|
|
7749
|
+
return;
|
|
7750
|
+
}
|
|
7751
|
+
if (dropPosition === 'bottom' && draggedNode.get(0) === targetBlock.next().get(0)) {
|
|
7752
|
+
return;
|
|
7753
|
+
}
|
|
7754
|
+
dragEvent.preventDefault();
|
|
7755
|
+
const draggedBox = new Box(draggedNode);
|
|
7756
|
+
const range = editor.selection.range;
|
|
7757
|
+
if (targetBlock.isBox) {
|
|
7758
|
+
if (dropPosition === 'top') {
|
|
7759
|
+
range.selectBoxStart(targetBlock);
|
|
7760
|
+
}
|
|
7761
|
+
else {
|
|
7762
|
+
range.selectBoxEnd(targetBlock);
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
else {
|
|
7766
|
+
range.selectNodeContents(targetBlock);
|
|
7767
|
+
if (dropPosition === 'top') {
|
|
7768
|
+
range.collapseToStart();
|
|
7769
|
+
}
|
|
7770
|
+
else {
|
|
7771
|
+
range.collapseToEnd();
|
|
7772
|
+
}
|
|
7773
|
+
}
|
|
7774
|
+
editor.insertBox(draggedBox.name, draggedBox.value);
|
|
7775
|
+
draggedNode.remove();
|
|
7776
|
+
editor.history.save();
|
|
7777
|
+
}
|
|
7778
|
+
});
|
|
7779
|
+
};
|
|
7780
|
+
|
|
7471
7781
|
var undo = (editor) => {
|
|
7472
7782
|
if (editor.readonly) {
|
|
7473
7783
|
return;
|
|
@@ -8525,7 +8835,7 @@ const blockItemListForEnterKey = [
|
|
|
8525
8835
|
],
|
|
8526
8836
|
},
|
|
8527
8837
|
{
|
|
8528
|
-
re:
|
|
8838
|
+
re: /^`{3,}([a-z]*)$/i,
|
|
8529
8839
|
getParameters: (results) => {
|
|
8530
8840
|
var _a;
|
|
8531
8841
|
if (!results[1]) {
|
|
@@ -8730,12 +9040,10 @@ function splitBlock(editor, block) {
|
|
|
8730
9040
|
editor.selection.splitBlock();
|
|
8731
9041
|
block = range.getBlocks()[0];
|
|
8732
9042
|
if (!block) {
|
|
8733
|
-
editor.history.save();
|
|
8734
9043
|
return;
|
|
8735
9044
|
}
|
|
8736
9045
|
if (endText === '' && (block.isHeading || block.name === 'blockquote')) {
|
|
8737
9046
|
editor.selection.setBlocks('<p />');
|
|
8738
|
-
editor.history.save();
|
|
8739
9047
|
return;
|
|
8740
9048
|
}
|
|
8741
9049
|
if (block.isList && block.attr('type') === 'checklist') {
|
|
@@ -9298,6 +9606,7 @@ Editor.box.add(codeBlockBox);
|
|
|
9298
9606
|
Editor.plugin.add(copy);
|
|
9299
9607
|
Editor.plugin.add(cut);
|
|
9300
9608
|
Editor.plugin.add(paste);
|
|
9609
|
+
Editor.plugin.add(drop);
|
|
9301
9610
|
Editor.plugin.add(undo);
|
|
9302
9611
|
Editor.plugin.add(redo);
|
|
9303
9612
|
Editor.plugin.add(selectAll);
|