lakelib 0.1.12 → 0.1.14

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.js CHANGED
@@ -319,7 +319,7 @@ function parseStyle(styleValue) {
319
319
  // Converts the special tags to ordinary HTML tags that can be parsed by browser.
320
320
  function normalizeValue(value) {
321
321
  return value.
322
- replace(/(<lake-box[^>]+>)[\s\S]*?(<\/lake-box>)/ig, '$1$2').
322
+ replace(/(<lake-box[^>]+>)[\s\S]*?(<\/lake-box>|$)/ig, '$1</lake-box>').
323
323
  replace(/<anchor\s*\/>/ig, '<lake-bookmark type="anchor"></lake-bookmark>').
324
324
  replace(/<focus\s*\/>/ig, '<lake-bookmark type="focus"></lake-bookmark>');
325
325
  }
@@ -1566,7 +1566,7 @@ class Range {
1566
1566
  }
1567
1567
  }
1568
1568
  // Relocates the start and end points of the range for the box.
1569
- adaptBox() {
1569
+ adjustBox() {
1570
1570
  const startBoxNode = this.startNode.closest('lake-box');
1571
1571
  if (startBoxNode.length > 0) {
1572
1572
  const startRange = this.clone();
@@ -1591,7 +1591,7 @@ class Range {
1591
1591
  }
1592
1592
  }
1593
1593
  // Relocates the beginning or end position of the range for table.
1594
- adaptTable() {
1594
+ adjustTable() {
1595
1595
  const startTable = this.startNode.closest('table');
1596
1596
  const endTable = this.endNode.closest('table');
1597
1597
  if (startTable.length === 0 && endTable.length > 0 && endTable.isInside) {
@@ -1617,7 +1617,7 @@ class Range {
1617
1617
  // [<p>foo</p><p>]bar</p>
1618
1618
  // to
1619
1619
  // <p>[foo]</p><p>bar</p>
1620
- adaptBlock() {
1620
+ adjustBlock() {
1621
1621
  if (!this.isCollapsed) {
1622
1622
  // [<p>foo</p><p>]bar</p> to [<p>foo</p>]<p>bar</p>
1623
1623
  if (this.endNode.isElement && this.endOffset === 0) {
@@ -1639,10 +1639,10 @@ class Range {
1639
1639
  }
1640
1640
  }
1641
1641
  // Relocates the start and end points of the range.
1642
- adapt() {
1643
- this.adaptBox();
1644
- this.adaptTable();
1645
- this.adaptBlock();
1642
+ adjust() {
1643
+ this.adjustBox();
1644
+ this.adjustTable();
1645
+ this.adjustBlock();
1646
1646
  }
1647
1647
  // Returns the previous node of the beginning point of the range.
1648
1648
  getPrevNode() {
@@ -1684,7 +1684,7 @@ class Range {
1684
1684
  }
1685
1685
  const nodeList = [];
1686
1686
  const clonedRange = this.clone();
1687
- clonedRange.adaptBox();
1687
+ clonedRange.adjustBox();
1688
1688
  for (const child of clonedRange.commonAncestor.getWalker()) {
1689
1689
  if (child.isBox && clonedRange.intersectsNode(child)) {
1690
1690
  nodeList.push(child);
@@ -2029,10 +2029,15 @@ function wrapNodeList(nodeList, wrapper) {
2029
2029
  // Removes Zero-width spaces that are dependent on some other text nodes.
2030
2030
  function removeZWS(node) {
2031
2031
  for (const child of node.getWalker()) {
2032
- if (child.isText && child.text().length > 1) {
2033
- const nodeValue = child.text();
2034
- if (/\u200B/.test(child.text())) {
2035
- child.get(0).nodeValue = nodeValue.replace(/\u200B/g, '');
2032
+ if (child.isText) {
2033
+ const text = child.text();
2034
+ if (text === '') {
2035
+ child.remove();
2036
+ }
2037
+ else if (text.length > 1) {
2038
+ if (/\u200B/.test(text)) {
2039
+ child.get(0).nodeValue = text.replace(/\u200B/g, '');
2040
+ }
2036
2041
  }
2037
2042
  }
2038
2043
  }
@@ -2717,21 +2722,18 @@ function nodeAndView(node) {
2717
2722
  let bottom = rect.bottom;
2718
2723
  let viewportWidth = window.innerWidth;
2719
2724
  let viewportHeight = window.innerHeight;
2720
- const container = node.closestContainer();
2721
- if (container.length > 0) {
2722
- const viewport = container.closestScroller();
2723
- if (viewport.length > 0) {
2724
- const nativeViewport = viewport.get(0);
2725
- const viewportRect = nativeViewport.getBoundingClientRect();
2726
- const offsetLeft = viewportRect.x;
2727
- const offsetTop = viewportRect.y;
2728
- left -= offsetLeft;
2729
- right -= offsetLeft;
2730
- top -= offsetTop;
2731
- bottom -= offsetTop;
2732
- viewportWidth = viewportRect.width;
2733
- viewportHeight = viewportRect.height;
2734
- }
2725
+ const viewport = node.closestScroller();
2726
+ if (viewport.length > 0) {
2727
+ const nativeViewport = viewport.get(0);
2728
+ const viewportRect = nativeViewport.getBoundingClientRect();
2729
+ const offsetLeft = viewportRect.x;
2730
+ const offsetTop = viewportRect.y;
2731
+ left -= offsetLeft;
2732
+ right -= offsetLeft;
2733
+ top -= offsetTop;
2734
+ bottom -= offsetTop;
2735
+ viewportWidth = viewportRect.width;
2736
+ viewportHeight = viewportRect.height;
2735
2737
  }
2736
2738
  const position = {
2737
2739
  left,
@@ -3569,7 +3571,7 @@ class Box {
3569
3571
  container.removeClass('lake-box-hovered');
3570
3572
  });
3571
3573
  container.on('click', () => {
3572
- debug(`Box '${this.name}' (id = ${this.node.id}) value:`);
3574
+ debug(`Box "${this.name}" (id = ${this.node.id}) value:`);
3573
3575
  debug(this.value);
3574
3576
  });
3575
3577
  if (this.type === 'block' && this.node.isContentEditable) {
@@ -3670,7 +3672,7 @@ class Box {
3670
3672
  newContainer.append(content);
3671
3673
  morph(container, newContainer);
3672
3674
  }
3673
- debug(`Box '${this.name}' (id = ${this.node.id}) rendered`);
3675
+ debug(`Box "${this.name}" (id: ${this.node.id}) rendered`);
3674
3676
  }
3675
3677
  // Destroys a rendered box.
3676
3678
  unmount() {
@@ -3679,7 +3681,7 @@ class Box {
3679
3681
  boxData[this.node.id] = {};
3680
3682
  this.event.removeAllListeners();
3681
3683
  this.node.empty();
3682
- debug(`Box '${this.name}' (id = ${this.node.id}) unmounted`);
3684
+ debug(`Box "${this.name}" (id: ${this.node.id}) unmounted`);
3683
3685
  }
3684
3686
  // Returns a HTML string of the box.
3685
3687
  getHTML() {
@@ -4290,9 +4292,8 @@ function insertBookmark(range) {
4290
4292
  function removeAndNormalizeNode(node, range) {
4291
4293
  const previousNode = node.prev();
4292
4294
  const nextNode = node.next();
4293
- if (previousNode.isText && nextNode.isText) {
4295
+ if (previousNode.isText || nextNode.isText) {
4294
4296
  const parentNode = node.parent();
4295
- removeZWS(parentNode);
4296
4297
  node.remove();
4297
4298
  parentNode.get(0).normalize();
4298
4299
  }
@@ -4375,8 +4376,8 @@ function deleteContents(range) {
4375
4376
  if (range.isCollapsed) {
4376
4377
  return;
4377
4378
  }
4378
- range.adaptBox();
4379
- range.adaptTable();
4379
+ range.adjustBox();
4380
+ range.adjustTable();
4380
4381
  if (range.isInoperative) {
4381
4382
  return;
4382
4383
  }
@@ -4385,7 +4386,7 @@ function deleteContents(range) {
4385
4386
  const noMerge = startBlock.get(0) === endBlock.get(0);
4386
4387
  const nativeRange = range.get();
4387
4388
  nativeRange.deleteContents();
4388
- range.adaptBlock();
4389
+ range.adjustBlock();
4389
4390
  if (noMerge) {
4390
4391
  const block = range.getBlocks()[0];
4391
4392
  if (block && block.isEmpty) {
@@ -4414,7 +4415,7 @@ function insertFragment(range, fragment) {
4414
4415
  return;
4415
4416
  }
4416
4417
  if (range.isCollapsed) {
4417
- range.adaptBox();
4418
+ range.adjustBox();
4418
4419
  }
4419
4420
  else {
4420
4421
  deleteContents(range);
@@ -4424,7 +4425,7 @@ function insertFragment(range, fragment) {
4424
4425
  const bookmark = insertBookmark(range);
4425
4426
  bookmark.focus.before(fragment);
4426
4427
  toBookmark(range, bookmark);
4427
- range.adaptBlock();
4428
+ range.adjustBlock();
4428
4429
  }
4429
4430
 
4430
4431
  // Inserts a HTML string into the specified range.
@@ -4543,7 +4544,7 @@ function splitBlock$1(range) {
4543
4544
  };
4544
4545
  }
4545
4546
  if (range.isCollapsed) {
4546
- range.adaptBox();
4547
+ range.adjustBox();
4547
4548
  }
4548
4549
  else {
4549
4550
  deleteContents(range);
@@ -4596,7 +4597,7 @@ function splitBlock$1(range) {
4596
4597
  }
4597
4598
 
4598
4599
  // Removes empty marks that contain no content.
4599
- function removeEmptyMarks$1(node) {
4600
+ function removeEmptyMarks$2(node) {
4600
4601
  if (node.isMark && node.isEmpty) {
4601
4602
  node.remove();
4602
4603
  return;
@@ -4618,8 +4619,8 @@ function splitMarksAtPoint(node, offset, removeEmptyMark) {
4618
4619
  const parts = splitNodes(node, offset, limitBlock);
4619
4620
  if (parts) {
4620
4621
  if (removeEmptyMark) {
4621
- removeEmptyMarks$1(parts.start);
4622
- removeEmptyMarks$1(parts.end);
4622
+ removeEmptyMarks$2(parts.start);
4623
+ removeEmptyMarks$2(parts.end);
4623
4624
  if (!parts.start.isEmpty) {
4624
4625
  start = parts.start;
4625
4626
  }
@@ -4649,7 +4650,7 @@ function splitMarks(range, removeEmptyMark = true) {
4649
4650
  end: null,
4650
4651
  };
4651
4652
  }
4652
- range.adaptBox();
4653
+ range.adjustBox();
4653
4654
  if (range.isCollapsed) {
4654
4655
  const parts = splitMarksAtPoint(range.startNode, range.startOffset, removeEmptyMark);
4655
4656
  if (parts.start) {
@@ -4754,7 +4755,7 @@ function addMark(range, value) {
4754
4755
  range.shrinkAfter(newBlock);
4755
4756
  }
4756
4757
  else {
4757
- range.adaptBox();
4758
+ range.adjustBox();
4758
4759
  }
4759
4760
  }
4760
4761
  const block = range.startNode.closestBlock();
@@ -4805,7 +4806,7 @@ function addMark(range, value) {
4805
4806
  }
4806
4807
 
4807
4808
  // Removes empty marks that contain no content.
4808
- function removeEmptyMarks(node) {
4809
+ function removeEmptyMarks$1(node) {
4809
4810
  if (node.isMark && node.isEmpty) {
4810
4811
  node.remove();
4811
4812
  return;
@@ -4863,13 +4864,13 @@ function removeMark(range, value) {
4863
4864
  return;
4864
4865
  }
4865
4866
  if (parts.end) {
4866
- removeEmptyMarks(parts.end);
4867
+ removeEmptyMarks$1(parts.end);
4867
4868
  }
4868
4869
  const zeroWidthSpace = new Nodes(document.createTextNode('\u200B'));
4869
4870
  const newMark = copyNestedMarks(parts.start, tagName);
4870
4871
  if (!newMark) {
4871
4872
  parts.start.after(zeroWidthSpace);
4872
- removeEmptyMarks(parts.start);
4873
+ removeEmptyMarks$1(parts.start);
4873
4874
  if (zeroWidthSpace.prev().isText) {
4874
4875
  range.setStartAfter(zeroWidthSpace.prev());
4875
4876
  range.collapseToStart();
@@ -4882,7 +4883,7 @@ function removeMark(range, value) {
4882
4883
  }
4883
4884
  appendDeepest(newMark, zeroWidthSpace);
4884
4885
  parts.start.after(newMark);
4885
- removeEmptyMarks(parts.start);
4886
+ removeEmptyMarks$1(parts.start);
4886
4887
  range.shrinkAfter(newMark);
4887
4888
  return;
4888
4889
  }
@@ -4950,7 +4951,7 @@ function insertLink(range, value) {
4950
4951
  return linkNode;
4951
4952
  }
4952
4953
 
4953
- var version = "0.1.12";
4954
+ var version = "0.1.14";
4954
4955
 
4955
4956
  // Inserts a box into the specified range.
4956
4957
  function insertBox(range, boxName, boxValue) {
@@ -5119,7 +5120,10 @@ class Selection {
5119
5120
  // Updates the saved range with the range of the native selection.
5120
5121
  updateByRange() {
5121
5122
  const newRange = this.getRangeFromNativeSelection();
5122
- if (this.range.get() === newRange.get()) {
5123
+ if (this.range.startNode.get(0) === newRange.startNode.get(0) &&
5124
+ this.range.startOffset === newRange.startOffset &&
5125
+ this.range.endNode.get(0) === newRange.endNode.get(0) &&
5126
+ this.range.endOffset === newRange.endOffset) {
5123
5127
  return;
5124
5128
  }
5125
5129
  this.range = newRange;
@@ -5221,7 +5225,6 @@ class Selection {
5221
5225
  class Command {
5222
5226
  constructor(selection) {
5223
5227
  this.commandMap = new Map();
5224
- this.event = new EventEmitter();
5225
5228
  this.selection = selection;
5226
5229
  }
5227
5230
  add(name, commandItem) {
@@ -5239,7 +5242,7 @@ class Command {
5239
5242
  getItem(name) {
5240
5243
  const commandItem = this.commandMap.get(name);
5241
5244
  if (commandItem === undefined) {
5242
- throw new Error(`Command '${name}' does not exist.`);
5245
+ throw new Error(`Command '${name}' does not exist`);
5243
5246
  }
5244
5247
  return commandItem;
5245
5248
  }
@@ -5269,10 +5272,8 @@ class Command {
5269
5272
  }
5270
5273
  execute(name, ...data) {
5271
5274
  const commandItem = this.getItem(name);
5272
- this.event.emit('beforeexecute', name);
5273
5275
  commandItem.execute.apply(this, data);
5274
- this.event.emit('execute', name);
5275
- debug(`Command '${name}' executed`);
5276
+ debug(`Command "${name}" executed`);
5276
5277
  }
5277
5278
  }
5278
5279
 
@@ -5290,11 +5291,11 @@ class Command {
5290
5291
  // inputs 'e': value: 'abe', list: ['a', 'ab', 'abe'], index: 3, canRedo: false
5291
5292
  class History {
5292
5293
  constructor(selection) {
5294
+ this.canSave = true;
5293
5295
  // an array for storing the history items
5294
5296
  this.list = [];
5295
5297
  // the next index of the list
5296
5298
  this.index = 0;
5297
- this.canSave = true;
5298
5299
  this.limit = 100;
5299
5300
  this.event = new EventEmitter();
5300
5301
  this.selection = selection;
@@ -5346,6 +5347,12 @@ class History {
5346
5347
  this.removeIdfromBoxes(container);
5347
5348
  this.removeIdfromBoxes(otherContainer);
5348
5349
  }
5350
+ get canUndo() {
5351
+ return this.index > 1 && !!this.list[this.index - 1];
5352
+ }
5353
+ get canRedo() {
5354
+ return !!this.list[this.index];
5355
+ }
5349
5356
  cloneContainer() {
5350
5357
  const range = this.selection.range;
5351
5358
  const newContainer = this.container.clone(true);
@@ -5357,6 +5364,12 @@ class History {
5357
5364
  return newContainer;
5358
5365
  }
5359
5366
  if (range.isInsideBox) {
5367
+ const boxNode = range.commonAncestor.closest('lake-box');
5368
+ const boxNodePath = boxNode.path();
5369
+ const newBoxNode = newContainer.find(boxNodePath);
5370
+ const newRange = range.clone();
5371
+ newRange.selectBox(newBoxNode);
5372
+ insertBookmark(newRange);
5360
5373
  return newContainer;
5361
5374
  }
5362
5375
  const startNodePath = range.startNode.path();
@@ -5369,39 +5382,27 @@ class History {
5369
5382
  insertBookmark(newRange);
5370
5383
  return newContainer;
5371
5384
  }
5372
- get count() {
5373
- return this.list.length;
5374
- }
5375
- get canUndo() {
5376
- return this.index > 1 && !!this.list[this.index - 1];
5377
- }
5378
- get canRedo() {
5379
- return !!this.list[this.index];
5380
- }
5381
5385
  undo() {
5382
- if (!this.list[this.index - 1]) {
5386
+ if (!this.list[this.index - 2]) {
5383
5387
  return;
5384
5388
  }
5385
5389
  this.selection.insertBookmark();
5386
5390
  const value = this.getValue(this.container);
5387
- while (this.index > 0) {
5388
- const prevItem = this.list[this.index - 1];
5391
+ while (this.index > 1) {
5392
+ const prevItem = this.list[this.index - 2];
5389
5393
  if (!prevItem) {
5390
5394
  break;
5391
5395
  }
5396
+ this.index--;
5392
5397
  const prevValue = this.getValue(prevItem);
5393
5398
  if (this.removeBookmark(prevValue) !== this.removeBookmark(value)) {
5394
5399
  this.morphContainer(prevItem);
5395
5400
  this.event.emit('undo', prevValue);
5396
5401
  break;
5397
5402
  }
5398
- if (this.index === 1) {
5399
- break;
5400
- }
5401
- this.index--;
5402
5403
  }
5403
5404
  this.selection.updateByBookmark();
5404
- debug(`History undone, the last index is ${this.index}`);
5405
+ debug(`History undone (index: ${this.index})`);
5405
5406
  }
5406
5407
  redo() {
5407
5408
  if (!this.list[this.index]) {
@@ -5423,7 +5424,7 @@ class History {
5423
5424
  }
5424
5425
  }
5425
5426
  this.selection.updateByBookmark();
5426
- debug(`History redone, the last index is ${this.index}`);
5427
+ debug(`History redone (index: ${this.index})`);
5427
5428
  }
5428
5429
  continue() {
5429
5430
  this.canSave = true;
@@ -5431,7 +5432,11 @@ class History {
5431
5432
  pause() {
5432
5433
  this.canSave = false;
5433
5434
  }
5434
- save(emitSaveEvent = true) {
5435
+ save(options = {}) {
5436
+ var _a, _b, _c;
5437
+ const inputType = (_a = options.inputType) !== null && _a !== void 0 ? _a : '';
5438
+ const update = (_b = options.update) !== null && _b !== void 0 ? _b : false;
5439
+ const emitEvent = (_c = options.emitEvent) !== null && _c !== void 0 ? _c : true;
5435
5440
  if (!this.canSave) {
5436
5441
  return;
5437
5442
  }
@@ -5441,16 +5446,25 @@ class History {
5441
5446
  this.removeBookmark(this.getValue(this.list[this.index - 1])) === this.removeBookmark(value)) {
5442
5447
  return;
5443
5448
  }
5444
- this.list.splice(this.index, Infinity, item);
5445
- this.index++;
5449
+ if (update) {
5450
+ this.list.splice(this.index - 1, Infinity, item);
5451
+ }
5452
+ else {
5453
+ this.list.splice(this.index, Infinity, item);
5454
+ this.index++;
5455
+ }
5446
5456
  if (this.list.length > this.limit) {
5447
5457
  this.list.shift();
5448
5458
  this.index = this.list.length;
5449
5459
  }
5450
- if (emitSaveEvent) {
5451
- this.event.emit('save', denormalizeValue(value));
5460
+ debug(`History saved (index: ${this.index}, inputType: "${inputType}", update: ${update}, emitEvent: ${emitEvent})`);
5461
+ if (emitEvent) {
5462
+ this.event.emit('save', denormalizeValue(value), {
5463
+ inputType,
5464
+ update,
5465
+ emitEvent,
5466
+ });
5452
5467
  }
5453
- debug(`History saved, the last index is ${this.index}`);
5454
5468
  }
5455
5469
  }
5456
5470
 
@@ -5529,27 +5543,6 @@ class BoxManager {
5529
5543
  getNames() {
5530
5544
  return Array.from(boxes.keys());
5531
5545
  }
5532
- rectifyInstances(container) {
5533
- const instanceMap = getInstanceMap(container.id);
5534
- for (const box of instanceMap.values()) {
5535
- if (!box.node.get(0).isConnected) {
5536
- box.unmount();
5537
- instanceMap.delete(box.node.id);
5538
- }
5539
- }
5540
- }
5541
- renderAll(container) {
5542
- this.rectifyInstances(container);
5543
- const instanceMap = getInstanceMap(container.id);
5544
- container.find('lake-box').each(boxNativeNode => {
5545
- const boxNode = query(boxNativeNode);
5546
- if (instanceMap.get(boxNode.id)) {
5547
- return;
5548
- }
5549
- const box = getBox(boxNode);
5550
- box.render();
5551
- });
5552
- }
5553
5546
  }
5554
5547
 
5555
5548
  class Plugin {
@@ -5595,6 +5588,7 @@ const defaultConfig = {
5595
5588
  class Editor {
5596
5589
  constructor(config) {
5597
5590
  this.unsavedInputData = '';
5591
+ this.unsavedInputCount = 0;
5598
5592
  this.state = {
5599
5593
  appliedItems: [],
5600
5594
  disabledNameMap: new Map(),
@@ -5625,9 +5619,6 @@ class Editor {
5625
5619
  }
5626
5620
  this.event.emit('paste', event);
5627
5621
  };
5628
- this.beforeunloadListener = () => {
5629
- this.history.save();
5630
- };
5631
5622
  this.selectionchangeListener = () => {
5632
5623
  this.selection.updateByRange();
5633
5624
  this.updateBoxSelectionStyle();
@@ -5643,6 +5634,7 @@ class Editor {
5643
5634
  this.resizeListener = () => {
5644
5635
  this.event.emit('resize');
5645
5636
  };
5637
+ // Updates the classes of all boxes when the current selection of the editor is changed.
5646
5638
  this.updateBoxSelectionStyle = debounce(() => {
5647
5639
  // The editor has been unmounted.
5648
5640
  if (this.root.first().length === 0) {
@@ -5650,7 +5642,7 @@ class Editor {
5650
5642
  }
5651
5643
  const range = this.selection.range;
5652
5644
  const clonedRange = range.clone();
5653
- clonedRange.adaptBox();
5645
+ clonedRange.adjustBox();
5654
5646
  this.container.find('lake-box').each(boxNativeNode => {
5655
5647
  const box = getBox(boxNativeNode);
5656
5648
  const boxContainer = box.getContainer();
@@ -5693,6 +5685,7 @@ class Editor {
5693
5685
  trailing: true,
5694
5686
  maxWait: 50,
5695
5687
  });
5688
+ // Triggers the statechange event when the current selection of the editor is changed.
5696
5689
  this.emitStateChangeEvent = debounce(() => {
5697
5690
  const commandNames = this.command.getNames();
5698
5691
  let appliedItems = this.selection.getAppliedItems();
@@ -5739,13 +5732,6 @@ class Editor {
5739
5732
  trailing: true,
5740
5733
  maxWait: 100,
5741
5734
  });
5742
- this.emitChangeEvent = (value) => {
5743
- this.rectifyContent();
5744
- this.emitStateChangeEvent();
5745
- this.togglePlaceholderClass(value);
5746
- this.scrollToCaret();
5747
- this.event.emit('change', value);
5748
- };
5749
5735
  if (!config.root) {
5750
5736
  throw new Error('The root of the config must be specified.');
5751
5737
  }
@@ -5775,6 +5761,7 @@ class Editor {
5775
5761
  this.keystroke = new Keystroke(this.container);
5776
5762
  editors.set(this.container.id, this);
5777
5763
  }
5764
+ // Adds or Removes a placeholder class.
5778
5765
  togglePlaceholderClass(value) {
5779
5766
  value = denormalizeValue(value);
5780
5767
  const className = 'lake-show-placeholder';
@@ -5785,7 +5772,8 @@ class Editor {
5785
5772
  this.container.removeClass(className);
5786
5773
  }
5787
5774
  }
5788
- inputInBoxStrip() {
5775
+ // Moves the input text from box strip to normal position.
5776
+ moveBoxStripText() {
5789
5777
  const selection = this.selection;
5790
5778
  const range = selection.range;
5791
5779
  const stripNode = range.startNode.closest('.lake-box-strip');
@@ -5815,6 +5803,12 @@ class Editor {
5815
5803
  stripNode.html('<br />');
5816
5804
  selection.insertNode(document.createTextNode(text));
5817
5805
  }
5806
+ // Resets the value of unsaved input property.
5807
+ resetUnsavedInputData() {
5808
+ this.unsavedInputData = '';
5809
+ this.unsavedInputCount = 0;
5810
+ }
5811
+ // Binds events about input.
5818
5812
  bindInputEvents() {
5819
5813
  this.container.on('compositionstart', () => {
5820
5814
  this.isComposing = true;
@@ -5822,19 +5816,6 @@ class Editor {
5822
5816
  this.container.on('compositionend', () => {
5823
5817
  this.isComposing = false;
5824
5818
  });
5825
- this.container.on('beforeinput', event => {
5826
- const inputEvent = event;
5827
- const range = this.selection.range;
5828
- if (range.isBoxStart || range.isBoxEnd) {
5829
- this.commitUnsavedInputData();
5830
- return;
5831
- }
5832
- if (inputEvent.inputType === 'insertText' ||
5833
- inputEvent.inputType === 'insertCompositionText') {
5834
- return;
5835
- }
5836
- this.commitUnsavedInputData();
5837
- });
5838
5819
  this.container.on('input', event => {
5839
5820
  const inputEvent = event;
5840
5821
  // Here setTimeout is necessary because isComposing is not false after ending composition.
@@ -5850,7 +5831,7 @@ class Editor {
5850
5831
  return;
5851
5832
  }
5852
5833
  if (range.isBoxStart || range.isBoxEnd) {
5853
- this.inputInBoxStrip();
5834
+ this.moveBoxStripText();
5854
5835
  this.history.save();
5855
5836
  this.event.emit('input', inputEvent);
5856
5837
  return;
@@ -5858,30 +5839,60 @@ class Editor {
5858
5839
  if (inputEvent.inputType === 'insertText' ||
5859
5840
  inputEvent.inputType === 'insertCompositionText') {
5860
5841
  this.unsavedInputData += (_a = inputEvent.data) !== null && _a !== void 0 ? _a : '';
5842
+ this.unsavedInputCount++;
5861
5843
  if (this.unsavedInputData.length < this.config.minChangeSize) {
5862
- this.event.emit('input', inputEvent);
5863
- this.emitChangeEvent(this.getValue());
5864
- return;
5844
+ this.history.save({
5845
+ inputType: 'insertText',
5846
+ update: this.unsavedInputCount > 1,
5847
+ });
5865
5848
  }
5849
+ else {
5850
+ this.history.save({
5851
+ inputType: 'insertText',
5852
+ update: true,
5853
+ });
5854
+ this.resetUnsavedInputData();
5855
+ }
5856
+ this.event.emit('input', inputEvent);
5857
+ return;
5866
5858
  }
5867
5859
  this.history.save();
5868
5860
  this.event.emit('input', inputEvent);
5869
5861
  }, 0);
5870
5862
  });
5871
- this.command.event.on('beforeexecute', () => this.commitUnsavedInputData());
5872
5863
  }
5864
+ // Binds events about history.
5873
5865
  bindHistoryEvents() {
5866
+ const executeCommonMethods = (value) => {
5867
+ if (this.fixContent()) {
5868
+ this.history.save({
5869
+ update: true,
5870
+ emitEvent: false,
5871
+ });
5872
+ value = this.getValue();
5873
+ }
5874
+ this.emitStateChangeEvent();
5875
+ this.togglePlaceholderClass(value);
5876
+ this.scrollToCaret();
5877
+ this.event.emit('change', value);
5878
+ };
5874
5879
  this.history.event.on('undo', value => {
5875
- this.box.renderAll(this.container);
5876
- this.emitChangeEvent(value);
5880
+ this.renderBoxes();
5881
+ executeCommonMethods(value);
5882
+ this.resetUnsavedInputData();
5877
5883
  });
5878
5884
  this.history.event.on('redo', value => {
5879
- this.box.renderAll(this.container);
5880
- this.emitChangeEvent(value);
5885
+ this.renderBoxes();
5886
+ executeCommonMethods(value);
5887
+ this.resetUnsavedInputData();
5881
5888
  });
5882
- this.history.event.on('save', value => {
5883
- this.box.rectifyInstances(this.container);
5884
- this.emitChangeEvent(value);
5889
+ this.history.event.on('save', (value, options) => {
5890
+ this.removeBoxGarbage();
5891
+ executeCommonMethods(value);
5892
+ this.selection.sync();
5893
+ if (options.inputType !== 'insertText') {
5894
+ this.resetUnsavedInputData();
5895
+ }
5885
5896
  });
5886
5897
  }
5887
5898
  // Returns a boolean value indicating whether the editor has focus.
@@ -5897,65 +5908,76 @@ class Editor {
5897
5908
  return i18nObject(this.config.lang);
5898
5909
  }
5899
5910
  // Fixes wrong content, especially empty tag.
5900
- rectifyContent() {
5911
+ fixContent() {
5912
+ let changed = false;
5901
5913
  let children = this.container.children();
5902
5914
  for (const child of children) {
5903
5915
  if ((child.isBlock || child.isMark) && child.html() === '') {
5904
5916
  child.remove();
5905
- debug('Rectifying content: empty tag was removed');
5917
+ changed = true;
5918
+ debug(`Content fixed: empty tag "${child.name}" was removed`);
5906
5919
  }
5907
5920
  }
5908
5921
  children = this.container.children();
5909
5922
  if (children.length === 0) {
5910
5923
  this.container.html('<p><br /></p>');
5911
5924
  this.selection.range.shrinkAfter(this.container);
5912
- debug('Rectifying content: default paragraph was added');
5913
- return;
5925
+ changed = true;
5926
+ debug('Content fixed: default paragraph was added');
5914
5927
  }
5915
- if (children.length === 1) {
5928
+ else if (children.length === 1) {
5916
5929
  const child = children[0];
5917
5930
  if (child.isVoid) {
5918
5931
  const paragraph = query('<p />');
5919
5932
  child.before(paragraph);
5920
5933
  paragraph.append(child);
5921
5934
  this.selection.range.shrinkAfter(paragraph);
5922
- debug('Rectifying content: void element was wrapped in paragraph');
5935
+ changed = true;
5936
+ debug(`Content fixed: void element "${child.name}" was wrapped in paragraph`);
5923
5937
  }
5924
5938
  }
5925
- }
5926
- // Saves the input data which is unsaved.
5927
- commitUnsavedInputData() {
5928
- if (this.unsavedInputData.length > 0) {
5929
- this.history.save(false);
5930
- this.unsavedInputData = '';
5931
- }
5932
- }
5933
- // Updates some state before custom modifications.
5934
- prepareOperation() {
5935
- this.commitUnsavedInputData();
5936
- this.history.pause();
5937
- }
5938
- // Saves custom modifications to the history.
5939
- commitOperation() {
5940
- this.history.continue();
5941
- this.history.save();
5939
+ return changed;
5942
5940
  }
5943
5941
  // Sets default config for a plugin.
5944
- setPluginConfig(pluginName, pluginConfig) {
5945
- if (!this.config[pluginName]) {
5946
- this.config[pluginName] = {};
5942
+ setPluginConfig(name, config) {
5943
+ if (!this.config[name]) {
5944
+ this.config[name] = {};
5945
+ }
5946
+ for (const key of Object.keys(config)) {
5947
+ if (this.config[name][key] === undefined) {
5948
+ this.config[name][key] = config[key];
5949
+ }
5947
5950
  }
5948
- for (const key of Object.keys(pluginConfig)) {
5949
- if (this.config[pluginName][key] === undefined) {
5950
- this.config[pluginName][key] = pluginConfig[key];
5951
+ }
5952
+ // Removes all unused box instances.
5953
+ removeBoxGarbage() {
5954
+ const instanceMap = getInstanceMap(this.container.id);
5955
+ for (const box of instanceMap.values()) {
5956
+ if (!box.node.get(0).isConnected) {
5957
+ box.unmount();
5958
+ instanceMap.delete(box.node.id);
5951
5959
  }
5952
5960
  }
5953
5961
  }
5954
- // Sets focus on the editor area.
5962
+ // Renders all boxes that haven't been rendered yet.
5963
+ renderBoxes() {
5964
+ this.removeBoxGarbage();
5965
+ const container = this.container;
5966
+ const instanceMap = getInstanceMap(container.id);
5967
+ container.find('lake-box').each(boxNativeNode => {
5968
+ const boxNode = query(boxNativeNode);
5969
+ if (instanceMap.get(boxNode.id)) {
5970
+ return;
5971
+ }
5972
+ const box = getBox(boxNode);
5973
+ box.render();
5974
+ });
5975
+ }
5976
+ // Sets focus on the editor.
5955
5977
  focus() {
5956
5978
  this.container.focus();
5957
5979
  }
5958
- // Removes focus from the editor area.
5980
+ // Removes focus from the editor.
5959
5981
  blur() {
5960
5982
  this.container.blur();
5961
5983
  }
@@ -5963,6 +5985,9 @@ class Editor {
5963
5985
  scrollToCaret() {
5964
5986
  // Creates an artificial caret that is the same size as the caret at the current caret position.
5965
5987
  const rangeRect = this.selection.range.getRect();
5988
+ if (rangeRect.x === 0 || rangeRect.y === 0) {
5989
+ return;
5990
+ }
5966
5991
  const containerRect = this.container.get(0).getBoundingClientRect();
5967
5992
  const artificialCaret = query('<div class="lake-artificial-caret" />');
5968
5993
  const left = rangeRect.x - containerRect.x;
@@ -5978,48 +6003,20 @@ class Editor {
5978
6003
  });
5979
6004
  this.overlayContainer.find('.lake-artificial-caret').remove();
5980
6005
  this.overlayContainer.append(artificialCaret);
6006
+ const position = nodeAndView(artificialCaret);
5981
6007
  // Scrolls the artificial caret element into the visible area of the browser window
5982
6008
  // if it's not already within the visible area of the browser window.
5983
- // If the element is already within the visible area of the browser window, then no scrolling takes place.
5984
- let scrollX;
5985
- let scrollY;
5986
- let viewportWidth;
5987
- let viewportHeight;
5988
- const viewport = this.container.closestScroller();
5989
- if (viewport.length > 0) {
5990
- const nativeViewport = viewport.get(0);
5991
- const viewportRect = nativeViewport.getBoundingClientRect();
5992
- scrollX = nativeViewport.scrollLeft;
5993
- scrollY = nativeViewport.scrollTop;
5994
- viewportWidth = viewportRect.width;
5995
- viewportHeight = viewportRect.height;
5996
- }
5997
- else {
5998
- const nativeContainerWrapper = this.containerWrapper.get(0);
5999
- scrollX = window.scrollX;
6000
- scrollY = window.scrollY;
6001
- viewportWidth = window.innerWidth - nativeContainerWrapper.offsetLeft;
6002
- viewportHeight = window.innerHeight - nativeContainerWrapper.offsetTop;
6003
- }
6004
- let needScroll = false;
6005
- let alignToTop = true;
6006
- if (left < scrollX || left > scrollX + viewportWidth) {
6007
- needScroll = true;
6008
- }
6009
- if (top < scrollY) {
6010
- needScroll = true;
6011
- alignToTop = true;
6012
- }
6013
- else if (top > scrollY + viewportHeight) {
6014
- needScroll = true;
6015
- alignToTop = false;
6016
- }
6017
- if (needScroll) {
6018
- artificialCaret.get(0).scrollIntoView(alignToTop);
6009
+ // If the element is already within the visibposition.rightle area of the browser window, then no scrolling takes place.
6010
+ if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
6011
+ artificialCaret.get(0).scrollIntoView({
6012
+ behavior: 'instant',
6013
+ block: 'center',
6014
+ inline: 'nearest',
6015
+ });
6019
6016
  }
6020
6017
  artificialCaret.remove();
6021
6018
  }
6022
- // Sets the specified HTML string to the editor area.
6019
+ // Sets the specified value to the editor.
6023
6020
  setValue(value) {
6024
6021
  value = normalizeValue(value);
6025
6022
  const htmlParser = new HTMLParser(value);
@@ -6027,18 +6024,17 @@ class Editor {
6027
6024
  this.container.empty();
6028
6025
  this.togglePlaceholderClass(htmlParser.getHTML());
6029
6026
  this.container.append(fragment);
6030
- Editor.box.renderAll(this.container);
6027
+ this.renderBoxes();
6031
6028
  this.selection.updateByBookmark();
6032
6029
  }
6033
- // Returns the contents from the editor.
6030
+ // Returns the value of the editor.
6034
6031
  getValue() {
6035
- const bookmark = this.selection.insertBookmark();
6036
- let value = new HTMLParser(this.container).getHTML();
6032
+ const item = this.history.cloneContainer();
6033
+ let value = new HTMLParser(item).getHTML();
6037
6034
  value = denormalizeValue(value);
6038
- this.selection.toBookmark(bookmark);
6039
6035
  return value;
6040
6036
  }
6041
- // Renders an editor area and set default value to it.
6037
+ // Renders an editor area and sets default value to it.
6042
6038
  render() {
6043
6039
  const value = normalizeValue(this.config.value);
6044
6040
  const htmlParser = new HTMLParser(value);
@@ -6053,9 +6049,11 @@ class Editor {
6053
6049
  Editor.plugin.loadAll(this);
6054
6050
  if (!this.readonly) {
6055
6051
  this.selection.updateByBookmark();
6056
- this.history.save();
6052
+ this.history.save({
6053
+ emitEvent: false,
6054
+ });
6057
6055
  }
6058
- Editor.box.renderAll(this.container);
6056
+ this.renderBoxes();
6059
6057
  if (this.toolbar) {
6060
6058
  this.toolbar.render(this);
6061
6059
  }
@@ -6063,7 +6061,6 @@ class Editor {
6063
6061
  if (!this.readonly) {
6064
6062
  document.addEventListener('cut', this.cutListener);
6065
6063
  document.addEventListener('paste', this.pasteListener);
6066
- window.addEventListener('beforeunload', this.beforeunloadListener);
6067
6064
  document.addEventListener('selectionchange', this.selectionchangeListener);
6068
6065
  document.addEventListener('click', this.clickListener);
6069
6066
  window.addEventListener('resize', this.resizeListener);
@@ -6071,10 +6068,9 @@ class Editor {
6071
6068
  this.bindHistoryEvents();
6072
6069
  }
6073
6070
  }
6074
- // Destroys a rendered editor.
6071
+ // Destroys the rendered editor.
6075
6072
  unmount() {
6076
6073
  this.event.removeAllListeners();
6077
- this.command.event.removeAllListeners();
6078
6074
  this.history.event.removeAllListeners();
6079
6075
  this.root.empty();
6080
6076
  this.popupContainer.remove();
@@ -6082,7 +6078,6 @@ class Editor {
6082
6078
  if (!this.readonly) {
6083
6079
  document.removeEventListener('cut', this.cutListener);
6084
6080
  document.removeEventListener('paste', this.pasteListener);
6085
- window.removeEventListener('beforeunload', this.beforeunloadListener);
6086
6081
  document.removeEventListener('selectionchange', this.selectionchangeListener);
6087
6082
  document.removeEventListener('click', this.clickListener);
6088
6083
  window.removeEventListener('resize', this.resizeListener);
@@ -7131,7 +7126,6 @@ function appendButtonGroup(box) {
7131
7126
  event.stopPropagation();
7132
7127
  editor.selection.removeBox(box);
7133
7128
  editor.history.save();
7134
- editor.selection.sync();
7135
7129
  });
7136
7130
  videoNode.append(buttonGroupNode);
7137
7131
  }
@@ -7853,7 +7847,6 @@ const imageBox = {
7853
7847
  }
7854
7848
  editor.selection.removeBox(box);
7855
7849
  editor.history.save();
7856
- editor.selection.sync();
7857
7850
  });
7858
7851
  }
7859
7852
  box.event.emit('render');
@@ -7890,7 +7883,6 @@ const boxToolbarItems = [
7890
7883
  }
7891
7884
  editor.selection.removeBox(box);
7892
7885
  editor.history.save();
7893
- editor.selection.sync();
7894
7886
  },
7895
7887
  },
7896
7888
  ];
@@ -7970,7 +7962,11 @@ var copy = (editor) => {
7970
7962
  if (range.isInsideBox) {
7971
7963
  return;
7972
7964
  }
7973
- const boxNode = range.startNode.closest('lake-box');
7965
+ if (!range.isCollapsed) {
7966
+ range.adjust();
7967
+ return;
7968
+ }
7969
+ const boxNode = range.commonAncestor.closest('lake-box');
7974
7970
  if (boxNode.length === 0) {
7975
7971
  return;
7976
7972
  }
@@ -7992,12 +7988,26 @@ var cut = (editor) => {
7992
7988
  if (editor.readonly) {
7993
7989
  return;
7994
7990
  }
7995
- editor.event.on('cut', event => {
7991
+ editor.event.on('cut', (event) => {
7992
+ const dataTransfer = event.clipboardData;
7993
+ if (!dataTransfer) {
7994
+ return;
7995
+ }
7996
7996
  const range = editor.selection.range;
7997
7997
  if (range.isInsideBox) {
7998
7998
  return;
7999
7999
  }
8000
- const boxNode = range.startNode.closest('lake-box');
8000
+ if (!range.isCollapsed) {
8001
+ event.preventDefault();
8002
+ const fragment = editor.selection.range.cloneContents();
8003
+ const tempContainer = query('<div />');
8004
+ tempContainer.append(fragment);
8005
+ dataTransfer.setData('text/html', tempContainer.html());
8006
+ editor.selection.deleteContents();
8007
+ editor.history.save();
8008
+ return;
8009
+ }
8010
+ const boxNode = range.commonAncestor.closest('lake-box');
8001
8011
  if (boxNode.length === 0) {
8002
8012
  return;
8003
8013
  }
@@ -8005,10 +8015,6 @@ var cut = (editor) => {
8005
8015
  return;
8006
8016
  }
8007
8017
  event.preventDefault();
8008
- const dataTransfer = event.clipboardData;
8009
- if (!dataTransfer) {
8010
- return;
8011
- }
8012
8018
  const box = getBox(boxNode);
8013
8019
  const content = box.getHTML();
8014
8020
  dataTransfer.setData('text/html', content);
@@ -8130,6 +8136,14 @@ function insertFirstNode(editor, otherNode) {
8130
8136
  }
8131
8137
  const nextSibling = child.next();
8132
8138
  editor.selection.insertNode(child);
8139
+ if (child.isBox) {
8140
+ getBox(child).render();
8141
+ }
8142
+ else if (child.isElement) {
8143
+ child.find('lake-box').each(node => {
8144
+ getBox(node).render();
8145
+ });
8146
+ }
8133
8147
  child = nextSibling;
8134
8148
  }
8135
8149
  otherNode.remove();
@@ -8167,6 +8181,7 @@ function pasteFragment(editor, fragment) {
8167
8181
  parts.end.remove();
8168
8182
  }
8169
8183
  selection.insertFragment(fragment);
8184
+ editor.renderBoxes();
8170
8185
  range.shrinkAfter(lastNode);
8171
8186
  }
8172
8187
  fixNumberedList(editor.container.children().filter(node => node.isBlock));
@@ -8219,7 +8234,6 @@ var paste = (editor) => {
8219
8234
  editor.event.emit('beforepaste', fragment);
8220
8235
  fixClipboardData(fragment);
8221
8236
  pasteFragment(editor, fragment);
8222
- editor.box.renderAll(editor.container);
8223
8237
  });
8224
8238
  };
8225
8239
 
@@ -8560,7 +8574,6 @@ var list = (editor) => {
8560
8574
  }
8561
8575
  }
8562
8576
  editor.history.save();
8563
- editor.selection.sync();
8564
8577
  },
8565
8578
  });
8566
8579
  editor.container.on('click', event => {
@@ -9172,14 +9185,12 @@ var link = (editor) => {
9172
9185
  const range = editor.selection.range;
9173
9186
  range.setStartAfter(node);
9174
9187
  range.collapseToStart();
9175
- editor.selection.sync();
9176
9188
  editor.history.save();
9177
9189
  },
9178
9190
  onRemove: node => {
9179
9191
  const range = editor.selection.range;
9180
9192
  range.setStartAfter(node);
9181
9193
  range.collapseToStart();
9182
- editor.selection.sync();
9183
9194
  editor.history.save();
9184
9195
  },
9185
9196
  });
@@ -9560,7 +9571,7 @@ function executeMarkCommand(editor, point) {
9560
9571
  // <p>foobold\u200B<focus /></p>,
9561
9572
  // to
9562
9573
  // <p>foo[bold]\u200B<focus /></p>, startOffset = 3, endOffset = 7
9563
- editor.prepareOperation();
9574
+ editor.history.pause();
9564
9575
  const bookmark = selection.insertBookmark();
9565
9576
  const node = bookmark.focus.prev();
9566
9577
  const oldValue = node.text();
@@ -9570,7 +9581,8 @@ function executeMarkCommand(editor, point) {
9570
9581
  range.setEnd(node, offset - (oldValue.length - newValue.length) - 1);
9571
9582
  editor.command.execute(commandName, ...parameters);
9572
9583
  selection.toBookmark(bookmark);
9573
- editor.commitOperation();
9584
+ editor.history.continue();
9585
+ editor.history.save();
9574
9586
  return true;
9575
9587
  }
9576
9588
  }
@@ -9592,16 +9604,14 @@ function spaceKeyExecutesBlockCommand(editor, point) {
9592
9604
  // <p>#<focus />foo</p>
9593
9605
  // to
9594
9606
  // <h1><focus />foo</h1>
9595
- editor.prepareOperation();
9596
9607
  const bookmark = selection.insertBookmark();
9597
9608
  const node = bookmark.focus.prev();
9598
9609
  node.remove();
9599
9610
  const block = bookmark.focus.closestBlock();
9600
9611
  fixEmptyBlock(block);
9601
9612
  selection.range.shrinkAfter(block);
9602
- editor.command.execute(commandName, ...parameters);
9603
9613
  selection.toBookmark(bookmark);
9604
- editor.commitOperation();
9614
+ editor.command.execute(commandName, ...parameters);
9605
9615
  return true;
9606
9616
  }
9607
9617
  }
@@ -9622,12 +9632,10 @@ function enterKeyExecutesBlockCommand(editor, block) {
9622
9632
  // <p>---<focus /></p>
9623
9633
  // to
9624
9634
  // <lake-box type="block" name="hr" focus="end"></lake-box>
9625
- editor.prepareOperation();
9626
9635
  block.empty();
9627
9636
  fixEmptyBlock(block);
9628
9637
  selection.range.shrinkAfter(block);
9629
9638
  editor.command.execute(commandName, ...parameters);
9630
- editor.commitOperation();
9631
9639
  return true;
9632
9640
  }
9633
9641
  }
@@ -9748,13 +9756,13 @@ var enterKey = (editor) => {
9748
9756
  return;
9749
9757
  }
9750
9758
  event.preventDefault();
9751
- editor.rectifyContent();
9759
+ editor.fixContent();
9752
9760
  if (range.isBox) {
9753
9761
  addBlockOrSplitBlockForBox(editor);
9754
9762
  editor.history.save();
9755
9763
  return;
9756
9764
  }
9757
- range.adapt();
9765
+ range.adjust();
9758
9766
  if (range.isInoperative) {
9759
9767
  return;
9760
9768
  }
@@ -9833,14 +9841,14 @@ var shiftEnterKey = (editor) => {
9833
9841
  if (range.isInsideBox) {
9834
9842
  return;
9835
9843
  }
9836
- editor.rectifyContent();
9844
+ editor.fixContent();
9837
9845
  event.preventDefault();
9838
9846
  if (range.isBox) {
9839
9847
  addBlockOrLineBreakForBox(editor);
9840
9848
  editor.history.save();
9841
9849
  return;
9842
9850
  }
9843
- range.adapt();
9851
+ range.adjust();
9844
9852
  if (range.isInoperative) {
9845
9853
  return;
9846
9854
  }
@@ -9854,6 +9862,14 @@ var shiftEnterKey = (editor) => {
9854
9862
  });
9855
9863
  };
9856
9864
 
9865
+ function removeEmptyMarks(range) {
9866
+ const block = range.getBlocks()[0];
9867
+ if (block && block.isEmpty && block.first().name !== 'br') {
9868
+ block.empty();
9869
+ appendDeepest(block, query('<br />'));
9870
+ range.shrinkAfter(block);
9871
+ }
9872
+ }
9857
9873
  function mergeWithPreviousBlock(editor, block) {
9858
9874
  const range = editor.selection.range;
9859
9875
  let prevBlock = block.prev();
@@ -9884,6 +9900,7 @@ function mergeWithPreviousBlock(editor, block) {
9884
9900
  prevBlock.remove();
9885
9901
  return;
9886
9902
  }
9903
+ removeEmptyMarks(range);
9887
9904
  const bookmark = editor.selection.insertBookmark();
9888
9905
  mergeNodes(prevBlock, block);
9889
9906
  editor.selection.toBookmark(bookmark);
@@ -9896,9 +9913,17 @@ var backspaceKey = (editor) => {
9896
9913
  editor.keystroke.setKeydown('backspace', event => {
9897
9914
  const range = editor.selection.range;
9898
9915
  if (range.isInsideBox) {
9916
+ const boxNode = range.commonAncestor.closest('lake-box');
9917
+ const box = getBox(boxNode);
9918
+ const boxValue = box.value;
9919
+ if (box.name === 'codeBlock' && (boxValue.code === undefined || boxValue.code === '')) {
9920
+ event.preventDefault();
9921
+ editor.selection.removeBox(box);
9922
+ editor.history.save();
9923
+ }
9899
9924
  return;
9900
9925
  }
9901
- editor.rectifyContent();
9926
+ editor.fixContent();
9902
9927
  if (range.isBoxStart) {
9903
9928
  const boxNode = range.startNode.closest('lake-box');
9904
9929
  const prevNode = boxNode.prev();
@@ -9929,7 +9954,7 @@ var backspaceKey = (editor) => {
9929
9954
  editor.history.save();
9930
9955
  return;
9931
9956
  }
9932
- range.adaptBox();
9957
+ range.adjustBox();
9933
9958
  }
9934
9959
  if (range.isBox) {
9935
9960
  event.preventDefault();
@@ -9946,7 +9971,7 @@ var backspaceKey = (editor) => {
9946
9971
  editor.history.save();
9947
9972
  return;
9948
9973
  }
9949
- range.adapt();
9974
+ range.adjust();
9950
9975
  const prevNode = range.getPrevNode();
9951
9976
  if (prevNode.isBox) {
9952
9977
  event.preventDefault();
@@ -9954,7 +9979,7 @@ var backspaceKey = (editor) => {
9954
9979
  editor.history.save();
9955
9980
  return;
9956
9981
  }
9957
- if (prevNode.isText && prevNode.text().length === 1) {
9982
+ if (prevNode.isText && prevNode.text().length === 1 && prevNode.parent().isBlock) {
9958
9983
  event.preventDefault();
9959
9984
  const block = prevNode.closestBlock();
9960
9985
  range.setStartBefore(prevNode);
@@ -10036,7 +10061,7 @@ var deleteKey = (editor) => {
10036
10061
  if (range.isInsideBox) {
10037
10062
  return;
10038
10063
  }
10039
- editor.rectifyContent();
10064
+ editor.fixContent();
10040
10065
  if (range.isBoxEnd) {
10041
10066
  const boxNode = range.startNode.closest('lake-box');
10042
10067
  const nextNode = boxNode.next();
@@ -10061,7 +10086,7 @@ var deleteKey = (editor) => {
10061
10086
  range.shrinkBefore(nextNode);
10062
10087
  return;
10063
10088
  }
10064
- range.adaptBox();
10089
+ range.adjustBox();
10065
10090
  }
10066
10091
  if (range.isBox) {
10067
10092
  event.preventDefault();
@@ -10078,7 +10103,7 @@ var deleteKey = (editor) => {
10078
10103
  editor.history.save();
10079
10104
  return;
10080
10105
  }
10081
- range.adapt();
10106
+ range.adjust();
10082
10107
  const nextNode = range.getNextNode();
10083
10108
  if (nextNode.isBox) {
10084
10109
  event.preventDefault();