@nerd-bible/wordgard 0.6.2-beta5 → 0.6.2-beta7

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/command.d.ts CHANGED
@@ -518,10 +518,10 @@ declare const enter: Command.Pure;
518
518
  /**
519
519
  Delete the selection, or the unit after or before the selection.
520
520
  If that unit is the start or end of a textblock, this will try to
521
- join that textblock to the next one. Otherwise, if it is a
522
- character or leaf node, that is deleted. If none of that is
523
- possible and the cursor is in an empty textblock, this will delete
524
- the textblock.
521
+ join that textblock to the next one. Otherwise, if the cursor is
522
+ in an empty textblock, this will delete the textblock. Finally, if
523
+ there is a character or leaf node in the given direction, that is
524
+ deleted.
525
525
 
526
526
  When deleting backward at the start of a list item that has a
527
527
  sibling before it, this command will try to join those list items.
@@ -709,9 +709,17 @@ declare const redo: Command;
709
709
 
710
710
  /**
711
711
  If the cursor is in an empty textblock that can be lifted out of a
712
- parent, return a transaction that does this.
712
+ parent, return a transaction that does this. Unless
713
+ `splitListItem` is set to false, if the block is part of a
714
+ continued list item, this function will split the item above the
715
+ block before it lifts it.
713
716
  */
714
- declare function liftEmptyBlock(state: GardState): Transaction.Spec | false;
717
+ declare function liftEmptyBlock(state: GardState, splitListItem?: boolean): Transaction.Spec | false;
718
+ /**
719
+ Lift the textblock that the cursor is at the start of out of its
720
+ innermost parent, if possible.
721
+ */
722
+ declare function liftTextblock(state: GardState): Transaction.Spec | false;
715
723
  /**
716
724
  If the selection is in a {@link Plot.Spec.preserveWhitespace
717
725
  `preserveWhitespace`} textblock, replace the selected content with
@@ -823,4 +831,4 @@ updated to perform those joins.
823
831
  */
824
832
  declare function autoJoinBlocks(state: GardState, tr: Transaction.Spec): Transaction.Spec;
825
833
 
826
- export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
834
+ export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, liftTextblock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
package/dist/command.js CHANGED
@@ -45,12 +45,27 @@ const Command = /*@__PURE__*/(function (Command) {
45
45
  Command.dispatch = dispatch;
46
46
  ;return Command})({});
47
47
 
