markupeditor 0.9.9 → 0.9.11

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.
@@ -138,7 +138,7 @@
138
138
  "type": {
139
139
  "text": "object"
140
140
  },
141
- "default": "{ activeConfig, activeView, addButton, addCol, addDiv, addHeader, addRow, borderTable, cancelSearch, canUndo, canRedo, consoleLog, cutImage, deactivateSearch, deleteLink, deleteTableArea, doRedo, doUndo, emptyDocument, focus, focusOn, focused, getDataImages, getHTML, getHeight, getImageAttributes, getLinkAttributes, getSelectionState, getTestHTML, indent, insertImage, insertLink, insertTable, loadUserFiles, modifyImage, openImageDialog, openLinkDialog, outdent, padBottom, pasteHTML, pasteText, removeAllDivs, removeButton, removeDiv, resetSelection, savedDataImage, searchFor, setActiveView, setHTML, setStyle, setTestHTML, setTopLevelAttributes, testBlockquoteEnter, testExtractContents, testListEnter, testPasteHTMLPreprocessing, testPasteTextPreprocessing, toggleBold, toggleCode, toggleItalic, toggleListItem, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline, // Helpers to create custom toolbar items MenuItem, Dropdown, DropdownSubmenu, cmdItem, renderGrouped, renderDropdownItems, toggleSearch, // Config access ToolbarConfig, KeymapConfig, BehaviorConfig, // Registry access registerAugmentation, registerConfig, registerDelegate, registerMessageHandler, }",
141
+ "default": "{ activeConfig, activeView, addButton, addCol, addDiv, addHeader, addRow, borderTable, callbackSelectImage, cancelSearch, canUndo, canRedo, consoleLog, cutImage, deactivateSearch, deleteLink, deleteTableArea, doRedo, doUndo, emptyDocument, focus, focusOn, focused, getDataImages, getHTML, getHeight, getImageAttributes, getLinkAttributes, getSelectionState, getTestHTML, indent, insertImage, insertLink, insertTable, loadUserFiles, modifyImage, openImageDialog, openLinkDialog, outdent, padBottom, pasteHTML, pasteText, removeAllDivs, removeButton, removeDiv, resetSelection, savedDataImage, searchFor, setActiveView, setHTML, setStyle, setTestHTML, setTopLevelAttributes, testBlockquoteEnter, testExtractContents, testListEnter, testPasteHTMLPreprocessing, testPasteTextPreprocessing, toggleBold, toggleCode, toggleItalic, toggleListItem, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline, // Helpers to create custom toolbar items MenuItem, Dropdown, DropdownSubmenu, cmdItem, renderGrouped, renderDropdownItems, toggleSearch, // Config access ToolbarConfig, KeymapConfig, BehaviorConfig, // Registry access registerAugmentation, registerConfig, registerDelegate, registerMessageHandler, }",
142
142
  "description": "The object whose methods comprise the MarkupEditor API."
143
143
  }
144
144
  ],
@@ -722,6 +722,11 @@
722
722
  }
723
723
  ]
724
724
  },
725
+ {
726
+ "kind": "function",
727
+ "name": "callbackSelectImage",
728
+ "description": "Callback to signal that the user wants to select an image from a file.\n\nThe messageHandler will need to do something like bring up a file picker\nand in turn execute insertImage."
729
+ },
725
730
  {
726
731
  "kind": "function",
727
732
  "name": "searchedCallback",
@@ -1505,6 +1510,14 @@
1505
1510
  "module": "src/markup.js"
1506
1511
  }
1507
1512
  },
