@manuscripts/body-editor 1.13.1 → 1.13.2-LEAN-3307.0

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.
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.insertTableFootnote = exports.addInlineComment = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.ifInTableBody = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertSection = exports.insertGraphicalAbstract = exports.insertInlineFootnote = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertFileAsFigure = exports.insertGeneralFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = void 0;
18
+ exports.insertTableFootnote = exports.addInlineComment = exports.addNodeComment = exports.createAndFillTableElement = exports.selectAllIsolating = exports.ignoreAtomBlockNodeForward = exports.isAtEndOfTextBlock = exports.ignoreMetaNodeBackspaceCommand = exports.ignoreAtomBlockNodeBackward = exports.isTextSelection = exports.isAtStartOfTextBlock = exports.ifInTableBody = exports.insertTOCSection = exports.insertBibliographySection = exports.insertList = exports.insertKeywords = exports.insertContributors = exports.insertAbstract = exports.insertBackMatterSection = exports.insertSection = exports.insertGraphicalAbstract = exports.insertInlineFootnote = exports.insertInlineEquation = exports.insertCrossReference = exports.insertInlineCitation = exports.insertLink = exports.insertSectionLabel = exports.insertBreak = exports.deleteBlock = exports.insertBlock = exports.insertFileAsFigure = exports.insertGeneralFootnote = exports.createBlock = exports.createSelection = exports.canInsert = exports.blockActive = exports.isNodeSelection = exports.markActive = void 0;
19
19
  const json_schema_1 = require("@manuscripts/json-schema");
20
20
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
21
21
  const transform_1 = require("@manuscripts/transform");
@@ -365,7 +365,7 @@ const insertInlineFootnote = (kind) => (state, dispatch) => {
365
365
  return true;
366
366
  };
367
367
  exports.insertInlineFootnote = insertInlineFootnote;