48
- function liftEmptyBlock(state) {
48
+ function liftEmptyBlock(state, splitListItem = true) {
49
49
  if (!state.selection.isCursor)
50
50
  return false;
51
51
  let sel = state.sel, block = sel.head.textblockParent;
52
52
  if (!block || !sel.head.isAtStart(block) || !sel.head.isAtEnd(block))
53
53
  return false;
54
+ if (splitListItem && block.parent?.parent && block.index && block.parent.parent.node.type.hasRole(Node.Role.List))
55
+ return {
56
+ changes: { from: block.before, insert: [Plot.End, block.parent.node.tag] },
57
+ scrollIntoView: true,
58
+ userEvent: "split.list"
59
+ };
60
+ return liftBlock(state, block);
61
+ }
62
+ function liftTextblock(state) {
63
+ if (!state.selection.isCursor)
64
+ return false;
65
+ let { head } = state.sel, block = head.textblockParent;
66
+ return !block || !head.isAtStart(block) ? false : liftBlock(state, block);
67
+ }
68
+ function liftBlock(state, block) {
54
69
  let start = block.before, end = block.after, before = [], after = [];
55
70
  for (let level = block.parent, index = block.index, atStart = true, atEnd = true, first = true; level; first = false, index = level.index, level = level.parent) {
56
71
  if (!first && state.schema.canContain(level.node.type, block.node.type))
@@ -60,7 +75,7 @@ function liftEmptyBlock(state) {
60
75
  { from: block.after, to: end, insert: after }
61
76
  ],
62
77
  scrollIntoView: true,
63
- userEvent: "unwrap.empty"
78
+ userEvent: "unwrap"
64
79
  };
65
80
  if (level.node.isInline || level.node.type.isolating)
66
81
  break;
@@ -792,8 +807,8 @@ const deleteUnit = ({ state }, dir) => {
792
807
  if (state.readOnly)
793
808
  return false;
794
809
  return deleteSelection(state) || (dir == "forward"
795
- ? joinForward(state) || deleteForward(state) || deleteEmptyPlot(state, 1)
796
- : joinListItems(state) || joinBackward(state) || deleteBackward(state) || deleteEmptyPlot(state, -1));
810
+ ? joinForward(state) || deleteEmptyPlot(state, 1) || deleteForward(state)
811
+ : joinListItems(state) || liftTextblock(state) || joinBackward(state) || deleteEmptyPlot(state, -1) || deleteBackward(state));
797
812
  };
798
813
  const deleteWord = ({ state }, dir) => {
799
814
  if (state.readOnly)
@@ -1541,4 +1556,4 @@ const Menu = /*@__PURE__*/(function (Menu) {
1541
1556
  Menu.resolve = resolve;
1542
1557
  ;return Menu})({});
1543
1558
 
1544
- export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
1559
+ export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, liftTextblock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
package/dist/doc.js CHANGED
@@ -412,7 +412,7 @@ const Attributes = /*@__PURE__*/(function (Attributes) {
412
412
  score--;
413
413
  iA += 2;
414
414
  }
415
- else if (iB < b.length && iA == a.length) {
415
+ else if (iB < b.length) {
416
416
  score--;
417
417
  iB += 2;
418
418
  }
@@ -2399,6 +2399,36 @@ class ChangeSetBuilder {
2399
2399
  sections = [];
2400
2400
  data = [];
2401
2401
  pos = 0;
2402
+ addSection(from, to, ins, value) {
2403
+ if (from >= this.pos) {
2404
+ addSection(this.sections, this.data, from - this.pos, -1, null);
2405
+ addSection(this.sections, this.data, to - from, ins, value);
2406
+ this.pos = to;
2407
+ return true;
2408
+ }
2409
+ if (this.sections.length && this.sections[0] > to && this.sections[1] == -1) {
2410
+ this.spliceSection(0, from, to, ins, value);
2411
+ return true;
2412
+ }
2413
+ for (let pos = this.pos, i = this.sections.length; i > 2 && pos > to;) {
2414
+ let nextIns = this.sections[--i], nextLen = this.sections[--i];
2415
+ let start = pos - nextLen;
2416
+ if (nextIns == -1 && start < from) {
2417
+ this.spliceSection(i, from - start, to - start, ins, value);
2418
+ return true;
2419
+ }
2420
+ pos = start;
2421
+ }
2422
+ return false;
2423
+ }
2424
+ spliceSection(i, from, to, ins, value) {
2425
+ let sections = [], data = [];
2426
+ addSection(sections, data, from, -1, null);
2427
+ addSection(sections, data, to - from, ins, value);
2428
+ addSection(sections, data, this.sections[i] - to, -1, null);
2429
+ this.sections.splice(i, 2, ...sections);
2430
+ this.data.splice(i >> 1, 1, ...data);
2431
+ }
2402
2432
  }
2403
2433
  function sliceLen(tokens) {
2404
2434
  return tokens.reduce((l, e) => l + (e.tokenType == Token.Type.Node ? e.length : 1), 0);
@@ -2419,14 +2449,11 @@ function createChangeSet(doc, spec, mayCorrect = true) {
2419
2449
  accum = accum ? accum.compose(transform(set, accum, doc, false, false).set) : set;
2420
2450
  };
2421
2451
  let section = (from, to, ins, value) => {
2422
- if (!cur || from < cur.pos) {
2452
+ if (!cur?.addSection(from, to, ins, value)) {
2423
2453
  flush();
2424
2454
  cur = new ChangeSetBuilder(doc.length);
2455
+ cur.addSection(from, to, ins, value);
2425
2456
  }
2426
- if (from > cur.pos)
2427
- addSection(cur.sections, cur.data, from - cur.pos, -1, null);
2428
- addSection(cur.sections, cur.data, to - from, ins, value);
2429
- cur.pos = to;
2430
2457
  };
2431
2458
  let build = (spec) => {
2432
2459
  if (Array.isArray(spec)) {
package/dist/editor.d.ts CHANGED
@@ -375,10 +375,11 @@ declare const enum TileFlag {
375
375
  Composition = 128,
376
376
  Synced = 256,// Node has been synced. DOM content matches child list / text content, child array becomes read-only
377
377
  Atom = 512,// Composite tile whose length isn't determined by child length
378
- HasContent = 1024,// EltTile whose elt has a content hole
379
- AfterContent = 2048,// Tiles that sit after their parent's content position
380
- ContentNotLast = 4096,// EltTile that has children with AfterContent flag
381
- Dirty = 8192
378
+ Uneditable = 1024,// Tile's DOM is uneditable
379
+ HasContent = 2048,// EltTile whose elt has a content hole
380
+ AfterContent = 4096,// Tiles that sit after their parent's content position
381
+ ContentNotLast = 8192,// EltTile that has children with AfterContent flag
382
+ Dirty = 16384
382
383
  }
383
384
  declare const enum Orientation {
384
385
  Row = 0,
@@ -420,14 +421,15 @@ declare abstract class Tile {
420
421
  get boundary(): 0 | 1;
421
422
  get firstChild(): Tile | null;
422
423
  get lastChild(): Tile | null;
423
- get nodeParent(): Tile;
424
424
  ignoreEvent(event: Event): boolean;
425
425
  get ignoreMutations(): boolean;
426
426
  toString(): string;
427
427
  abstract sync(): void;
428
428
  connect(): void;
429
429
  disconnect(reused?: Map<Tile, Reused>): void;
430
- nearestNode(): Tile;
430
+ nearestNode(): Tile & {
431
+ tag: Node$1.Tag;
432
+ };
431
433
  markDirty(): void;
432
434
  posAtCoords(state: GardState, x: number, y: number): CoordPos;
433
435
  abstract posAtCoordsInner(start: number, state: GardState, x: number, y: number, textblock: TextblockMap | null, orientation: Orientation): CoordPos;
@@ -437,6 +439,7 @@ declare class CompositeTile extends Tile {
437
439
  children: Tile[];
438
440
  dom: Element;
439
441
  addChild(child: Tile): void;
442
+ putChild(child: Tile, index: number): void;
440
443
  sync(): void;
441
444
  syncChildren(): void;
442
445
  posAtCoordsInner(start: number, state: GardState, x: number, y: number, textblock: TextblockMap | null, orientation: Orientation): CoordPos;
package/dist/editor.js CHANGED
@@ -202,6 +202,14 @@ class Widget {
202
202
  },
203
203
  editable: true
204
204
  });
205
+ Widget.blockImg = Widget.create({
206
+ render() {
207
+ let img = document.createElement("img");
208
+ img.className = "wg-blockBuffer";
209
+ return img;
210
+ },
211
+ editable: true
212
+ });
205
213
  Widget.br = Widget.create({
206
214
  render() { return document.createElement("br"); },
207
215
  editable: true
@@ -735,7 +743,7 @@ class DecoIterator {
735
743
  else
736
744
  started = true;
737
745
  let hasPending = pendingPos == pos && !node.isText;
738
- let shape = hasPending && pendingShape ? pendingShape.shape : this.tagShape(node.tag, iter.active);
746
+ let shape = this.tagShape(node.tag, iter.active, hasPending ? pendingShape : null);
739
747
  if (hasPending)
740
748
  for (let deco of pendingDeco)
741
749
  shape = applyDeco(shape, deco, node.tag);
@@ -749,8 +757,7 @@ class DecoIterator {
749
757
  this.widgets(node.tag, 0, walker);
750
758
  else
751
759
  started = true;
752
- let shape = pendingShape && pendingPos == pos ? pendingShape.shape
753
- : this.tagShape(node.tag, iter.active);
760
+ let shape = this.tagShape(node.tag, iter.active, pendingShape && pendingPos == pos ? pendingShape : null);
754
761
  if (pendingPos == pos)
755
762
  for (let deco of pendingDeco)
756
763
  shape = applyDeco(shape, deco, node.tag);
@@ -829,9 +836,8 @@ class DecoIterator {
829
836
  }
830
837
  this.pos = pos;
831
838
  }
832
- tagShape(tag, active) {
833
- let override = this.tagShapes.get(tag.type);
834
- let shape = override ? override(tag) : baseTagShape(tag);
839
+ tagShape(tag, active, fromPoint) {
840
+ let shape = fromPoint ? fromPoint.shape : this.tagShapes.get(tag.type)?.(tag) ?? baseTagShape(tag);
835
841
  if (tag.marks.length)
836
842
  shape = addMarkAttributes(this.markShapes, shape, tag);
837
843
  let add;
@@ -1284,12 +1290,6 @@ class Tile {
1284
1290
  let last = this.children.length - 1;
1285
1291
  return last < 0 ? null : this.children[last];
1286
1292
  }
1287
- get nodeParent() {
1288
- let tile = this;
1289
- while (!tile.tag)
1290
- tile = tile.parent;
1291
- return tile;
1292
- }
1293
1293
  ignoreEvent(event) { return false; }
1294
1294
  get ignoreMutations() { return false; }
1295
1295
  toString() { return this.dom.nodeName + (this.children.length ? `(${this.children})` : ""); }
@@ -1309,8 +1309,8 @@ class Tile {
1309
1309
  return tile;
1310
1310
  }
1311
1311
  markDirty() {
1312
- if (!(this.flags & 8192)) {
1313
- this.flags |= 8192;
1312
+ if (!(this.flags & 16384)) {
1313
+ this.flags |= 16384;
1314
1314
  this.parent?.markDirty();
1315
1315
  }
1316
1316
  }
@@ -1321,10 +1321,10 @@ class Tile {
1321
1321
  static get(node) { return node.wgTile; }
1322
1322
  }
1323
1323
  function checkSync(tile) {
1324
- if ((tile.flags & 256) && !(tile.flags & 8192))
1324
+ if ((tile.flags & 256) && !(tile.flags & 16384))
1325
1325
  return false;
1326
1326
  tile.flags |= 256;
1327
- tile.flags &= -8193;
1327
+ tile.flags &= -16385;
1328
1328
  return true;
1329
1329
  }
1330
1330
  class CompositeTile extends Tile {
@@ -1332,9 +1332,9 @@ class CompositeTile extends Tile {
1332
1332
  addChild(child) {
1333
1333
  if (this.flags & 256)
1334
1334
  throw new Error("Cannot add to a synced tile");
1335
- if ((this.flags & 4096) && !(child.flags & 2048)) {
1335
+ if ((this.flags & 8192) && !(child.flags & 4096)) {
1336
1336
  let i = this.children.length;
1337
- while (i > 0 && (this.children[i - 1].flags & 2048))
1337
+ while (i > 0 && (this.children[i - 1].flags & 4096))
1338
1338
  i--;
1339
1339
  this.children.splice(i, 0, child);
1340
1340
  }
@@ -1343,6 +1343,10 @@ class CompositeTile extends Tile {
1343
1343
  }
1344
1344
  child.parent = this;
1345
1345
  }
1346
+ putChild(child, index) {
1347
+ this.children.splice(index, 0, child);
1348
+ child.parent = this;
1349
+ }
1346
1350
  sync() {
1347
1351
  if (!checkSync(this))
1348
1352
  return;
@@ -1633,7 +1637,7 @@ class DocTile extends CompositeTile {
1633
1637
  parentBefore = before;
1634
1638
  before = before.children[beforeI = before.children.length - 1];
1635
1639
  }
1636
- if (before.isNodeInner && (before.flags & 2048) || (before.flags & 64)) {
1640
+ if (before.isNodeInner && (before.flags & 4096) || (before.flags & 64)) {
1637
1641
  parent = parentBefore;
1638
1642
  i = beforeI;
1639
1643
  continue adjust;
@@ -1645,7 +1649,7 @@ class DocTile extends CompositeTile {
1645
1649
  parentAfter = after;
1646
1650
  after = after.children[afterI = 0];
1647
1651
  }
1648
- if (after.isNodeInner && !(after.flags & 2048) || (after.flags & 32)) {
1652
+ if (after.isNodeInner && !(after.flags & 4096) || (after.flags & 32)) {
1649
1653
  parent = parentAfter;
1650
1654
  i = afterI + 1;
1651
1655
  continue adjust;
@@ -1764,20 +1768,20 @@ class EltTile extends CompositeTile {
1764
1768
  get boundary() { return this._tag && !(this.flags & 512) ? 1 : 0; }
1765
1769
  get tag() { return this._tag; }
1766
1770
  get contentTile() {
1767
- if (!(this.flags & 1024))
1771
+ if (!(this.flags & 2048))
1768
1772
  return null;
1769
1773
  for (let ch of this.children)
1770
- if (ch.isNodeInner && (ch.flags & 1024))
1774
+ if (ch.isNodeInner && (ch.flags & 2048))
1771
1775
  return ch.contentTile;
1772
1776
  return this;
1773
1777
  }
1774
1778
  static of(elt, tag, flags, length, dom) {
1775
1779
  if (elt.hasContent) {
1776
- flags |= 1024;
1780
+ flags |= 2048;
1777
1781
  if (elt.children.length > 1) {
1778
1782
  let zero = elt.children.indexOf(0);
1779
1783
  if (zero > -1 && zero < elt.children.length - 1)
1780
- flags |= 4096;
1784
+ flags |= 8192;
1781
1785
  }
1782
1786
  }
1783
1787
  return new EltTile(elt, tag, flags, length, dom || elt.outerDOM());
@@ -1789,8 +1793,13 @@ function setUneditable(dom) {
1789
1793
  span.appendChild(dom);
1790
1794
  dom = span;
1791
1795
  }
1792
- if (dom.contentEditable == "inherit" && !/^(br|hr|img|input|wbr)$/i.test(dom.nodeName))
1793
- dom.contentEditable = "false";
1796
+ let cur = dom.contentEditable;
1797
+ if (cur == "false")
1798
+ return true;
1799
+ if (cur != "inherit" || !/^(br|hr|img|input|wbr)$/i.test(dom.nodeName))
1800
+ return false;
1801
+ dom.contentEditable = "false";
1802
+ return true;
1794
1803
  }
1795
1804
  class WidgetTile extends Tile {
1796
1805
  widget;
@@ -1949,7 +1958,12 @@ class TilePointer {
1949
1958
  let { tile, index } = this;
1950
1959
  if (tile.isAtom)
1951
1960
  return tile;
1952
- return index < tile.children.length ? tile.children[index] : null;
1961
+ for (; index < tile.children.length; index++) {
1962
+ let next = tile.children[index];
1963
+ if (!(next instanceof WidgetTile && (next.widget == Widget.blockImg || next.widget == Widget.br)))
1964
+ return next;
1965
+ }
1966
+ return null;
1953
1967
  }
1954
1968
  matchingWrapper(elt, spanning, reused) {
1955
1969
  let best, bestScore = 0;
@@ -1987,7 +2001,7 @@ class TilePointer {
1987
2001
  if (!before.isPoint)
1988
2002
  break;
1989
2003
  if (!reused.has(before) && before instanceof WidgetTile && before.widget.eq(widget) &&
1990
- (before.flags & 96) == sideFlag && !(before.flags & 8192)) {
2004
+ (before.flags & 96) == sideFlag && !(before.flags & 16384)) {
1991
2005
  reused.set(before, 1);
1992
2006
  return before;
1993
2007
  }
@@ -2073,7 +2087,7 @@ class ContentUpdate {
2073
2087
  else if (this.new.lastChild instanceof TextTile && !this.new.lastChild.isComposition) {
2074
2088
  this.addText(tile.text.slice(from, to));
2075
2089
  }
2076
- else if (!from && to == tile.text.length && !(tile.flags & 8192) && !this.reused.has(tile)) {
2090
+ else if (!from && to == tile.text.length && !(tile.flags & 16384) && !this.reused.has(tile)) {
2077
2091
  this.reused.set(tile, 1);
2078
2092
  this.new.addChild(tile);
2079
2093
  }
@@ -2242,7 +2256,7 @@ class ContentUpdate {
2242
2256
  if (!(next instanceof TextTile) || this.reused.has(next)) {
2243
2257
  this.addText(node.param);
2244
2258
  }
2245
- else if (next.text == node.param && !(next.flags & 8192)) {
2259
+ else if (next.text == node.param && !(next.flags & 16384)) {
2246
2260
  this.reused.set(next, 1);
2247
2261
  this.new.addChild(next);
2248
2262
  }
@@ -2290,9 +2304,10 @@ class ContentUpdate {
2290
2304
  : null;
2291
2305
  if (!tile) {
2292
2306
  let dom = widget.render(this.wg);
2293
- if (!widget.type.editable)
2294
- setUneditable(dom);
2295
- tile = new WidgetTile(widget, null, 16 | sideFlag, dom);
2307
+ let flags = 16 | sideFlag;
2308
+ if (!widget.type.editable && setUneditable(dom))
2309
+ flags |= 1024;
2310
+ tile = new WidgetTile(widget, null, flags, dom);
2296
2311
  if (widget.type.connect)
2297
2312
  this.toConnect.push(tile);
2298
2313
  }
@@ -2329,27 +2344,33 @@ class ContentUpdate {
2329
2344
  }
2330
2345
  buildNodeShape(tag, length, shape, reuse, inEditable = true, afterContent = 0) {
2331
2346
  if (shape instanceof Elt) {
2347
+ let flags = (tag ? (shape.hasContent ? 0 : 512)
2348
+ : 1 | (shape.hasContent ? 0 : 16)) | afterContent;
2332
2349
  if (inEditable && !shape.hasContent) {
2333
- if (Attributes.get(shape.attrs, "contenteditable") == null && !/^(br|hr|img|input|wbr)$/i.test(shape.tagName))
2350
+ let contentEd = Attributes.get(shape.attrs, "contenteditable");
2351
+ if (contentEd == null && !/^(br|hr|img|input|wbr)$/i.test(shape.tagName)) {
2334
2352
  shape = Elt.create(shape.tagName, Attributes.merge(shape.attrs, ["contenteditable", "false"]), shape.children);
2353
+ flags |= 1024;
2354
+ }
2355
+ else if (contentEd == "false") {
2356
+ flags |= 1024;
2357
+ }
2335
2358
  inEditable = false;
2336
2359
  }
2337
2360
  let reusable, dom, strict = true;
2338
2361
  if (reusable = this.findReusableTile(shape, reuse, strict) || this.findReusableTile(shape, reuse, strict = false)) {
2339
2362
  this.reused.set(reusable, 2);
2340
2363
  dom = reusable.dom;
2341
- if (reusable.flags & 8192)
2364
+ if (reusable.flags & 16384)
2342
2365
  updateAttributes(dom, takeAttributes(reusable.dom), shape.attrs);
2343
2366
  else if (!strict)
2344
2367
  updateAttributes(dom, reusable.elt.attrs, shape.attrs);
2345
2368
  }
2346
- let flags = (tag ? (shape.hasContent ? 0 : 512)
2347
- : 1 | (shape.hasContent ? 0 : 16)) | afterContent;
2348
2369
  let tile = EltTile.of(shape, tag, flags, tag ? length : 0, dom);
2349
2370
  let afterContentInner = 0;
2350
2371
  for (let ch of shape.children) {
2351
2372
  if (ch === 0) {
2352
- afterContentInner = 2048;
2373
+ afterContentInner = 4096;
2353
2374
  tile.flags |= 2;
2354
2375
  }
2355
2376
  else {
@@ -2358,8 +2379,7 @@ class ContentUpdate {
2358
2379
  }
2359
2380
  return tile;
2360
2381
  }
2361
- else {
2362
- let reusable, dom;
2382
+ else { let reusable, dom;
2363
2383
  if (reusable = this.findReusableTile(shape, reuse, false)) {
2364
2384
  this.reused.set(reusable, 2);
2365
2385
  dom = reusable.dom;
@@ -2367,9 +2387,9 @@ class ContentUpdate {
2367
2387
  else {
2368
2388
  dom = shape.render(this.wg);
2369
2389
  }
2370
- if (inEditable && !shape.type.editable)
2371
- setUneditable(dom);
2372
2390
  let flags = (tag ? 512 : 16 | 1) | afterContent;
2391
+ if (inEditable && !shape.type.editable && setUneditable(dom))
2392
+ flags |= 1024;
2373
2393
  let tile = new WidgetTile(shape, tag, flags, dom, tag ? length : 0);
2374
2394
  if (shape.type.connect)
2375
2395
  this.toConnect.push(tile);
@@ -2382,25 +2402,26 @@ class ContentUpdate {
2382
2402
  if (tile.isNodeOuter)
2383
2403
  for (let child of tile.children)
2384
2404
  if (child.isNodeInner) {
2385
- copy.addChild((child.flags & 1024) ? this.copyEltStructure(child) : child);
2405
+ copy.addChild((child.flags & 2048) ? this.copyEltStructure(child) : child);
2386
2406
  }
2387
2407
  return copy;
2388
2408
  }
2389
- ensureHackNode() {
2390
- let tile = this.new;
2391
- if (!tile.isPlotContent)
2392
- return;
2393
- while (tile.isNodeInner)
2394
- tile = tile.parent;
2395
- let tag = tile.tag;
2396
- if (!tag || !tag.isPlot || !(tag.isTextblock || tag.type.isInline))
2397
- return;
2409
+ ensureHackNodes() {
2410
+ if (this.new.isPlotContent || this.new.isWrapper) {
2411
+ let { tag } = this.new.nearestNode();
2412
+ if (this.new.isPlotContent && tag.isPlot && (tag.isTextblock || tag.type.isInline))
2413
+ this.ensureTrailingHackNode(this.new);
2414
+ if (tag.isPlot && !tag.inlineContent)
2415
+ this.ensureBlockSeparators(this.new);
2416
+ }
2417
+ }
2418
+ ensureTrailingHackNode(target) {
2398
2419
  let hasHack = -1, needsHack = true;
2399
- for (let parent = this.new, i = parent.children.length;;) {
2420
+ for (let parent = target, i = parent.children.length;;) {
2400
2421
  if (i > 0) {
2401
2422
  let next = parent.children[--i];
2402
2423
  if (next.isNodeInner || next instanceof WidgetTile && !next.widget.type.inFlow) ;
2403
- else if (next instanceof WidgetTile && next.widget == Widget.br && parent == this.new) {
2424
+ else if (next instanceof WidgetTile && next.widget == Widget.br && parent == target) {
2404
2425
  hasHack = i;
2405
2426
  }
2406
2427
  else if (next.dom.nodeName == "BR") {
@@ -2415,7 +2436,7 @@ class ContentUpdate {
2415
2436
  break;
2416
2437
  }
2417
2438
  }
2418
- else if (parent == this.new) {
2439
+ else if (parent == target) {
2419
2440
  break;
2420
2441
  }
2421
2442
  else {
@@ -2425,14 +2446,32 @@ class ContentUpdate {
2425
2446
  }
2426
2447
  if (hasHack > -1) {
2427
2448
  if (!needsHack)
2428
- this.new.children.splice(hasHack, 1);
2449
+ target.children.splice(hasHack, 1);
2429
2450
  }
2430
2451
  else if (needsHack) {
2431
- this.new.addChild(new WidgetTile(Widget.br, null, 16 | 64, Widget.br.render(this.wg)));
2452
+ target.addChild(new WidgetTile(Widget.br, null, 16 | 64, Widget.br.render(this.wg)));
2453
+ }
2454
+ }
2455
+ ensureBlockSeparators(target) {
2456
+ for (let i = 0, prev = null;; i++) {
2457
+ let next = i == target.children.length ? null : target.children[i];
2458
+ if (next && next.isNodeInner)
2459
+ continue;
2460
+ if (!next && !prev)
2461
+ break;
2462
+ if ((next || prev) &&
2463
+ (!next || ((next.flags & 1024) && !(next.flags & 32))) &&
2464
+ (!prev || ((prev.flags & 1024) && !(prev.flags & 64)))) {
2465
+ let widget = new WidgetTile(Widget.blockImg, null, 16 | 64, Widget.blockImg.render(this.wg));
2466
+ target.putChild(widget, i++);
2467
+ }
2468
+ if (!next)
2469
+ break;
2470
+ prev = next;
2432
2471
  }
2433
2472
  }
2434
2473
  up() {
2435
- this.ensureHackNode();
2474
+ this.ensureHackNodes();
2436
2475
  this.new = this.new.parent;
2437
2476
  }
2438
2477
  leaveNode() {
@@ -2491,8 +2530,10 @@ class ContentUpdate {
2491
2530
  prev = copy;
2492
2531
  prev.parent = cur;
2493
2532
  }
2494
- for (let j = i + 1; j < cur.children.length; j++)
2533
+ for (let j = i + 1; j < cur.children.length; j++) {
2495
2534
  prev.addChild(cur.children[j]);
2535
+ cur.children.splice(j, 1);
2536
+ }
2496
2537
  return prev;
2497
2538
  }
2498
2539
  return null;
@@ -2515,7 +2556,7 @@ class ContentUpdate {
2515
2556
  finish() {
2516
2557
  while (!(this.new instanceof DocTile))
2517
2558
  this.up();
2518
- this.ensureHackNode();
2559
+ this.ensureHackNodes();
2519
2560
  return this.new;
2520
2561
  }
2521
2562
  }
@@ -2917,6 +2958,9 @@ const baseStyles = /*@__PURE__*/buildTheme("." + styleID, {
2917
2958
  verticalAlign: "bottom",
2918
2959
  height: "1em",
2919
2960
  },
2961
+ ".wg-blockBuffer": {
2962
+ position: "absolute"
2963
+ },
2920
2964
  "wg-placeholder": {
2921
2965
  opacity: "0.6",
2922
2966
  display: "inline-block",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerd-bible/wordgard",
3
- "version": "0.6.2-beta5",
3
+ "version": "0.6.2-beta7",
4
4
  "description": "Semantic rich text editor system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",