1513
+ {
1514
+ "kind": "js",
1515
+ "name": "callbackSelectImage",
1516
+ "declaration": {
1517
+ "name": "callbackSelectImage",
1518
+ "module": "src/markup.js"
1519
+ }
1520
+ },
1508
1521
  {
1509
1522
  "kind": "js",
1510
1523
  "name": "searchedCallback",
@@ -2379,18 +2392,7 @@
2379
2392
  {
2380
2393
  "kind": "method",
2381
2394
  "name": "selectImage",
2382
- "parameters": [
2383
- {
2384
- "name": "state"
2385
- },
2386
- {
2387
- "name": "dispatch"
2388
- },
2389
- {
2390
- "name": "view"
2391
- }
2392
- ],
2393
- "description": "Tell the delegate to select an image to insert, because we don't know how to do that"
2395
+ "description": "Call back to the messageHandler after closing the dialog. The message handler should \nlet the delegate deal with bringing up a file picker of some kind."
2394
2396
  },
2395
2397
  {
2396
2398
  "kind": "method",
@@ -14767,6 +14767,7 @@ let baseNodes = OrderedMap.from({
14767
14767
  div: {
14768
14768
  content: "block*",
14769
14769
  group: "block",
14770
+ isolating: true, // Prevent operations like lift from going outside of a div
14770
14771
  selectable: false,
14771
14772
  attrs: {
14772
14773
  id: {default: null},
@@ -14841,9 +14842,14 @@ let baseNodes = OrderedMap.from({
14841
14842
  }
14842
14843
  }
14843
14844
  }],
14844
- toDOM(node) {
14845
- let {id, cssClass} = node.attrs;
14846
- return ["button", { id: id, class: cssClass }, 0]
14845
+ toDOM(node) {
14846
+ let {id, cssClass, label} = node.attrs;
14847
+ const button = document.createElement("button");
14848
+ if (id) button.setAttribute("id", id);
14849
+ if (cssClass) button.setAttribute("class", cssClass);
14850
+ button.setAttribute("type", "button");
14851
+ if (label) button.innerHTML = label;
14852
+ return button;
14847
14853
  }
14848
14854
  }
14849
14855
 
@@ -16150,6 +16156,121 @@ A command function that redoes the last undone change, if any.
16150
16156
  */
16151
16157
  const redo$1 = buildCommand(true, true);
16152
16158
 
16159
+ /**
16160
+ *
16161
+ * @param {EditorView} view
16162
+ * @param {string} text Text to be translated
16163
+ * @returns {string} The translated text if the view supports it
16164
+ */
16165
+ function translate(view, text) {
16166
+ return view._props.translate ? view._props.translate(text) : text;
16167
+ }
16168
+ /**
16169
+ * Add or remove a class from the element.
16170
+ *
16171
+ * Apparently a workaround for classList.toggle being broken in IE11
16172
+ *
16173
+ * @param {HTMLElement} dom
16174
+ * @param {string} cls The class name to add or remove
16175
+ * @param {boolean} on True to add the class name to the `classList`
16176
+ */
16177
+ function setClass(dom, cls, on) {
16178
+ if (on)
16179
+ dom.classList.add(cls);
16180
+ else
16181
+ dom.classList.remove(cls);
16182
+ }
16183
+
16184
+ /**
16185
+ * DOMAccess provides access to the MarkupToolbar and other well-known elements.
16186
+ */
16187
+ class DOMAccess {
16188
+
16189
+ constructor(prefix) {
16190
+ this.prefix = prefix ?? 'Markup';
16191
+ }
16192
+
16193
+ setPrefix(prefix) {
16194
+ this.prefix = prefix;
16195
+ }
16196
+
16197
+ /**
16198
+ * Return the toolbar div in `view`
16199
+ * @param {EditorView} view
16200
+ * @returns {HTMLDivElement} The toolbar div in the view
16201
+ */
16202
+ getToolbar(view) {
16203
+ return view.dom.getRootNode().getElementById(this.prefix + "-toolbar")
16204
+ }
16205
+
16206
+ getSearchItem(view) {
16207
+ return view.dom.getRootNode().getElementById(this.prefix + '-searchitem')
16208
+ }
16209
+
16210
+ getSearchbar(view) {
16211
+ return view.dom.getRootNode().getElementById(this.prefix + "-searchbar")
16212
+ }
16213
+
16214
+ getToolbarMore(view) {
16215
+ return view.dom.getRootNode().getElementById(this.prefix + "-toolbar-more")
16216
+ }
16217
+
16218
+ getWrapper(view) {
16219
+ return this.getToolbar(view)?.parentElement
16220
+ }
16221
+
16222
+ /** Adding promptShowing class on wrapper lets us suppress scroll while the prompt is showing */
16223
+ addPromptShowing(view) {
16224
+ setClass(getWrapper(view), promptShowing(), true);
16225
+ }
16226
+
16227
+ /** Removing promptShowing class on wrapper lets wrapper scroll again */
16228
+ removePromptShowing(view) {
16229
+ setClass(getWrapper(view), promptShowing(), false);
16230
+ }
16231
+
16232
+ promptShowing() {
16233
+ return this.prefix + "-prompt-showing"
16234
+ }
16235
+
16236
+ searchInput() {
16237
+ return this.prefix + "-searchinput"
16238
+ }
16239
+
16240
+ searchbarShowing() {
16241
+ return this.prefix + "-searchbar-showing"
16242
+ }
16243
+
16244
+ searchbarHidden() {
16245
+ return this.prefix + "-searchbar-hidden"
16246
+ }
16247
+
16248
+ isSearchFocused(view) {
16249
+ return view?.dom.getRootNode().getElementById(this.searchInput())?.matches(':focus') ?? false
16250
+ }
16251
+
16252
+ isPromptShowing(view) {
16253
+ return (view) ? this.getWrapper(view)?.classList.contains(this.promptShowing()) ?? false : false
16254
+ }
16255
+
16256
+ }
16257
+
16258
+ const _domAccess = new DOMAccess();
16259
+ const prefix = _domAccess.prefix;
16260
+ const setPrefix = _domAccess.setPrefix.bind(_domAccess);
16261
+ const getToolbar = _domAccess.getToolbar.bind(_domAccess);
16262
+ _domAccess.getSearchItem.bind(_domAccess);
16263
+ const getSearchbar = _domAccess.getSearchbar.bind(_domAccess);
16264
+ const getToolbarMore = _domAccess.getToolbarMore.bind(_domAccess);
16265
+ const getWrapper = _domAccess.getWrapper.bind(_domAccess);
16266
+ const addPromptShowing = _domAccess.addPromptShowing.bind(_domAccess);
16267
+ const removePromptShowing = _domAccess.removePromptShowing.bind(_domAccess);
16268
+ const promptShowing = _domAccess.promptShowing.bind(_domAccess);
16269
+ const searchbarShowing = _domAccess.searchbarShowing.bind(_domAccess);
16270
+ const searchbarHidden = _domAccess.searchbarHidden.bind(_domAccess);
16271
+ const isSearchFocused = _domAccess.isSearchFocused.bind(_domAccess);
16272
+ const isPromptShowing = _domAccess.isPromptShowing.bind(_domAccess);
16273
+
16153
16274
  /**
16154
16275
  * Define various arrays of tags used to represent MarkupEditor-specific concepts.
16155
16276
  *
@@ -16954,7 +17075,7 @@ function _buttonGroupDiv(buttonGroupJSON) {
16954
17075
  buttonGroupDiv.setAttribute('editable', "false"); // Hardcode
16955
17076
  buttonGroup.buttons.forEach( buttonAttributes => {
16956
17077
  let button = document.createElement('button');
16957
- button.appendChild(document.createTextNode(buttonAttributes.label));
17078
+ button.innerHTML = buttonAttributes.label;
16958
17079
  button.setAttribute('label', buttonAttributes.label);
16959
17080
  button.setAttribute('type', 'button');
16960
17081
  button.setAttribute('id', buttonAttributes.id);
@@ -17011,7 +17132,7 @@ function addButton(id, parentId, cssClass, label) {
17011
17132
  button.setAttribute('parentId', parentId);
17012
17133
  button.setAttribute('class', cssClass);
17013
17134
  button.setAttribute('type', 'button');
17014
- button.appendChild(document.createTextNode(label));
17135
+ button.innerHTML = label;
17015
17136
  const buttonSlice = _sliceFromElement(button);
17016
17137
  const buttonNode = buttonNodeType.create({id, parentId, cssClass, label}, buttonSlice.content);
17017
17138
  const transaction = view.state.tr;
@@ -17868,9 +17989,12 @@ function _getSelectionState() {
17868
17989
  // absolutely reflects the selection state at the time of the call regardless
17869
17990
  // of whether it is editable or not.
17870
17991
  const contentEditable = _getContentEditable();
17992
+ const view = activeView();
17871
17993
  state['divid'] = contentEditable.id; // Will be 'editor' or a div ID
17872
- state['valid'] = contentEditable.editable; // Valid means the selection is in something editable
17873
- if (!contentEditable.editable) return state; // No need to do more with state if it's not editable
17994
+ // Valid means the selection is in something editable and
17995
+ // neither search is focused nor is a prompt showing
17996
+ state['valid'] = contentEditable.editable && !(isSearchFocused(view) || isPromptShowing(view));
17997
+ if (!state['valid']) return state; // No need to do more with state if it's not editable
17874
17998
 
17875
17999
  // Selected text
17876
18000
  state['selection'] = _getSelectionText();
@@ -18198,6 +18322,17 @@ function _getIndented(state) {
18198
18322
  function callbackInput(element) {
18199
18323
  _callback('input' + (selectedID() ?? ''), element);
18200
18324
  }
18325
+ /**
18326
+ * Callback to signal that the user wants to select an image from a file.
18327
+ *
18328
+ * The messageHandler will need to do something like bring up a file picker
18329
+ * and in turn execute insertImage.
18330
+ */
18331
+ function callbackSelectImage() {
18332
+ let messageDict = { 'messageType' : 'selectImage' };
18333
+ _callback(JSON.stringify(messageDict));
18334
+ }
18335
+
18201
18336
  /**
18202
18337
  * Callback to signal that user-provided CSS and/or script files have
18203
18338
  * been loaded.
@@ -20806,107 +20941,6 @@ function add(elt, child) {
20806
20941
  }
20807
20942
  }
20808
20943
 
20809
- /**
20810
- *
20811
- * @param {EditorView} view
20812
- * @param {string} text Text to be translated
20813
- * @returns {string} The translated text if the view supports it
20814
- */
20815
- function translate(view, text) {
20816
- return view._props.translate ? view._props.translate(text) : text;
20817
- }
20818
- /**
20819
- * Add or remove a class from the element.
20820
- *
20821
- * Apparently a workaround for classList.toggle being broken in IE11
20822
- *
20823
- * @param {HTMLElement} dom
20824
- * @param {string} cls The class name to add or remove
20825
- * @param {boolean} on True to add the class name to the `classList`
20826
- */
20827
- function setClass(dom, cls, on) {
20828
- if (on)
20829
- dom.classList.add(cls);
20830
- else
20831
- dom.classList.remove(cls);
20832
- }
20833
-
20834
- /**
20835
- * DOMAccess provides access to the MarkupToolbar and other well-known elements.
20836
- */
20837
- class DOMAccess {
20838
-
20839
- constructor(prefix) {
20840
- this.prefix = prefix ?? 'Markup';
20841
- }
20842
-
20843
- setPrefix(prefix) {
20844
- this.prefix = prefix;
20845
- }
20846
-
20847
- /**
20848
- * Return the toolbar div in `view`
20849
- * @param {EditorView} view
20850
- * @returns {HTMLDivElement} The toolbar div in the view
20851
- */
20852
- getToolbar(view) {
20853
- return view.dom.getRootNode().getElementById(this.prefix + "-toolbar");
20854
- }
20855
-
20856
- getSearchItem(view) {
20857
- return view.dom.getRootNode().getElementById(this.prefix + '-searchitem')
20858
- }
20859
-
20860
- getSearchbar(view) {
20861
- return view.dom.getRootNode().getElementById(this.prefix + "-searchbar");
20862
- }
20863
-
20864
- getToolbarMore(view) {
20865
- return view.dom.getRootNode().getElementById(this.prefix + "-toolbar-more")
20866
- }
20867
-
20868
- getWrapper(view) {
20869
- return this.getToolbar(view).parentElement;
20870
- }
20871
-
20872
- /** Adding promptShowing class on wrapper lets us suppress scroll while the prompt is showing */
20873
- addPromptShowing(view) {
20874
- setClass(getWrapper(view), promptShowing(), true);
20875
- }
20876
-
20877
- /** Removing promptShowing class on wrapper lets wrapper scroll again */
20878
- removePromptShowing(view) {
20879
- setClass(getWrapper(view), promptShowing(), false);
20880
- }
20881
-
20882
- promptShowing() {
20883
- return this.prefix + "-prompt-showing"
20884
- }
20885
-
20886
- searchbarShowing() {
20887
- return this.prefix + "-searchbar-showing"
20888
- }
20889
-
20890
- searchbarHidden() {
20891
- return this.prefix + "-searchbar-hidden"
20892
- }
20893
-
20894
- }
20895
-
20896
- const _domAccess = new DOMAccess();
20897
- const prefix = _domAccess.prefix;
20898
- const setPrefix = _domAccess.setPrefix.bind(_domAccess);
20899
- const getToolbar = _domAccess.getToolbar.bind(_domAccess);
20900
- _domAccess.getSearchItem.bind(_domAccess);
20901
- const getSearchbar = _domAccess.getSearchbar.bind(_domAccess);
20902
- const getToolbarMore = _domAccess.getToolbarMore.bind(_domAccess);
20903
- const getWrapper = _domAccess.getWrapper.bind(_domAccess);
20904
- const addPromptShowing = _domAccess.addPromptShowing.bind(_domAccess);
20905
- const removePromptShowing = _domAccess.removePromptShowing.bind(_domAccess);
20906
- const promptShowing = _domAccess.promptShowing.bind(_domAccess);
20907
- const searchbarShowing = _domAccess.searchbarShowing.bind(_domAccess);
20908
- const searchbarHidden = _domAccess.searchbarHidden.bind(_domAccess);
20909
-
20910
20944
  function getIcon(root, icon) {
20911
20945
  let doc = (root.nodeType == 9 ? root : root.ownerDocument) || document;
20912
20946
  let node = doc.createElement("span");
@@ -21283,8 +21317,9 @@ class DialogItem {
21283
21317
  * @param {EditorView} view
21284
21318
  */
21285
21319
  openDialog(state, dispatch, view) {
21286
- setActiveView(view);
21320
+ setActiveView(view);
21287
21321
  this.createDialog(view);
21322
+ selectionChanged(); // Since it's pseudo modal, we can do it once
21288
21323
  this.dialog.show();
21289
21324
  }
21290
21325
 
@@ -21371,6 +21406,7 @@ class DialogItem {
21371
21406
  */
21372
21407
  closeDialog() {
21373
21408
  removePromptShowing(activeView());
21409
+ selectionChanged(); // Since it's pseudo modal, we can do it once
21374
21410
  this.toolbarOverlay?.parentElement?.removeChild(this.toolbarOverlay);
21375
21411
  this.overlay?.parentElement?.removeChild(this.overlay);
21376
21412
  this.selectionDiv?.parentElement?.removeChild(this.selectionDiv);
@@ -21866,10 +21902,10 @@ class ImageItem extends DialogItem {
21866
21902
  this.dialog.appendChild(buttonsDiv);
21867
21903
 
21868
21904
  // When local images are allowed, we insert a "Select..." button that will bring up a
21869
- // file chooser. However, the MarkupEditor can't do that itself, so it invokes the
21870
- // delegate's `markupSelectImage` method if it exists. Thus, when `selectImage` is
21871
- // true in BehaviorConfig, that method should exist. It should bring up a file chooser
21872
- // and then invoke `MU.insertImage`.
21905
+ // file chooser. However, the MarkupEditor can't do that itself, so it calls back to
21906
+ // the messageHandler, which in turn should invoke the delegate's `markupSelectImage`
21907
+ // method if it exists. Thus, when `selectImage` is true in BehaviorConfig, that method
21908
+ // should exist. It should bring up a file chooser and then invoke `MU.insertImage`.
21873
21909
  if (this.config.behavior.selectImage) {
21874
21910
  this.preview = null;
21875
21911
  let selectItem = cmdItem(this.selectImage.bind(this), {
@@ -21967,10 +22003,13 @@ class ImageItem extends DialogItem {
21967
22003
  return this.altArea.value
21968
22004
  }
21969
22005
 
21970
- /** Tell the delegate to select an image to insert, because we don't know how to do that */
21971
- selectImage(state, dispatch, view) {
22006
+ /**
22007
+ * Call back to the messageHandler after closing the dialog. The message handler should
22008
+ * let the delegate deal with bringing up a file picker of some kind.
22009
+ */
22010
+ selectImage() {
21972
22011
  this.closeDialog();
21973
- if (this.config.delegate?.markupSelectImage) this.config.delegate?.markupSelectImage(state, dispatch, view);
22012
+ callbackSelectImage();
21974
22013
  }
21975
22014
 
21976
22015
  /**
@@ -22206,7 +22245,8 @@ class SearchItem {
22206
22245
  showSearchbar(state, dispatch, view) {
22207
22246
  let toolbar = getToolbar(view);
22208
22247
  if (!toolbar) return;
22209
- let input = crelt('input', { type: 'search', placeholder: 'Search document...' });
22248
+ let inputId = prefix + "-searchinput";
22249
+ let input = crelt('input', { id: inputId, type: 'search', placeholder: 'Search document...' });
22210
22250
  input.addEventListener('keydown', e => { // Use keydown because 'input' isn't triggered for Enter
22211
22251
  if (e.key === 'Enter') {
22212
22252
  let direction = (e.shiftKey) ? 'backward' : 'forward';
@@ -22224,6 +22264,12 @@ class SearchItem {
22224
22264
  this.text = e.target.value;
22225
22265
  this.stopSearching(false); // Stop searching but leave focus in the input field
22226
22266
  });
22267
+ input.addEventListener('focus', () => {
22268
+ selectionChanged();
22269
+ });
22270
+ input.addEventListener('blur', () => {
22271
+ selectionChanged();
22272
+ });
22227
22273
  let idClass = prefix + "-searchbar";
22228
22274
  let searchbar = crelt("div", { class: idClass, id: idClass }, input);
22229
22275
  this.addSearchButtons(view, searchbar);
@@ -24340,6 +24386,9 @@ class MessageHandler {
24340
24386
  case 'copyImage':
24341
24387
  console.log('fix copyImage ' + messageData.src);
24342
24388
  return
24389
+ case 'selectImage':
24390
+ delegate?.markupSelectImage && delegate?.markupSelectImage();
24391
+ return
24343
24392
  case 'addedImage': {
24344
24393
  if (!delegate?.markupImageAdded) return;
24345
24394
  let divId = messageData.divId;
@@ -24794,6 +24843,7 @@ const MU = {
24794
24843
  addHeader,
24795
24844
  addRow,
24796
24845
  borderTable,
24846
+ callbackSelectImage,
24797
24847
  cancelSearch,
24798
24848
  canUndo,
24799
24849
  canRedo,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markupeditor",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "description": "A web component and API for WYSIWYG HTML editing.",
5
5
  "keywords": [
6
6
  "wysiwyg",