markupeditor 0.9.37 → 0.9.39

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.
@@ -35639,34 +35639,32 @@ function insertInternalLink(hTag, index) {
35639
35639
  function insertInternalLinkCommand(hTag, index) {
35640
35640
  const commandAdapter = (state, dispatch, view) => {
35641
35641
  // Find the node matching hTag that is index into the nodes matching hTag
35642
- let {node} = headerMatching(hTag, index, state);
35642
+ let {node, pos} = headerMatching(hTag, index, state);
35643
35643
  if (!node) return false
35644
- // Get the unique id for this header, which is may or may not already have.
35644
+ // Get the unique id for this header, which it may or may not already have.
35645
35645
  let id = idForHeader(node, state);
35646
- let attrs = node.attrs;
35647
- attrs.id = id;
35648
- // Insert the mark (id is always referenced with # at front) and set (or reset) the
35649
- // id in the header itself. We don't care if it's the same, but we want these changes
35650
- // to be made in a single transaction so we can undo them if needed.
35646
+ // Same transaction as the mark insertion below, so both land as one undo step.
35647
+ let tr = state.tr.setNodeMarkup(pos, undefined, { ...node.attrs, id });
35651
35648
  const selection = state.selection;
35652
35649
  const linkMark = state.schema.marks.link.create({ href: '#' + id });
35653
35650
  if (selection.empty) {
35654
- // In case of an empty selection, insert the textContent of the header and then use
35651
+ // In case of an empty selection, insert the textContent of the header and then use
35655
35652
  // that to link-to the header
35656
35653
  const textNode = state.schema.text(node.textContent, [linkMark]);
35657
- let transaction = state.tr.replaceSelectionWith(textNode, false);
35658
- dispatch(transaction);
35654
+ tr.replaceSelectionWith(textNode, false);
35655
+ dispatch(tr);
35659
35656
  stateChanged(view);
35660
35657
  return true;
35661
35658
  } else {
35662
- const toggle = toggleMark(linkMark.type, linkMark.attrs);
35663
- if (toggle) {
35664
- toggle(state, dispatch);
35665
- stateChanged(view);
35666
- return true;
35667
- } else {
35668
- return false;
35669
- }
35659
+ // Capture toggleMark's steps rather than let it dispatch, then replay them onto
35660
+ // `tr` (setNodeMarkup doesn't shift positions, so they apply cleanly).
35661
+ let captured = null;
35662
+ toggleMark(linkMark.type, linkMark.attrs)(state, t => { captured = t; });
35663
+ if (!captured) return false;
35664
+ for (const step of captured.steps) tr.step(step);
35665
+ dispatch(tr);
35666
+ stateChanged(view);
35667
+ return true;
35670
35668
  }
35671
35669
  };
35672
35670
  return commandAdapter;
@@ -35751,11 +35749,17 @@ function headerMatching(hTag, index, state) {
35751
35749
  }
35752
35750
 
35753
35751
  /**
35754
- * Return a JSON-stringified array describing every header in the document, in document order
35755
- * within each level. Each entry is `{hTag, index, text}`, where `hTag` and `index` identify the
35756
- * header the same way `insertInternalLink(hTag, index)` and `idForInternalLinkCommand(hTag, index)` do.
35752
+ * Return a JSON-stringified array describing every non-empty header in the document, in document
35753
+ * order within each level. Each entry is `{hTag, index, text, id}`, where `hTag` and `index` identify
35754
+ * the header the same way `insertInternalLink(hTag, index)` and `idForInternalLinkCommand(hTag, index)`
35755
+ * do, and `id` is the header's current id attribute (null if it hasn't been assigned one yet).
35756
+ *
35757
+ * An empty header is omitted -- it can't form a usable id, so there's nothing to link to -- but
35758
+ * `index` still reflects its true position among ALL headers at that level (empty ones included),
35759
+ * matching what `headerMatching` expects; it's only the reported entries that skip empty headers,
35760
+ * not the numbering.
35757
35761
  *
35758
- * @returns {string} JSON-stringified array of `{hTag, index, text}`
35762
+ * @returns {string} JSON-stringified array of `{hTag, index, text, id}`
35759
35763
  */
35760
35764
  function getHeaders() {
35761
35765
  const view = activeView();
@@ -35765,7 +35769,9 @@ function getHeaders() {
35765
35769
  let hNodes = headersByLevel[level];
35766
35770
  if (hNodes) {
35767
35771
  hNodes.forEach((h, index) => {
35768
- result.push({hTag: 'H' + level.toString(), index: index, text: h.node.textContent});
35772
+ const text = h.node.textContent;
35773
+ if (text.trim().length === 0) return
35774
+ result.push({hTag: 'H' + level.toString(), index: index, text: text, id: h.node.attrs.id ?? null});
35769
35775
  });
35770
35776
  }
35771
35777
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markupeditor",
3
- "version": "0.9.37",
3
+ "version": "0.9.39",
4
4
  "description": "A web component and API for WYSIWYG HTML editing.",
5
5
  "keywords": [
6
6
  "wysiwyg",