368
- const insertGraphicalAbstract = (state, dispatch) => {
368
+ const insertGraphicalAbstract = (state, dispatch, view) => {
369
369
  if ((0, utils_1.getChildOfType)(state.doc, transform_1.schema.nodes.graphical_abstract_section, true)) {
370
370
  return false;
371
371
  }
@@ -378,26 +378,140 @@ const insertGraphicalAbstract = (state, dispatch) => {
378
378
  const tr = state.tr.insert(pos, section);
379
379
  if (dispatch) {
380
380
  const selection = prosemirror_state_1.TextSelection.create(tr.doc, pos + 1);
381
+ if (view) {
382
+ view.focus();
383
+ }
381
384
  dispatch(tr.setSelection(selection).scrollIntoView());
382
385
  }
383
386
  return true;
384
387
  };
385
388
  exports.insertGraphicalAbstract = insertGraphicalAbstract;
386
- const insertSection = (subsection = false) => (state, dispatch) => {
387
- const pos = findPosAfterParentSection(state.selection.$from);
388
- if (pos === null || (0, transform_1.isInBibliographySection)(state.selection.$from)) {
389
+ const insertSection = (subsection = false) => (state, dispatch, view) => {
390
+ let pos = findPosAfterParentSection(state.selection.$from);
391
+ const body = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.body)[0];
392
+ if ((0, transform_1.isInBibliographySection)(state.selection.$from)) {
393
+ return false;
394
+ }
395
+ else if (pos === null && subsection) {
389
396
  return false;
390
397
  }
398
+ if (pos === null) {
399
+ pos = body.pos + body.node.content.size + 1;
400
+ }
391
401
  const adjustment = subsection ? -1 : 0;
392
402
  const tr = state.tr.insert(pos + adjustment, state.schema.nodes.section.createAndFill());
393
403
  if (dispatch) {
394
404
  const selection = prosemirror_state_1.TextSelection.create(tr.doc, pos + adjustment + 2);
405
+ if (view) {
406
+ view.focus();
407
+ }
395
408
  dispatch(tr.setSelection(selection).scrollIntoView());
396
409
  }
397
410
  return true;
398
411
  };
399
412
  exports.insertSection = insertSection;
413
+ const insertBackMatterSection = (category) => (state, dispatch, view) => {
414
+ const bibliographySection = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.bibliography_section)[0];
415
+ const backmatter = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.backmatter)[0];
416
+ let pos;
417
+ if (bibliographySection) {
418
+ pos = bibliographySection.pos;
419
+ }
420
+ else {
421
+ pos = backmatter.pos + backmatter.node.content.size + 1;
422
+ }
423
+ const tr = state.tr.insert(pos, state.schema.nodes.section.createAndFill({
424
+ category: category,
425
+ }));
426
+ if (dispatch) {
427
+ const selection = prosemirror_state_1.TextSelection.create(tr.doc, pos);
428
+ if (view) {
429
+ view.focus();
430
+ }
431
+ dispatch(tr.setSelection(selection).scrollIntoView());
432
+ }
433
+ return true;
434
+ };
435
+ exports.insertBackMatterSection = insertBackMatterSection;
400
436
  const findSelectedList = (0, prosemirror_utils_1.findParentNodeOfType)([transform_1.schema.nodes.list]);
437
+ const insertAbstract = (state, dispatch, view) => {
438
+ if ((0, utils_1.getMatchingChild)(state.doc, (node) => node.attrs.category === 'MPSectionCategory:abstract', true)) {
439
+ return false;
440
+ }
441
+ const abstracts = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.abstracts)[0];
442
+ const pos = abstracts.pos + 1;
443
+ const section = transform_1.schema.nodes.section.createAndFill({ category: 'MPSectionCategory:abstract' }, [
444
+ transform_1.schema.nodes.section_title.create({}, transform_1.schema.text('Abstract')),
445
+ transform_1.schema.nodes.paragraph.create({ placeholder: 'Type abstract here...' }),
446
+ ]);
447
+ const tr = state.tr.insert(pos, section);
448
+ if (dispatch) {
449
+ const sectionStart = tr.doc.resolve(pos);
450
+ const sectionNode = sectionStart.nodeAfter;
451
+ if (sectionNode && sectionNode.firstChild) {
452
+ const paragraphPos = pos + sectionNode.firstChild.nodeSize + 2;
453
+ const selection = prosemirror_state_1.TextSelection.create(tr.doc, paragraphPos);
454
+ if (view) {
455
+ view.focus();
456
+ }
457
+ dispatch(tr.setSelection(selection).scrollIntoView());
458
+ }
459
+ }
460
+ return true;
461
+ };
462
+ exports.insertAbstract = insertAbstract;
463
+ const insertContributors = (state, dispatch, view) => {
464
+ if ((0, utils_1.getChildOfType)(state.doc, transform_1.schema.nodes.contributors, true)) {
465
+ return false;
466
+ }
467
+ const title = (0, prosemirror_utils_1.findChildrenByType)(state.doc, state.schema.nodes.title)[0];
468
+ const pos = title.pos + title.node.nodeSize;
469
+ const contributors = state.schema.nodes.contributors.create({
470
+ id: '',
471
+ });
472
+ const affiliations = state.schema.nodes.affiliations.create({ id: '' });
473
+ const fragment = prosemirror_model_1.Fragment.fromArray([contributors, affiliations]);
474
+ const tr = state.tr.insert(pos, fragment);
475
+ if (dispatch) {
476
+ const selection = prosemirror_state_1.NodeSelection.create(tr.doc, pos);
477
+ if (view) {
478
+ view.focus();
479
+ }
480
+ dispatch(tr.setSelection(selection).scrollIntoView());
481
+ }
482
+ return true;
483
+ };
484
+ exports.insertContributors = insertContributors;
485
+ const insertKeywords = (state, dispatch, view) => {
486
+ if ((0, utils_1.getChildOfType)(state.doc, transform_1.schema.nodes.keywords, true)) {
487
+ return false;
488
+ }
489
+ const supplements = (0, prosemirror_utils_1.findChildrenByType)(state.doc, state.schema.nodes.supplements)[0];
490
+ const abstracts = (0, prosemirror_utils_1.findChildrenByType)(state.doc, state.schema.nodes.abstracts)[0];
491
+ let pos;
492
+ if (supplements) {
493
+ pos = supplements.pos + supplements.node.nodeSize;
494
+ }
495
+ else {
496
+ pos = abstracts.pos;
497
+ }
498
+ const keywords = transform_1.schema.nodes.keywords.createAndFill({}, [
499
+ transform_1.schema.nodes.section_title.create({}, transform_1.schema.text('Keywords')),
500
+ transform_1.schema.nodes.keywords_element.create({}, [
501
+ transform_1.schema.nodes.keyword_group.create({}, []),
502
+ ]),
503
+ ]);
504
+ const tr = state.tr.insert(pos, keywords);
505
+ if (dispatch) {
506
+ const selection = prosemirror_state_1.NodeSelection.create(tr.doc, pos);
507
+ if (view) {
508
+ view.focus();
509
+ }
510
+ dispatch(tr.setSelection(selection).scrollIntoView());
511
+ }
512
+ return true;
513
+ };
514
+ exports.insertKeywords = insertKeywords;
401
515
  const findRootList = ($pos) => {
402
516
  for (let i = 0; i < $pos.depth; i++) {
403
517
  const node = $pos.node(i);
@@ -692,14 +806,17 @@ const addNodeComment = (node, state, dispatch) => {
692
806
  };
693
807
  const comment = transform_1.schema.nodes.comment.create(attrs);
694
808
  const comments = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.comments)[0];
695
- const pos = comments.pos + 1;
696
- const tr = state.tr.insert(pos, comment);
697
- const key = (0, comments_1.getCommentKey)(attrs, undefined, node);
698
- (0, comments_2.setCommentSelection)(tr, key, attrs.id, true);
699
- if (dispatch) {
700
- dispatch(tr);
809
+ if (comments) {
810
+ const pos = comments.pos + 1;
811
+ const tr = state.tr.insert(pos, comment);
812
+ const key = (0, comments_1.getCommentKey)(attrs, undefined, node);
813
+ (0, comments_2.setCommentSelection)(tr, key, attrs.id, true);
814
+ if (dispatch) {
815
+ dispatch(tr);
816
+ }
817
+ return true;
701
818
  }
702
- return true;
819
+ return false;
703
820
  };
704
821
  exports.addNodeComment = addNodeComment;
705
822
  const addInlineComment = (state, dispatch) => {
@@ -725,36 +842,39 @@ const addInlineComment = (state, dispatch) => {
725
842
  };
726
843
  const comment = transform_1.schema.nodes.comment.create(attrs);
727
844
  const comments = (0, prosemirror_utils_1.findChildrenByType)(state.doc, transform_1.schema.nodes.comments)[0];
728
- const pos = comments.pos + 1;
729
- const tr = state.tr.insert(pos, comment);
730
- if (from === to) {
731
- const point = transform_1.schema.nodes.highlight_marker.create({
732
- id: comment.attrs.id,
733
- tid: node.attrs.id,
734
- position: 'point',
735
- });
736
- tr.insert(from, point);
737
- }
738
- else {
739
- const start = transform_1.schema.nodes.highlight_marker.create({
740
- id: comment.attrs.id,
741
- tid: node.attrs.id,
742
- position: 'start',
743
- });
744
- const end = transform_1.schema.nodes.highlight_marker.create({
745
- id: comment.attrs.id,
746
- tid: node.attrs.id,
747
- position: 'end',
748
- });
749
- tr.insert(from, start).insert(to + 1, end);
750
- }
751
- const range = (0, comments_1.getCommentRange)(attrs);
752
- const key = (0, comments_1.getCommentKey)(attrs, range, node);
753
- (0, comments_2.setCommentSelection)(tr, key, attrs.id, true);
754
- if (dispatch) {
755
- dispatch(tr);
845
+ if (comments) {
846
+ const pos = comments.pos + 1;
847
+ const tr = state.tr.insert(pos, comment);
848
+ if (from === to) {
849
+ const point = transform_1.schema.nodes.highlight_marker.create({
850
+ id: comment.attrs.id,
851
+ tid: node.attrs.id,
852
+ position: 'point',
853
+ });
854
+ tr.insert(from, point);
855
+ }
856
+ else {
857
+ const start = transform_1.schema.nodes.highlight_marker.create({
858
+ id: comment.attrs.id,
859
+ tid: node.attrs.id,
860
+ position: 'start',
861
+ });
862
+ const end = transform_1.schema.nodes.highlight_marker.create({
863
+ id: comment.attrs.id,
864
+ tid: node.attrs.id,
865
+ position: 'end',
866
+ });
867
+ tr.insert(from, start).insert(to + 1, end);
868
+ }
869
+ const range = (0, comments_1.getCommentRange)(attrs);
870
+ const key = (0, comments_1.getCommentKey)(attrs, range, node);
871
+ (0, comments_2.setCommentSelection)(tr, key, attrs.id, true);
872
+ if (dispatch) {
873
+ dispatch(tr);
874
+ }
875
+ return true;
756
876
  }
757
- return true;
877
+ return false;
758
878
  };
759
879
  exports.addInlineComment = addInlineComment;
760
880
  const insertTableFootnote = (node, position, view, inlineFootnote) => {
@@ -153,13 +153,18 @@ const AddKeywordInline = ({ viewProps, getUpdatedNode }) => {
153
153
  setNewKeyword(event.target.value.trimStart());
154
154
  return;
155
155
  };
156
- return (react_1.default.createElement(KeywordField, { value: newKeyword, onChange: handleInputChange, onKeyUp: (e) => {
156
+ return (react_1.default.createElement(KeywordField, { value: newKeyword, onChange: handleInputChange, onKeyDown: (e) => {
157
+ e.stopPropagation();
157
158
  if (e.key == 'Enter') {
158
159
  handleAddKeyword();
159
160
  }
160
161
  else if (e.key == 'Escape') {
161
162
  handleCancel();
162
163
  }
164
+ }, onKeyUp: (e) => {
165
+ e.stopPropagation();
166
+ }, onKeyPress: (e) => {
167
+ e.stopPropagation();
163
168
  }, autoFocus: true }));
164
169
  };
165
170
  const CreateKeywordButtonElement = () => {
package/dist/cjs/menus.js CHANGED
@@ -72,6 +72,92 @@ const getEditorMenus = (editor) => {
72
72
  label: 'Insert',
73
73
  isEnabled: true,
74
74
  submenu: [
75
+ {
76
+ id: 'front-matter',
77
+ label: 'Article Metadata',
78
+ isEnabled: true,
79
+ submenu: [
80
+ {
81
+ id: 'insert-abstract',
82
+ label: 'Abstract',
83
+ isEnabled: isCommandValid(commands_1.insertAbstract),
84
+ run: doCommand(commands_1.insertAbstract),
85
+ },
86
+ {
87
+ id: 'insert-graphical-abstract',
88
+ label: 'Graphical Abstract',
89
+ isEnabled: isCommandValid(commands_1.insertGraphicalAbstract),
90
+ run: doCommand(commands_1.insertGraphicalAbstract),
91
+ },
92
+ {
93
+ id: 'insert-contributors',
94
+ label: 'Authors & Affiliations',
95
+ isEnabled: isCommandValid(commands_1.insertContributors),
96
+ run: doCommand(commands_1.insertContributors),
97
+ },
98
+ {
99
+ id: 'insert-keywords',
100
+ label: 'Keywords',
101
+ isEnabled: isCommandValid(commands_1.insertKeywords),
102
+ run: doCommand(commands_1.insertKeywords),
103
+ },
104
+ ],
105
+ },
106
+ {
107
+ id: 'back-matter',
108
+ label: 'Author Notes',
109
+ isEnabled: true,
110
+ submenu: [
111
+ {
112
+ id: 'insert-acknowledgements',
113
+ label: 'Acknowledgements',
114
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:acknowledgement')),
115
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:acknowledgement')),
116
+ },
117
+ {
118
+ id: 'insert-availability',
119
+ label: 'Availability',
120
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:availability')),
121
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:availability')),
122
+ },
123
+ {
124
+ id: 'insert-coi-statement',
125
+ label: 'COI Statement',
126
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:competing-interests')),
127
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:competing-interests')),
128
+ },
129
+ {
130
+ id: 'insert-con',
131
+ label: 'Contributed-by Information',
132
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:con')),
133
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:con')),
134
+ },
135
+ {
136
+ id: 'insert-ethics-statement',
137
+ label: 'Ethics Statement',
138
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:ethics-statement')),
139
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:ethics-statement')),
140
+ },
141
+ {
142
+ id: 'insert-financial-disclosure',
143
+ label: 'Financial Disclosure',
144
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:financial-disclosure')),
145
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:financial-disclosure')),
146
+ },
147
+ {
148
+ id: 'insert-supplementary-material',
149
+ label: 'Supplementary Material',
150
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:supplementary-material')),
151
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:supplementary-material')),
152
+ },
153
+ {
154
+ id: 'insert-supported-by',
155
+ label: 'Supported By',
156
+ isEnabled: isCommandValid((0, commands_1.insertBackMatterSection)('MPSectionCategory:supported-by')),
157
+ run: doCommand((0, commands_1.insertBackMatterSection)('MPSectionCategory:supported-by')),
158
+ },
159
+ ],
160
+ },
75
161
  {
76
162
  id: 'insert-section',
77
163
  label: 'Section',
@@ -82,12 +168,6 @@ const getEditorMenus = (editor) => {
82
168
  isEnabled: isCommandValid((0, commands_1.insertSection)()),
83
169
  run: doCommand((0, commands_1.insertSection)()),
84
170
  },
85
- {
86
- id: 'insert-graphical-abstract',
87
- label: 'Graphical Abstract',
88
- isEnabled: isCommandValid(commands_1.insertGraphicalAbstract),
89
- run: doCommand(commands_1.insertGraphicalAbstract),
90
- },
91
171
  {
92
172
  id: 'insert-subsection',
93
173
  label: 'Subsection',
@@ -59,6 +59,12 @@ class ContributorsView extends block_view_1.default {
59
59
  this.createLegend();
60
60
  this.updateSelection();
61
61
  };
62
+ this.selectNode = () => {
63
+ this.dom.classList.add('ProseMirror-selectednode');
64
+ if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
65
+ this.handleEdit('');
66
+ }
67
+ };
62
68
  this.buildAuthors = (affs) => {
63
69
  const wrapper = document.createElement('div');
64
70
  wrapper.classList.add('contributors-list');
@@ -25,10 +25,14 @@ class TitleView extends base_node_view_1.BaseNodeView {
25
25
  this.createDOM();
26
26
  };
27
27
  this.createDOM = () => {
28
+ const attrs = this.node.attrs;
28
29
  this.dom = document.createElement('div');
29
30
  this.dom.classList.add('manuscript-title');
30
31
  this.contentDOM = document.createElement('div');
31
32
  this.contentDOM.classList.add('article-titles');
33
+ if (!this.node.childCount && attrs.placeholder) {
34
+ this.contentDOM.setAttribute('data-placeholder', attrs.placeholder);
35
+ }
32
36
  this.dom.appendChild(this.contentDOM);
33
37
  };
34
38
  }
@@ -16,7 +16,7 @@
16
16
  import { buildContribution, ObjectTypes } from '@manuscripts/json-schema';
17
17
  import { skipTracking } from '@manuscripts/track-changes-plugin';
18
18
  import { generateID, isElementNodeType, isFootnoteNode, isInBibliographySection, isListNode, isParagraphNode, isSectionNodeType, schema, } from '@manuscripts/transform';
19
- import { NodeRange } from 'prosemirror-model';
19
+ import { Fragment, NodeRange, } from 'prosemirror-model';
20
20
  import { wrapInList } from 'prosemirror-schema-list';
21
21
  import { NodeSelection, TextSelection, } from 'prosemirror-state';
22
22
  import { findWrapping, liftTarget, ReplaceAroundStep, } from 'prosemirror-transform';
@@ -24,7 +24,7 @@ import { findChildrenByType, findParentNodeOfType, } from 'prosemirror-utils';
24
24
  import { getCommentKey, getCommentRange } from './lib/comments';
25
25
  import { isNodeOfType, nearestAncestor } from './lib/helpers';
26
26
  import { isDeleted, isRejectedInsert } from './lib/track-changes-utils';
27
- import { findParentNodeWithId, getChildOfType } from './lib/utils';
27
+ import { findParentNodeWithId, getChildOfType, getMatchingChild, } from './lib/utils';
28
28
  import { setCommentSelection } from './plugins/comments';
29
29
  import { getEditorProps } from './plugins/editor-props';
30
30
  import { getNewFootnotePos } from './plugins/footnotes/footnotes-utils';
@@ -345,7 +345,7 @@ export const insertInlineFootnote = (kind) => (state, dispatch) => {
345
345
  }
346
346
  return true;
347
347
  };
348
- export const insertGraphicalAbstract = (state, dispatch) => {
348
+ export const insertGraphicalAbstract = (state, dispatch, view) => {
349
349
  if (getChildOfType(state.doc, schema.nodes.graphical_abstract_section, true)) {
350
350
  return false;
351
351
  }
@@ -358,24 +358,134 @@ export const insertGraphicalAbstract = (state, dispatch) => {
358
358
  const tr = state.tr.insert(pos, section);
359
359
  if (dispatch) {
360
360
  const selection = TextSelection.create(tr.doc, pos + 1);
361
+ if (view) {
362
+ view.focus();
363
+ }
361
364
  dispatch(tr.setSelection(selection).scrollIntoView());
362
365
  }
363
366
  return true;
364
367
  };
365
- export const insertSection = (subsection = false) => (state, dispatch) => {
366
- const pos = findPosAfterParentSection(state.selection.$from);
367
- if (pos === null || isInBibliographySection(state.selection.$from)) {
368
+ export const insertSection = (subsection = false) => (state, dispatch, view) => {
369
+ let pos = findPosAfterParentSection(state.selection.$from);
370
+ const body = findChildrenByType(state.doc, schema.nodes.body)[0];
371
+ if (isInBibliographySection(state.selection.$from)) {
372
+ return false;
373
+ }
374
+ else if (pos === null && subsection) {
368
375
  return false;
369
376
  }
377
+ if (pos === null) {
378
+ pos = body.pos + body.node.content.size + 1;
379
+ }
370
380
  const adjustment = subsection ? -1 : 0;
371
381
  const tr = state.tr.insert(pos + adjustment, state.schema.nodes.section.createAndFill());
372
382
  if (dispatch) {
373
383
  const selection = TextSelection.create(tr.doc, pos + adjustment + 2);
384
+ if (view) {
385
+ view.focus();
386
+ }
387
+ dispatch(tr.setSelection(selection).scrollIntoView());
388
+ }
389
+ return true;
390
+ };
391
+ export const insertBackMatterSection = (category) => (state, dispatch, view) => {
392
+ const bibliographySection = findChildrenByType(state.doc, schema.nodes.bibliography_section)[0];
393
+ const backmatter = findChildrenByType(state.doc, schema.nodes.backmatter)[0];
394
+ let pos;
395
+ if (bibliographySection) {
396
+ pos = bibliographySection.pos;
397
+ }
398
+ else {
399
+ pos = backmatter.pos + backmatter.node.content.size + 1;
400
+ }
401
+ const tr = state.tr.insert(pos, state.schema.nodes.section.createAndFill({
402
+ category: category,
403
+ }));
404
+ if (dispatch) {
405
+ const selection = TextSelection.create(tr.doc, pos);
406
+ if (view) {
407
+ view.focus();
408
+ }
374
409
  dispatch(tr.setSelection(selection).scrollIntoView());
375
410
  }
376
411
  return true;
377
412
  };
378
413
  const findSelectedList = findParentNodeOfType([schema.nodes.list]);
414
+ export const insertAbstract = (state, dispatch, view) => {
415
+ if (getMatchingChild(state.doc, (node) => node.attrs.category === 'MPSectionCategory:abstract', true)) {
416
+ return false;
417
+ }
418
+ const abstracts = findChildrenByType(state.doc, schema.nodes.abstracts)[0];
419
+ const pos = abstracts.pos + 1;
420
+ const section = schema.nodes.section.createAndFill({ category: 'MPSectionCategory:abstract' }, [
421
+ schema.nodes.section_title.create({}, schema.text('Abstract')),
422
+ schema.nodes.paragraph.create({ placeholder: 'Type abstract here...' }),
423
+ ]);
424
+ const tr = state.tr.insert(pos, section);
425
+ if (dispatch) {
426
+ const sectionStart = tr.doc.resolve(pos);
427
+ const sectionNode = sectionStart.nodeAfter;
428
+ if (sectionNode && sectionNode.firstChild) {
429
+ const paragraphPos = pos + sectionNode.firstChild.nodeSize + 2;
430
+ const selection = TextSelection.create(tr.doc, paragraphPos);
431
+ if (view) {
432
+ view.focus();
433
+ }
434
+ dispatch(tr.setSelection(selection).scrollIntoView());
435
+ }
436
+ }
437
+ return true;
438
+ };
439
+ export const insertContributors = (state, dispatch, view) => {
440
+ if (getChildOfType(state.doc, schema.nodes.contributors, true)) {
441
+ return false;
442
+ }
443
+ const title = findChildrenByType(state.doc, state.schema.nodes.title)[0];
444
+ const pos = title.pos + title.node.nodeSize;
445
+ const contributors = state.schema.nodes.contributors.create({
446
+ id: '',
447
+ });
448
+ const affiliations = state.schema.nodes.affiliations.create({ id: '' });
449
+ const fragment = Fragment.fromArray([contributors, affiliations]);
450
+ const tr = state.tr.insert(pos, fragment);
451
+ if (dispatch) {
452
+ const selection = NodeSelection.create(tr.doc, pos);
453
+ if (view) {
454
+ view.focus();
455
+ }
456
+ dispatch(tr.setSelection(selection).scrollIntoView());
457
+ }
458
+ return true;
459
+ };
460
+ export const insertKeywords = (state, dispatch, view) => {
461
+ if (getChildOfType(state.doc, schema.nodes.keywords, true)) {
462
+ return false;
463
+ }
464
+ const supplements = findChildrenByType(state.doc, state.schema.nodes.supplements)[0];
465
+ const abstracts = findChildrenByType(state.doc, state.schema.nodes.abstracts)[0];
466
+ let pos;
467
+ if (supplements) {
468
+ pos = supplements.pos + supplements.node.nodeSize;
469
+ }
470
+ else {
471
+ pos = abstracts.pos;
472
+ }
473
+ const keywords = schema.nodes.keywords.createAndFill({}, [
474
+ schema.nodes.section_title.create({}, schema.text('Keywords')),
475
+ schema.nodes.keywords_element.create({}, [
476
+ schema.nodes.keyword_group.create({}, []),
477
+ ]),
478
+ ]);
479
+ const tr = state.tr.insert(pos, keywords);
480
+ if (dispatch) {
481
+ const selection = NodeSelection.create(tr.doc, pos);
482
+ if (view) {
483
+ view.focus();
484
+ }
485
+ dispatch(tr.setSelection(selection).scrollIntoView());
486
+ }
487
+ return true;
488
+ };
379
489
  const findRootList = ($pos) => {
380
490
  for (let i = 0; i < $pos.depth; i++) {
381
491
  const node = $pos.node(i);
@@ -658,14 +768,17 @@ export const addNodeComment = (node, state, dispatch) => {
658
768
  };
659
769
  const comment = schema.nodes.comment.create(attrs);
660
770
  const comments = findChildrenByType(state.doc, schema.nodes.comments)[0];
661
- const pos = comments.pos + 1;
662
- const tr = state.tr.insert(pos, comment);
663
- const key = getCommentKey(attrs, undefined, node);
664
- setCommentSelection(tr, key, attrs.id, true);
665
- if (dispatch) {
666
- dispatch(tr);
771
+ if (comments) {
772
+ const pos = comments.pos + 1;
773
+ const tr = state.tr.insert(pos, comment);
774
+ const key = getCommentKey(attrs, undefined, node);
775
+ setCommentSelection(tr, key, attrs.id, true);
776
+ if (dispatch) {
777
+ dispatch(tr);
778
+ }
779
+ return true;
667
780
  }
668
- return true;
781
+ return false;
669
782
  };
670
783
  export const addInlineComment = (state, dispatch) => {
671
784
  const selection = state.selection;
@@ -690,36 +803,39 @@ export const addInlineComment = (state, dispatch) => {
690
803
  };
691
804
  const comment = schema.nodes.comment.create(attrs);
692
805
  const comments = findChildrenByType(state.doc, schema.nodes.comments)[0];
693
- const pos = comments.pos + 1;
694
- const tr = state.tr.insert(pos, comment);
695
- if (from === to) {
696
- const point = schema.nodes.highlight_marker.create({
697
- id: comment.attrs.id,
698
- tid: node.attrs.id,
699
- position: 'point',
700
- });
701
- tr.insert(from, point);
702
- }
703
- else {
704
- const start = schema.nodes.highlight_marker.create({
705
- id: comment.attrs.id,
706
- tid: node.attrs.id,
707
- position: 'start',
708
- });
709
- const end = schema.nodes.highlight_marker.create({
710
- id: comment.attrs.id,
711
- tid: node.attrs.id,
712
- position: 'end',
713
- });
714
- tr.insert(from, start).insert(to + 1, end);
715
- }
716
- const range = getCommentRange(attrs);
717
- const key = getCommentKey(attrs, range, node);
718
- setCommentSelection(tr, key, attrs.id, true);
719
- if (dispatch) {
720
- dispatch(tr);
806
+ if (comments) {
807
+ const pos = comments.pos + 1;
808
+ const tr = state.tr.insert(pos, comment);
809
+ if (from === to) {
810
+ const point = schema.nodes.highlight_marker.create({
811
+ id: comment.attrs.id,
812
+ tid: node.attrs.id,
813
+ position: 'point',
814
+ });
815
+ tr.insert(from, point);
816
+ }
817
+ else {
818
+ const start = schema.nodes.highlight_marker.create({
819
+ id: comment.attrs.id,
820
+ tid: node.attrs.id,
821
+ position: 'start',
822
+ });
823
+ const end = schema.nodes.highlight_marker.create({
824
+ id: comment.attrs.id,
825
+ tid: node.attrs.id,
826
+ position: 'end',
827
+ });
828
+ tr.insert(from, start).insert(to + 1, end);
829
+ }
830
+ const range = getCommentRange(attrs);
831
+ const key = getCommentKey(attrs, range, node);
832
+ setCommentSelection(tr, key, attrs.id, true);
833
+ if (dispatch) {
834
+ dispatch(tr);
835
+ }
836
+ return true;
721
837
  }
722
- return true;
838
+ return false;
723
839
  };
724
840
  export const insertTableFootnote = (node, position, view, inlineFootnote) => {
725
841
  var _a;
@@ -124,13 +124,18 @@ export const AddKeywordInline = ({ viewProps, getUpdatedNode }) => {
124
124
  setNewKeyword(event.target.value.trimStart());
125
125
  return;
126
126
  };
127
- return (React.createElement(KeywordField, { value: newKeyword, onChange: handleInputChange, onKeyUp: (e) => {
127
+ return (React.createElement(KeywordField, { value: newKeyword, onChange: handleInputChange, onKeyDown: (e) => {
128
+ e.stopPropagation();
128
129
  if (e.key == 'Enter') {
129
130
  handleAddKeyword();
130
131
  }
131
132
  else if (e.key == 'Escape') {
132
133
  handleCancel();
133
134
  }
135
+ }, onKeyUp: (e) => {
136
+ e.stopPropagation();
137
+ }, onKeyPress: (e) => {
138
+ e.stopPropagation();
134
139
  }, autoFocus: true }));
135
140
  };
136
141
  const CreateKeywordButtonElement = () => {
package/dist/es/menus.js CHANGED
@@ -17,7 +17,7 @@ import { schema } from '@manuscripts/transform';
17
17
  import { toggleMark } from 'prosemirror-commands';
18
18
  import { redo, undo } from 'prosemirror-history';
19
19
  import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, deleteColumn, deleteRow, } from 'prosemirror-tables';
20
- import { addInlineComment, blockActive, canInsert, ifInTableBody, insertBlock, insertCrossReference, insertGraphicalAbstract, insertInlineCitation, insertInlineEquation, insertInlineFootnote, insertLink, insertList, insertSection, markActive, } from './commands';
20
+ import { addInlineComment, blockActive, canInsert, ifInTableBody, insertAbstract, insertBackMatterSection, insertBlock, insertContributors, insertCrossReference, insertGraphicalAbstract, insertInlineCitation, insertInlineEquation, insertInlineFootnote, insertKeywords, insertLink, insertList, insertSection, markActive, } from './commands';
21
21
  import { deleteClosestParentElement, findClosestParentElementNodeName, } from './lib/hierarchy';
22
22
  export const getEditorMenus = (editor) => {
23
23
  const { isCommandValid, state } = editor;
@@ -69,6 +69,92 @@ export const getEditorMenus = (editor) => {
69
69
  label: 'Insert',
70
70
  isEnabled: true,
71
71
  submenu: [
72
+ {
73
+ id: 'front-matter',
74
+ label: 'Article Metadata',
75
+ isEnabled: true,
76
+ submenu: [
77
+ {
78
+ id: 'insert-abstract',
79
+ label: 'Abstract',
80
+ isEnabled: isCommandValid(insertAbstract),
81
+ run: doCommand(insertAbstract),
82
+ },
83
+ {
84
+ id: 'insert-graphical-abstract',
85
+ label: 'Graphical Abstract',
86
+ isEnabled: isCommandValid(insertGraphicalAbstract),
87
+ run: doCommand(insertGraphicalAbstract),
88
+ },
89
+ {
90
+ id: 'insert-contributors',
91
+ label: 'Authors & Affiliations',
92
+ isEnabled: isCommandValid(insertContributors),
93
+ run: doCommand(insertContributors),
94
+ },
95
+ {
96
+ id: 'insert-keywords',
97
+ label: 'Keywords',
98
+ isEnabled: isCommandValid(insertKeywords),
99
+ run: doCommand(insertKeywords),
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ id: 'back-matter',
105
+ label: 'Author Notes',
106
+ isEnabled: true,
107
+ submenu: [
108
+ {
109
+ id: 'insert-acknowledgements',
110
+ label: 'Acknowledgements',
111
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:acknowledgement')),
112
+ run: doCommand(insertBackMatterSection('MPSectionCategory:acknowledgement')),
113
+ },
114
+ {
115
+ id: 'insert-availability',
116
+ label: 'Availability',
117
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:availability')),
118
+ run: doCommand(insertBackMatterSection('MPSectionCategory:availability')),
119
+ },
120
+ {
121
+ id: 'insert-coi-statement',
122
+ label: 'COI Statement',
123
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:competing-interests')),
124
+ run: doCommand(insertBackMatterSection('MPSectionCategory:competing-interests')),
125
+ },
126
+ {
127
+ id: 'insert-con',
128
+ label: 'Contributed-by Information',
129
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:con')),
130
+ run: doCommand(insertBackMatterSection('MPSectionCategory:con')),
131
+ },
132
+ {
133
+ id: 'insert-ethics-statement',
134
+ label: 'Ethics Statement',
135
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:ethics-statement')),
136
+ run: doCommand(insertBackMatterSection('MPSectionCategory:ethics-statement')),
137
+ },
138
+ {
139
+ id: 'insert-financial-disclosure',
140
+ label: 'Financial Disclosure',
141
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:financial-disclosure')),
142
+ run: doCommand(insertBackMatterSection('MPSectionCategory:financial-disclosure')),
143
+ },
144
+ {
145
+ id: 'insert-supplementary-material',
146
+ label: 'Supplementary Material',
147
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:supplementary-material')),
148
+ run: doCommand(insertBackMatterSection('MPSectionCategory:supplementary-material')),
149
+ },
150
+ {
151
+ id: 'insert-supported-by',
152
+ label: 'Supported By',
153
+ isEnabled: isCommandValid(insertBackMatterSection('MPSectionCategory:supported-by')),
154
+ run: doCommand(insertBackMatterSection('MPSectionCategory:supported-by')),
155
+ },
156
+ ],
157
+ },
72
158
  {
73
159
  id: 'insert-section',
74
160
  label: 'Section',
@@ -79,12 +165,6 @@ export const getEditorMenus = (editor) => {
79
165
  isEnabled: isCommandValid(insertSection()),
80
166
  run: doCommand(insertSection()),
81
167
  },
82
- {
83
- id: 'insert-graphical-abstract',
84
- label: 'Graphical Abstract',
85
- isEnabled: isCommandValid(insertGraphicalAbstract),
86
- run: doCommand(insertGraphicalAbstract),
87
- },
88
168
  {
89
169
  id: 'insert-subsection',
90
170
  label: 'Subsection',
@@ -53,6 +53,12 @@ export class ContributorsView extends BlockView {
53
53
  this.createLegend();
54
54
  this.updateSelection();
55
55
  };
56
+ this.selectNode = () => {
57
+ this.dom.classList.add('ProseMirror-selectednode');
58
+ if (!isDeleted(this.node)) {
59
+ this.handleEdit('');
60
+ }
61
+ };
56
62
  this.buildAuthors = (affs) => {
57
63
  const wrapper = document.createElement('div');
58
64
  wrapper.classList.add('contributors-list');
@@ -22,10 +22,14 @@ export class TitleView extends BaseNodeView {
22
22
  this.createDOM();
23
23
  };
24
24
  this.createDOM = () => {
25
+ const attrs = this.node.attrs;
25
26
  this.dom = document.createElement('div');
26
27
  this.dom.classList.add('manuscript-title');
27
28
  this.contentDOM = document.createElement('div');
28
29
  this.contentDOM.classList.add('article-titles');
30
+ if (!this.node.childCount && attrs.placeholder) {
31
+ this.contentDOM.setAttribute('data-placeholder', attrs.placeholder);
32
+ }
29
33
  this.dom.appendChild(this.contentDOM);
30
34
  };
31
35
  }
@@ -38,8 +38,12 @@ export declare const insertInlineCitation: (state: ManuscriptEditorState, dispat
38
38
  export declare const insertCrossReference: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
39
39
  export declare const insertInlineEquation: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
40
40
  export declare const insertInlineFootnote: (kind: 'footnote' | 'endnote') => (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
41
- export declare const insertGraphicalAbstract: (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
42
- export declare const insertSection: (subsection?: boolean) => (state: ManuscriptEditorState, dispatch?: Dispatch) => boolean;
41
+ export declare const insertGraphicalAbstract: (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
42
+ export declare const insertSection: (subsection?: boolean) => (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
43
+ export declare const insertBackMatterSection: (category: string) => (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
44
+ export declare const insertAbstract: (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
45
+ export declare const insertContributors: (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
46
+ export declare const insertKeywords: (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
43
47
  export declare const insertList: (type: ManuscriptNodeType, style?: string) => (state: ManuscriptEditorState, dispatch?: Dispatch, view?: EditorView) => boolean;
44
48
  export declare const insertBibliographySection: () => boolean;
45
49
  export declare const insertTOCSection: () => boolean;
@@ -27,6 +27,7 @@ export declare class ContributorsView extends BlockView<EditableBlockProps> {
27
27
  stopEvent: () => boolean;
28
28
  initialise: () => void;
29
29
  updateContents: () => void;
30
+ selectNode: () => void;
30
31
  buildAuthors: (affs: PluginState) => void;
31
32
  buildAuthor: (attrs: ContributorAttrs, isJointFirstAuthor: boolean) => HTMLSpanElement;
32
33
  private createNote;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/body-editor",
3
3
  "description": "Prosemirror components for editing and viewing manuscripts",
4
- "version": "1.13.1",
4
+ "version": "1.13.2-LEAN-3307.0",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -28,11 +28,11 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@iarna/word-count": "^1.1.2",
31
- "@manuscripts/json-schema": "2.2.8",
32
- "@manuscripts/library": "1.3.7",
33
- "@manuscripts/style-guide": "1.13.0",
31
+ "@manuscripts/json-schema": "2.2.9-LEAN-3307.0",
32
+ "@manuscripts/library": "1.3.8-LEAN-3307.0",
33
+ "@manuscripts/style-guide": "1.13.1-LEAN-3307.0",
34
34
  "@manuscripts/track-changes-plugin": "1.7.13",
35
- "@manuscripts/transform": "2.3.9",
35
+ "@manuscripts/transform": "2.3.9-LEAN-3307.1",
36
36
  "astrocite-eutils": "^0.16.4",
37
37
  "mathjax-full": "^3.2.2",
38
38
  "codemirror": "^5.58.1",
@@ -941,3 +941,7 @@ span.accepted .selected-suggestion,
941
941
  .ProseMirror li.ProseMirror-selectednode:after {
942
942
  content: none;
943
943
  }
944
+
945
+ .ProseMirror .manuscript-title.empty-node .article-titles::before {
946
+ content: attr(data-placeholder);
947
+ }
package/styles/Editor.css CHANGED
@@ -562,6 +562,15 @@
562
562
  .ProseMirror .empty-node:hover::before {
563
563
  color: #6e6e6e;
564
564
  }
565
+ .ProseMirror .empty-node .article-titles::before {
566
+ position: absolute;
567
+ color: #c9c9c9;
568
+ font-style: italic;
569
+ font-family: "PT Sans";
570
+ font-size: 28px;
571
+ font-weight: 400;
572
+ line-height: 40px;
573
+ }
565
574
 
566
575
  .ProseMirror .empty-node[data-placeholder]::before {
567
576
  content: attr(data-placeholder); /* TODO: innerHTML? */