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/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 0;
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
- // Is a key-value object for storing all events.
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
- // Is a key-value object for storing data about box.
2864
+ // A key-value object for storing data about box.
2801
2865
  const boxData = {};
2802
- // Is a key-value object for storing all effects.
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
- if (dropdownRect.x + menuNode.width() + 50 > window.innerWidth) {
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.6";
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 below is for unit testing because some test cases need to
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
- if (editor.readonly) {
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.container.on('cut', event => {
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.container.on('paste', event => {
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: /^`+([a-z]*)$/i,
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);