lakelib 0.1.17 → 0.1.19

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
@@ -126,13 +126,13 @@ lake-box {
126
126
  margin: 0;
127
127
  padding: 0;
128
128
  text-indent: 0;
129
- grid-template-columns: 1px 1fr 1px;
130
129
  }
131
130
  lake-box[type="inline"] {
132
- display: inline grid;
131
+ display: inline flex;
133
132
  }
134
133
  lake-box[type="block"] {
135
134
  display: block grid;
135
+ grid-template-columns: 1px 1fr 1px;
136
136
  }
137
137
  lake-box .lake-box-strip {
138
138
  display: block;
package/lib/lake.js CHANGED
@@ -663,10 +663,18 @@ class Nodes {
663
663
  }
664
664
  const nodeText = this.text();
665
665
  const isEmptyText = nodeText === '' || /^[\r\n\u200B\u2060]+$/.test(nodeText);
666
- if (this.isElement && isEmptyText) {
667
- return this.find('lake-box').length === 0;
666
+ if (!isEmptyText) {
667
+ return false;
668
668
  }
669
- return isEmptyText;
669
+ if (this.isElement) {
670
+ if (this.find('lake-box').length > 0) {
671
+ return false;
672
+ }
673
+ if (this.find('br').length > 1) {
674
+ return false;
675
+ }
676
+ }
677
+ return true;
670
678
  }
671
679
  // Returns a boolean value indicating whether the node and the target node are siblings.
672
680
  isSibling(target) {
@@ -1406,7 +1414,7 @@ class Range {
1406
1414
  const height = rect.height;
1407
1415
  return DOMRect.fromRect({
1408
1416
  x,
1409
- y: rect.y,
1417
+ y: height > 0 ? rect.y : 0,
1410
1418
  width: width > 0 ? width : 1,
1411
1419
  height: height > 0 ? height : 1,
1412
1420
  });
@@ -1560,6 +1568,7 @@ class Range {
1560
1568
  this.setEnd(child, child.children().length);
1561
1569
  }
1562
1570
  this.collapseToEnd();
1571
+ this.adjustBr();
1563
1572
  }
1564
1573
  // Reduces the boundary of the range.
1565
1574
  // <div>[<p><strong>foo</strong></p>]</div>
@@ -1663,6 +1672,21 @@ class Range {
1663
1672
  this.adjustTable();
1664
1673
  this.adjustBlock();
1665
1674
  }
1675
+ // Relocates the start and end points of the range for <br /> element.
1676
+ // In composition mode (e.g., when a user starts entering a Chinese character using a Pinyin IME),
1677
+ // uncompleted text is inserted if the caret is positioned behind a <br> tag.
1678
+ // To fix this bug, the caret needs to be moved to the front of the <br> tag.
1679
+ adjustBr() {
1680
+ if (!this.isCollapsed) {
1681
+ return;
1682
+ }
1683
+ const prevNode = this.getPrevNode();
1684
+ const nextNode = this.getNextNode();
1685
+ if (prevNode.name === 'br' && nextNode.length === 0) {
1686
+ this.setStartBefore(prevNode);
1687
+ this.collapseToStart();
1688
+ }
1689
+ }
1666
1690
  // Returns the previous node of the beginning point of the range.
1667
1691
  getPrevNode() {
1668
1692
  let prevNode;
@@ -1899,31 +1923,36 @@ function splitNodes(node, offset, limitNode) {
1899
1923
  };
1900
1924
  }
1901
1925
 
1902
- // Appends a node to the deepest element of the specified element.
1903
- function appendDeepest(element, node) {
1904
- let child = element;
1905
- while (child.length > 0) {
1906
- let firstChild = child.first();
1907
- while (firstChild.isText && firstChild.isEmpty) {
1908
- firstChild = firstChild.next();
1909
- }
1910
- if (child.isText || child.isBox) {
1911
- break;
1912
- }
1913
- if (child.isElement && child.children().length === 1 && firstChild.isBookmark) {
1914
- child.prepend(node);
1915
- break;
1916
- }
1917
- if (child.isElement && !child.isVoid && firstChild.length === 0) {
1918
- child.append(node);
1926
+ // Appends a line break to the end of a block.
1927
+ // Example:
1928
+ // case 1: <p></p> to <p><br /></p>
1929
+ // case 2: <p><br /></p> to <p><br /></p>
1930
+ // case 3: <p>foo</p> to <p>foo<br /></p>
1931
+ // case 4: <ul><li></li></ul> to <ul><li><br /></li></ul>
1932
+ // case 5: <p><focus /></p> to <p><focus /><br /></p>
1933
+ function appendBreak(block) {
1934
+ const breakNode = query('<br />');
1935
+ let child = block;
1936
+ while (child.isBlock) {
1937
+ let lastChild = child.last();
1938
+ while (lastChild.isText && lastChild.isEmpty) {
1939
+ lastChild = lastChild.prev();
1940
+ }
1941
+ if (!lastChild.isBlock && lastChild.name !== 'br') {
1942
+ child.append(breakNode);
1919
1943
  break;
1920
1944
  }
1921
- child = firstChild;
1945
+ child = lastChild;
1922
1946
  }
1947
+ return breakNode;
1923
1948
  }
1924
1949
 
1925
- // Removes The <br /> element in the specified block which is empty.
1926
- function removeBr(block) {
1950
+ // Removes a line break in the specified empty block.
1951
+ // Example:
1952
+ // case 1: <p><br /></p> to <p></p>
1953
+ // case 2: <p><br /><focus /></p> to <p><focus /></p>
1954
+ // case 3: <p><focus /><br /></p> to <p><focus /></p>
1955
+ function removeBreak(block) {
1927
1956
  if (block.length === 0) {
1928
1957
  return;
1929
1958
  }
@@ -1985,10 +2014,10 @@ function mergeNodes(node, otherNode) {
1985
2014
  if (node.isText || otherNode.isText || node.isVoid || otherNode.isVoid) {
1986
2015
  return getAfterPoint(node);
1987
2016
  }
1988
- removeBr(node);
1989
- removeBr(otherNode);
2017
+ removeBreak(node);
2018
+ removeBreak(otherNode);
1990
2019
  if (node.isBlock && node.isEmpty && otherNode.isEmpty) {
1991
- appendDeepest(node, query('<br />'));
2020
+ appendBreak(node);
1992
2021
  }
1993
2022
  const nextNode = node.last();
1994
2023
  const nextOtherNode = otherNode.first();
@@ -2016,7 +2045,7 @@ function mergeNodes(node, otherNode) {
2016
2045
  }
2017
2046
 
2018
2047
  // Returns the deepest element of the specified element.
2019
- function getDeepest(element) {
2048
+ function getDeepElement(element) {
2020
2049
  let child = element;
2021
2050
  while (child.length > 0) {
2022
2051
  let firstChild = child.first();
@@ -2037,7 +2066,7 @@ function wrapNodeList(nodeList, wrapper) {
2037
2066
  return wrapper;
2038
2067
  }
2039
2068
  wrapper = wrapper.clone(true);
2040
- const deepestElement = getDeepest(wrapper);
2069
+ const deepestElement = getDeepElement(wrapper);
2041
2070
  nodeList[0].before(wrapper);
2042
2071
  for (const node of nodeList) {
2043
2072
  deepestElement.append(node);
@@ -3967,7 +3996,7 @@ function uploadFile(config) {
3967
3996
 
3968
3997
  var index = /*#__PURE__*/Object.freeze({
3969
3998
  __proto__: null,
3970
- appendDeepest: appendDeepest,
3999
+ appendBreak: appendBreak,
3971
4000
  camelCase: camelCase,
3972
4001
  changeTagName: changeTagName,
3973
4002
  debug: debug,
@@ -3978,7 +4007,7 @@ var index = /*#__PURE__*/Object.freeze({
3978
4007
  fromBase64: fromBase64,
3979
4008
  getBox: getBox,
3980
4009
  getCSS: getCSS,
3981
- getDeepest: getDeepest,
4010
+ getDeepElement: getDeepElement,
3982
4011
  inString: inString,
3983
4012
  mergeNodes: mergeNodes,
3984
4013
  modifierText: modifierText,
@@ -3987,7 +4016,7 @@ var index = /*#__PURE__*/Object.freeze({
3987
4016
  normalizeValue: normalizeValue,
3988
4017
  parseStyle: parseStyle,
3989
4018
  query: query,
3990
- removeBr: removeBr,
4019
+ removeBreak: removeBreak,
3991
4020
  removeZWS: removeZWS,
3992
4021
  request: request,
3993
4022
  safeTemplate: safeTemplate,
@@ -4036,7 +4065,7 @@ class Fragment {
4036
4065
 
4037
4066
  const blockAttributeRules = {
4038
4067
  id: /^[\w-]+$/,
4039
- class: /^[\w-]+$/,
4068
+ class: /^[\w- ]+$/,
4040
4069
  style: {
4041
4070
  'text-align': ['left', 'center', 'right', 'justify', 'start', 'end'],
4042
4071
  'margin-left': /^-?\d+px$/i,
@@ -4109,7 +4138,7 @@ function getElementRules() {
4109
4138
  },
4110
4139
  },
4111
4140
  span: {
4112
- class: /^[\w-]+$/,
4141
+ class: /^[\w- ]+$/,
4113
4142
  style: {
4114
4143
  color: /^[^"]+$/,
4115
4144
  'background-color': /^[^"]+$/,
@@ -4127,7 +4156,7 @@ function getElementRules() {
4127
4156
  sup: {},
4128
4157
  code: {},
4129
4158
  a: {
4130
- class: /^[\w-]+$/,
4159
+ class: /^[\w- ]+$/,
4131
4160
  name: /^[\w-]+$/,
4132
4161
  href: /^[^"]+$/,
4133
4162
  target: /^[\w-]+$/,
@@ -4502,8 +4531,9 @@ function deleteContents(range) {
4502
4531
  if (noMerge) {
4503
4532
  const block = range.getBlocks()[0];
4504
4533
  if (block && block.isEmpty) {
4505
- appendDeepest(block, query('<br />'));
4506
- range.shrinkAfter(block);
4534
+ const breakNode = appendBreak(block);
4535
+ range.setStartBefore(breakNode);
4536
+ range.collapseToStart();
4507
4537
  }
4508
4538
  return;
4509
4539
  }
@@ -4536,7 +4566,7 @@ function insertFragment(range, fragment) {
4536
4566
  deleteContents(range);
4537
4567
  }
4538
4568
  const block = range.startNode.closestBlock();
4539
- removeBr(block);
4569
+ removeBreak(block);
4540
4570
  const bookmark = insertBookmark(range);
4541
4571
  bookmark.focus.before(fragment);
4542
4572
  toBookmark(range, bookmark);
@@ -4607,7 +4637,7 @@ function setBlocks(range, value) {
4607
4637
  if (block.isList && node.isList && node.attr('indent') !== '') {
4608
4638
  block.attr('indent', node.attr('indent'));
4609
4639
  }
4610
- const deepestBlock = getDeepest(block);
4640
+ const deepestBlock = getDeepElement(block);
4611
4641
  let child = node.first();
4612
4642
  while (child.length > 0) {
4613
4643
  const nextNode = child.next();
@@ -4631,8 +4661,9 @@ function setBlocks(range, value) {
4631
4661
  toBookmark(range, bookmark);
4632
4662
  fixList(range);
4633
4663
  if (block.isEmpty) {
4634
- appendDeepest(block, query('<br />'));
4635
- range.shrinkAfter(block);
4664
+ const breakNode = appendBreak(block);
4665
+ range.setStartBefore(breakNode);
4666
+ range.collapseToStart();
4636
4667
  }
4637
4668
  }
4638
4669
 
@@ -4683,16 +4714,13 @@ function splitBlock$1(range) {
4683
4714
  }
4684
4715
  }
4685
4716
  if (start && start.isEmpty) {
4686
- appendDeepest(start, query('<br />'));
4717
+ appendBreak(start);
4687
4718
  }
4688
4719
  if (end) {
4689
4720
  if (end.isEmpty) {
4690
- appendDeepest(end, query('<br />'));
4691
- range.shrinkAfter(end);
4692
- }
4693
- else {
4694
- range.shrinkBefore(end);
4721
+ appendBreak(end);
4695
4722
  }
4723
+ range.shrinkBefore(end);
4696
4724
  }
4697
4725
  fixList(range);
4698
4726
  return {
@@ -4864,7 +4892,7 @@ function addMark(range, value) {
4864
4892
  }
4865
4893
  }
4866
4894
  const block = range.startNode.closestBlock();
4867
- removeBr(block);
4895
+ removeBreak(block);
4868
4896
  // https://en.wikipedia.org/wiki/Zero-width_space
4869
4897
  const zeroWidthSpace = new Nodes(document.createTextNode('\u200B'));
4870
4898
  const parts = splitMarks(range);
@@ -4876,7 +4904,8 @@ function addMark(range, value) {
4876
4904
  valueNode = newMark;
4877
4905
  }
4878
4906
  else {
4879
- appendDeepest(newMark, zeroWidthSpace);
4907
+ const deepestMark = getDeepElement(newMark);
4908
+ deepestMark.append(zeroWidthSpace);
4880
4909
  valueNode.append(newMark);
4881
4910
  }
4882
4911
  }
@@ -4986,7 +5015,8 @@ function removeMark(range, value) {
4986
5015
  range.collapseToStart();
4987
5016
  return;
4988
5017
  }
4989
- appendDeepest(newMark, zeroWidthSpace);
5018
+ const deepestMark = getDeepElement(newMark);
5019
+ deepestMark.append(zeroWidthSpace);
4990
5020
  parts.start.after(newMark);
4991
5021
  removeEmptyMarks$1(parts.start);
4992
5022
  range.shrinkAfter(newMark);
@@ -5019,7 +5049,7 @@ function insertLink(range, value) {
5019
5049
  if (linkNode.length === 0) {
5020
5050
  linkNode = valueNode.clone(true);
5021
5051
  const block = range.startNode.closestBlock();
5022
- removeBr(block);
5052
+ removeBreak(block);
5023
5053
  insertNode(range, linkNode);
5024
5054
  return linkNode;
5025
5055
  }
@@ -5127,13 +5157,14 @@ function removeBox(range) {
5127
5157
  const parentNode = boxNode.parent();
5128
5158
  unmountBox(box);
5129
5159
  if (parentNode.isEmpty) {
5130
- appendDeepest(parentNode, query('<br />'));
5131
- range.shrinkAfter(parentNode);
5160
+ const breakNode = appendBreak(parentNode);
5161
+ range.setStartBefore(breakNode);
5162
+ range.collapseToStart();
5132
5163
  }
5133
5164
  return box;
5134
5165
  }
5135
5166
 
5136
- var version = "0.1.17";
5167
+ var version = "0.1.19";
5137
5168
 
5138
5169
  // Returns the attributes of the element as an key-value object.
5139
5170
  function getAttributes(node) {
@@ -5584,6 +5615,9 @@ class Keystroke {
5584
5615
  this.container = container;
5585
5616
  this.container.on('keydown', event => {
5586
5617
  const keyboardEvent = event;
5618
+ if (keyboardEvent.isComposing) {
5619
+ return;
5620
+ }
5587
5621
  for (const item of this.keydownEventList) {
5588
5622
  if (isKeyHotkey(item.type, keyboardEvent)) {
5589
5623
  if (item.listener(keyboardEvent) === false) {
@@ -5594,6 +5628,9 @@ class Keystroke {
5594
5628
  });
5595
5629
  this.container.on('keyup', event => {
5596
5630
  const keyboardEvent = event;
5631
+ if (keyboardEvent.isComposing) {
5632
+ return;
5633
+ }
5597
5634
  for (const item of this.keyupEventList) {
5598
5635
  if (isKeyHotkey(item.type, keyboardEvent)) {
5599
5636
  if (item.listener(keyboardEvent) === false) {
@@ -5909,7 +5946,8 @@ class Editor {
5909
5946
  else {
5910
5947
  boxNode.after(paragraph);
5911
5948
  }
5912
- range.shrinkAfter(paragraph);
5949
+ range.setStart(paragraph, 0);
5950
+ range.collapseToStart();
5913
5951
  }
5914
5952
  const text = stripNode.text();
5915
5953
  stripNode.html('<br />');
@@ -5928,18 +5966,6 @@ class Editor {
5928
5966
  this.container.on('compositionend', () => {
5929
5967
  this.isComposing = false;
5930
5968
  });
5931
- this.container.on('beforeinput', event => {
5932
- const inputEvent = event;
5933
- // <p><br /><focus /></p>
5934
- // When the caret is positioned behind a <br> tag, the input event is triggered twice after inserting a sharp(#) in composition mode.
5935
- if (this.isComposing && inputEvent.inputType === 'insertText') {
5936
- inputEvent.preventDefault();
5937
- this.isComposing = false;
5938
- this.history.save({
5939
- inputType: 'insertText',
5940
- });
5941
- }
5942
- });
5943
5969
  this.container.on('input', event => {
5944
5970
  const inputEvent = event;
5945
5971
  // Here setTimeout is necessary because isComposing is not false after ending composition.
@@ -6049,7 +6075,7 @@ class Editor {
6049
6075
  children = this.container.children();
6050
6076
  if (children.length === 0) {
6051
6077
  this.container.html('<p><br /></p>');
6052
- range.shrinkAfter(this.container);
6078
+ range.shrinkBefore(this.container);
6053
6079
  changed = true;
6054
6080
  debug('Content fixed: default paragraph was added');
6055
6081
  }
@@ -6064,18 +6090,7 @@ class Editor {
6064
6090
  debug(`Content fixed: void element "${child.name}" was wrapped in paragraph`);
6065
6091
  }
6066
6092
  }
6067
- // In composition mode (e.g., when a user starts entering a Chinese character using a Pinyin IME),
6068
- // uncompleted text is inserted if the caret is positioned behind a <br> tag.
6069
- // To fix this bug, the caret needs to be moved to the front of the <br> tag.
6070
- if (range.isCollapsed) {
6071
- const prevNode = range.getPrevNode();
6072
- const nextNode = range.getNextNode();
6073
- if (prevNode.name === 'br' && nextNode.length === 0) {
6074
- range.setStartBefore(prevNode);
6075
- range.collapseToStart();
6076
- debug('Range fixed: the caret has been moved to the front of the <br> tag');
6077
- }
6078
- }
6093
+ range.adjustBr();
6079
6094
  return changed;
6080
6095
  }
6081
6096
  // Sets default config for a plugin.
@@ -8312,7 +8327,7 @@ function insertFirstNode(editor, otherNode) {
8312
8327
  return;
8313
8328
  }
8314
8329
  if (otherNode.first().length > 0) {
8315
- removeBr(block);
8330
+ removeBreak(block);
8316
8331
  }
8317
8332
  if (block.isEmpty && block.name === 'p') {
8318
8333
  block.replaceWith(otherNode);
@@ -10104,8 +10119,9 @@ function removeEmptyMarks(range) {
10104
10119
  const block = range.getBlocks()[0];
10105
10120
  if (block && block.isEmpty && block.first().name !== 'br') {
10106
10121
  block.empty();
10107
- appendDeepest(block, query('<br />'));
10108
- range.shrinkAfter(block);
10122
+ const breakNode = appendBreak(block);
10123
+ range.setStartBefore(breakNode);
10124
+ range.collapseToStart();
10109
10125
  }
10110
10126
  }
10111
10127
  function mergeWithPreviousBlock(editor, block) {
@@ -10139,6 +10155,12 @@ function mergeWithPreviousBlock(editor, block) {
10139
10155
  return;
10140
10156
  }
10141
10157
  removeEmptyMarks(range);
10158
+ const nextNode = range.getNextNode();
10159
+ if (nextNode.name === 'br' && prevBlock.name !== 'p') {
10160
+ nextNode.remove();
10161
+ range.shrinkAfter(prevBlock);
10162
+ return;
10163
+ }
10142
10164
  const bookmark = editor.selection.insertBookmark();
10143
10165
  mergeNodes(prevBlock, block);
10144
10166
  editor.selection.toBookmark(bookmark);
@@ -10224,8 +10246,9 @@ var backspaceKey = (editor) => {
10224
10246
  range.collapseToStart();
10225
10247
  prevNode.remove();
10226
10248
  if (block.isEmpty) {
10227
- appendDeepest(block, query('<br />'));
10228
- range.shrinkAfter(block);
10249
+ const breakNode = appendBreak(block);
10250
+ range.setStartBefore(breakNode);
10251
+ range.collapseToStart();
10229
10252
  }
10230
10253
  editor.history.save();
10231
10254
  return;