@manuscripts/body-editor 3.6.10 → 3.6.12

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.
Files changed (50) hide show
  1. package/dist/cjs/commands.js +12 -9
  2. package/dist/cjs/components/LanguageDropdown/index.js +3 -18
  3. package/dist/cjs/components/LanguageDropdown/languages.js +16 -112
  4. package/dist/cjs/components/outline/DraggableTree.js +1 -0
  5. package/dist/cjs/configs/editor-views.js +4 -1
  6. package/dist/cjs/lib/doc.js +7 -5
  7. package/dist/cjs/plugins/placeholder.js +3 -0
  8. package/dist/cjs/versions.js +1 -1
  9. package/dist/cjs/views/abstracts.js +0 -36
  10. package/dist/cjs/views/editable_block.js +1 -0
  11. package/dist/cjs/views/section.js +83 -0
  12. package/dist/cjs/views/section_title.js +1 -0
  13. package/dist/cjs/views/supplement.js +175 -0
  14. package/dist/cjs/views/supplement_editable.js +20 -0
  15. package/dist/cjs/views/supplements.js +56 -0
  16. package/dist/cjs/views/supplements_editable.js +21 -0
  17. package/dist/cjs/views/translated_abstract.js +7 -5
  18. package/dist/es/commands.js +13 -10
  19. package/dist/es/components/LanguageDropdown/index.js +4 -19
  20. package/dist/es/components/LanguageDropdown/languages.js +15 -72
  21. package/dist/es/components/outline/DraggableTree.js +1 -0
  22. package/dist/es/configs/editor-views.js +4 -1
  23. package/dist/es/lib/doc.js +5 -3
  24. package/dist/es/plugins/placeholder.js +3 -0
  25. package/dist/es/versions.js +1 -1
  26. package/dist/es/views/abstracts.js +0 -36
  27. package/dist/es/views/editable_block.js +1 -0
  28. package/dist/es/views/section.js +83 -0
  29. package/dist/es/views/section_title.js +1 -0
  30. package/dist/es/views/supplement.js +171 -0
  31. package/dist/es/views/supplement_editable.js +18 -0
  32. package/dist/es/views/supplements.js +49 -0
  33. package/dist/es/views/supplements_editable.js +19 -0
  34. package/dist/es/views/translated_abstract.js +8 -6
  35. package/dist/types/commands.d.ts +1 -1
  36. package/dist/types/components/LanguageDropdown/index.d.ts +2 -0
  37. package/dist/types/components/LanguageDropdown/languages.d.ts +21 -12
  38. package/dist/types/configs/ManuscriptsEditor.d.ts +2 -0
  39. package/dist/types/lib/doc.d.ts +2 -2
  40. package/dist/types/versions.d.ts +1 -1
  41. package/dist/types/views/abstracts.d.ts +0 -2
  42. package/dist/types/views/section.d.ts +7 -0
  43. package/dist/types/views/supplement.d.ts +37 -0
  44. package/dist/types/views/supplement_editable.d.ts +18 -0
  45. package/dist/types/views/supplements.d.ts +27 -0
  46. package/dist/types/views/supplements_editable.d.ts +44 -0
  47. package/dist/types/views/translated_abstract.d.ts +1 -1
  48. package/package.json +2 -3
  49. package/styles/AdvancedEditor.css +32 -4
  50. package/styles/Editor.css +159 -0
@@ -297,18 +297,21 @@ const insertTable = (config, state, dispatch) => {
297
297
  return true;
298
298
  };
299
299
  exports.insertTable = insertTable;
300
- const insertSupplement = (file, state, dispatch) => {
300
+ const insertSupplement = (file, view) => {
301
301
  const supplement = transform_1.schema.nodes.supplement.createAndFill({
302
302
  id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.supplement),
303
303
  href: file.id,
304
- });
305
- const tr = state.tr;
306
- const supplements = (0, doc_1.insertSupplementsNode)(tr);
307
- const pos = supplements.pos + supplements.node.nodeSize - 1;
308
- tr.insert(pos, supplement);
309
- if (dispatch) {
310
- dispatch((0, track_changes_plugin_1.skipTracking)(tr));
311
- }
304
+ }, [
305
+ transform_1.schema.nodes.figcaption.create({}, [
306
+ transform_1.schema.nodes.caption_title.create(),
307
+ transform_1.schema.nodes.caption.create(),
308
+ ]),
309
+ ]);
310
+ const tr = view.state.tr;
311
+ const { pos } = (0, doc_1.upsertSupplementsSection)(tr, supplement);
312
+ tr.setSelection(prosemirror_state_1.NodeSelection.create(tr.doc, pos));
313
+ view.focus();
314
+ view.dispatch(tr.scrollIntoView());
312
315
  return true;
313
316
  };
314
317
  exports.insertSupplement = insertSupplement;
@@ -60,24 +60,9 @@ const LanguageOptionItem = ({ language, isSelected, onSelect }) => (react_1.defa
60
60
  language.nativeName && ` (${language.nativeName})`,
61
61
  isSelected && (react_1.default.createElement(TickIconWrapper, null,
62
62
  react_1.default.createElement(style_guide_1.TickIcon, null)))));
63
- const LanguageDropdown = ({ onLanguageSelect, onClose, currentLanguage = 'en', showButton = false, selectedLanguageDisplay, onCloseParent, }) => {
64
- const [allLanguages, setAllLanguages] = (0, react_1.useState)([]);
63
+ const LanguageDropdown = ({ onLanguageSelect, onClose, currentLanguage = 'en', showButton = false, selectedLanguageDisplay, onCloseParent, languages, }) => {
65
64
  const [isOpen, setIsOpen] = (0, react_1.useState)(!showButton);
66
65
  const dropdownRef = (0, react_1.useRef)(null);
67
- (0, react_1.useEffect)(() => {
68
- const loadLanguages = async () => {
69
- try {
70
- const languages = await (0, languages_1.loadAllLanguages)();
71
- const sortedLanguages = (0, languages_1.sortLanguagesByCommonality)(languages);
72
- setAllLanguages(sortedLanguages);
73
- }
74
- catch (error) {
75
- console.error('Failed to load language data:', error);
76
- setAllLanguages([]);
77
- }
78
- };
79
- loadLanguages();
80
- }, []);
81
66
  (0, react_1.useEffect)(() => {
82
67
  const handleClickOutside = (event) => {
83
68
  if (dropdownRef.current &&
@@ -103,7 +88,7 @@ const LanguageDropdown = ({ onLanguageSelect, onClose, currentLanguage = 'en', s
103
88
  onLanguageSelect(languageCode);
104
89
  };
105
90
  const getDisplayName = (languageCode) => {
106
- return (0, languages_1.getSelectedLanguageName)(languageCode, allLanguages);
91
+ return (0, languages_1.getSelectedLanguageName)(languageCode, languages);
107
92
  };
108
93
  return (react_1.default.createElement(style_guide_1.DropdownContainer, { ref: dropdownRef },
109
94
  showButton && (react_1.default.createElement(LanguageButton, { onClick: toggleDropdown },
@@ -114,7 +99,7 @@ const LanguageDropdown = ({ onLanguageSelect, onClose, currentLanguage = 'en', s
114
99
  react_1.default.createElement(SelectedLanguage, null, selectedLanguageDisplay || getDisplayName(currentLanguage))))),
115
100
  isOpen && (react_1.default.createElement(DropdownMenu, { direction: "right", width: 231, height: 400, top: 18 },
116
101
  !showButton && react_1.default.createElement(DropdownTitle, null, "Choose language"),
117
- allLanguages.map((language) => (react_1.default.createElement(LanguageOptionItem, { key: language.code, language: language, isSelected: currentLanguage === language.code, onSelect: handleSelect })))))));
102
+ languages.map((language) => (react_1.default.createElement(LanguageOptionItem, { key: language.code, language: language, isSelected: currentLanguage === language.code, onSelect: handleSelect })))))));
118
103
  };
119
104
  const StyledDropdownList = (0, styled_components_1.default)(style_guide_1.DropdownList) `
120
105
  overflow-y: auto;
@@ -1,98 +1,26 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
38
17
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.sortLanguagesByCommonality = exports.getLanguageDisplayName = exports.getSelectedLanguageName = exports.loadAllLanguages = exports.initializeLanguageData = exports.ENGLISH_FALLBACK = exports.COMMON_LANGUAGES = exports.COMMON_LANGUAGES_INFO = void 0;
40
- const i18n_iso_languages_1 = __importDefault(require("@cospired/i18n-iso-languages"));
41
- exports.COMMON_LANGUAGES_INFO = {
42
- en: { englishName: 'English', nativeName: 'Default' },
43
- es: { englishName: 'Spanish', nativeName: 'Español' },
44
- fr: { englishName: 'French', nativeName: 'Français' },
45
- de: { englishName: 'German', nativeName: 'Deutsch' },
46
- it: { englishName: 'Italian', nativeName: 'Italiano' },
47
- pt: { englishName: 'Portuguese', nativeName: 'Português' },
48
- ru: { englishName: 'Russian', nativeName: 'Русский' },
49
- ja: { englishName: 'Japanese', nativeName: '日本語' },
50
- ko: { englishName: 'Korean', nativeName: '한국어' },
51
- zh: { englishName: 'Chinese', nativeName: '中文' },
52
- ar: { englishName: 'Arabic', nativeName: 'العربية' },
53
- };
54
- exports.COMMON_LANGUAGES = Object.keys(exports.COMMON_LANGUAGES_INFO);
18
+ exports.getLanguageDisplayName = exports.getSelectedLanguageName = exports.ENGLISH_FALLBACK = void 0;
55
19
  exports.ENGLISH_FALLBACK = {
56
20
  code: 'en',
57
21
  name: 'English',
58
22
  nativeName: 'English',
59
- isCommon: true,
60
- };
61
- const initializeLanguageData = async () => {
62
- try {
63
- const englishLanguageData = await Promise.resolve().then(() => __importStar(require('@cospired/i18n-iso-languages/langs/en.json')));
64
- i18n_iso_languages_1.default.registerLocale(englishLanguageData.default);
65
- }
66
- catch (error) {
67
- console.error('Failed to initialize language data:', error);
68
- throw error;
69
- }
70
23
  };
71
- exports.initializeLanguageData = initializeLanguageData;
72
- const loadAllLanguages = async () => {
73
- try {
74
- await (0, exports.initializeLanguageData)();
75
- const languageCodes = i18n_iso_languages_1.default.getAlpha2Codes();
76
- return Object.keys(languageCodes).map((code) => {
77
- const commonLanguageInfo = exports.COMMON_LANGUAGES_INFO[code];
78
- return {
79
- code,
80
- name: commonLanguageInfo?.englishName ||
81
- i18n_iso_languages_1.default.getName(code, 'en') ||
82
- code.toUpperCase(),
83
- nativeName: commonLanguageInfo?.nativeName ||
84
- i18n_iso_languages_1.default.getName(code, code) ||
85
- undefined,
86
- isCommon: exports.COMMON_LANGUAGES.includes(code),
87
- };
88
- });
89
- }
90
- catch (error) {
91
- console.error('Failed to load languages:', error);
92
- return [exports.ENGLISH_FALLBACK];
93
- }
94
- };
95
- exports.loadAllLanguages = loadAllLanguages;
96
24
  const getSelectedLanguageName = (selectedLanguage, allLanguages) => {
97
25
  if (!allLanguages.length) {
98
26
  return 'English (Default)';
@@ -105,30 +33,6 @@ const getSelectedLanguageName = (selectedLanguage, allLanguages) => {
105
33
  };
106
34
  exports.getSelectedLanguageName = getSelectedLanguageName;
107
35
  const getLanguageDisplayName = (languageCode) => {
108
- const languageInfo = exports.COMMON_LANGUAGES_INFO[languageCode];
109
- if (languageInfo) {
110
- const { englishName, nativeName } = languageInfo;
111
- if (nativeName !== englishName && nativeName !== 'Default') {
112
- return `${englishName} (${nativeName})`;
113
- }
114
- return englishName;
115
- }
116
- const englishName = i18n_iso_languages_1.default.getName(languageCode, 'en');
117
- if (englishName) {
118
- return englishName;
119
- }
120
36
  return languageCode.toUpperCase();
121
37
  };
122
38
  exports.getLanguageDisplayName = getLanguageDisplayName;
123
- const sortLanguagesByCommonality = (languages) => {
124
- return [...languages].sort((a, b) => {
125
- if (a.isCommon && !b.isCommon) {
126
- return -1;
127
- }
128
- if (!a.isCommon && b.isCommon) {
129
- return 1;
130
- }
131
- return a.name.localeCompare(b.name);
132
- });
133
- };
134
- exports.sortLanguagesByCommonality = sortLanguagesByCommonality;
@@ -63,6 +63,7 @@ const excludedTypes = [
63
63
  transform_1.schema.nodes.trans_abstract,
64
64
  transform_1.schema.nodes.subtitles,
65
65
  transform_1.schema.nodes.subtitle,
66
+ transform_1.schema.nodes.supplements,
66
67
  ];
67
68
  const childrenExcludedTypes = [
68
69
  transform_1.schema.nodes.pullquote_element,
@@ -47,6 +47,8 @@ const section_label_1 = __importDefault(require("../views/section_label"));
47
47
  const section_title_editable_1 = __importDefault(require("../views/section_title_editable"));
48
48
  const subtitle_editable_1 = __importDefault(require("../views/subtitle_editable"));
49
49
  const subtitles_editable_1 = __importDefault(require("../views/subtitles_editable"));
50
+ const supplement_editable_1 = __importDefault(require("../views/supplement_editable"));
51
+ const supplements_editable_1 = __importDefault(require("../views/supplements_editable"));
50
52
  const table_cell_1 = __importDefault(require("../views/table_cell"));
51
53
  const table_element_editable_1 = __importDefault(require("../views/table_element_editable"));
52
54
  const table_element_footer_1 = __importDefault(require("../views/table_element_footer"));
@@ -96,7 +98,8 @@ exports.default = (props, dispatch) => {
96
98
  table_header: (0, table_cell_1.default)(props),
97
99
  table_element_footer: (0, table_element_footer_1.default)(props),
98
100
  comments: (0, empty_1.default)('comments'),
99
- supplements: (0, empty_1.default)('supplements'),
101
+ supplements: (0, supplements_editable_1.default)(props, dispatch),
102
+ supplement: (0, supplement_editable_1.default)(props, dispatch),
100
103
  author_notes: (0, author_notes_1.default)(props, dispatch),
101
104
  awards: (0, awards_1.default)(props, dispatch),
102
105
  award: (0, award_1.default)(props, dispatch),
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findNodeByID = exports.findGraphicalAbstractFigureElement = exports.findFootnotesSection = exports.findBibliographySection = exports.findBackmatter = exports.findBody = exports.findAbstractsNode = exports.insertFootnotesSection = exports.insertAttachmentsNode = exports.insertSupplementsNode = exports.insertAwardsNode = void 0;
3
+ exports.findNodeByID = exports.findGraphicalAbstractFigureElement = exports.findFootnotesSection = exports.findBibliographySection = exports.findBackmatter = exports.findBody = exports.findAbstractsNode = exports.insertFootnotesSection = exports.insertAttachmentsNode = exports.upsertSupplementsSection = exports.insertAwardsNode = void 0;
4
4
  const transform_1 = require("@manuscripts/transform");
5
5
  const prosemirror_utils_1 = require("prosemirror-utils");
6
6
  const utils_1 = require("./utils");
@@ -19,21 +19,23 @@ const insertAwardsNode = (tr) => {
19
19
  };
20
20
  };
21
21
  exports.insertAwardsNode = insertAwardsNode;
22
- const insertSupplementsNode = (tr) => {
22
+ const upsertSupplementsSection = (tr, supplement) => {
23
23
  const doc = tr.doc;
24
24
  const supplements = (0, prosemirror_utils_1.findChildrenByType)(doc, transform_1.schema.nodes.supplements)[0];
25
25
  if (supplements) {
26
- return supplements;
26
+ const pos = supplements.pos + supplements.node.nodeSize - 1;
27
+ tr.insert(pos, supplement);
28
+ return { node: supplements.node, pos };
27
29
  }
28
30
  const pos = (0, utils_1.findInsertionPosition)(transform_1.schema.nodes.supplements, doc);
29
- const node = transform_1.schema.nodes.supplements.createAndFill();
31
+ const node = transform_1.schema.nodes.supplements.createAndFill({ id: (0, transform_1.generateNodeID)(transform_1.schema.nodes.supplements) }, [supplement]);
30
32
  tr.insert(pos, node);
31
33
  return {
32
34
  node,
33
35
  pos,
34
36
  };
35
37
  };
36
- exports.insertSupplementsNode = insertSupplementsNode;
38
+ exports.upsertSupplementsSection = upsertSupplementsSection;
37
39
  const insertAttachmentsNode = (tr) => {
38
40
  const attachmentsNodes = (0, prosemirror_utils_1.findChildrenByType)(tr.doc, transform_1.schema.nodes.attachments);
39
41
  if (attachmentsNodes.length) {
@@ -84,6 +84,9 @@ exports.default = () => new prosemirror_state_1.Plugin({
84
84
  if ((0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.box_element)) {
85
85
  placeholderText = 'Optional box title...';
86
86
  }
87
+ if ((0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.supplements)) {
88
+ placeholderText = 'Supplements';
89
+ }
87
90
  decorations.push(prosemirror_view_1.Decoration.widget(pos + 1, placeholderWidget(placeholderText)));
88
91
  }
89
92
  else if (node.type === node.type.schema.nodes.trans_abstract) {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '3.6.10';
4
+ exports.VERSION = '3.6.12';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -16,29 +16,12 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.AbstractsView = void 0;
19
- const prosemirror_state_1 = require("prosemirror-state");
20
- const icons_1 = require("../icons");
21
19
  const base_node_view_1 = require("./base_node_view");
22
20
  const creators_1 = require("./creators");
23
21
  class AbstractsView extends base_node_view_1.BaseNodeView {
24
22
  constructor() {
25
23
  super(...arguments);
26
24
  this.elementType = 'div';
27
- this.addTranslation = () => {
28
- const { state } = this.view;
29
- const { schema } = state;
30
- const documentLanguage = state.doc.attrs.primaryLanguageCode || 'en';
31
- const sectionTitle = schema.nodes.section_title.create();
32
- const paragraph = schema.nodes.paragraph.create();
33
- const transAbstractNode = schema.nodes.trans_abstract.create({
34
- lang: documentLanguage,
35
- }, [sectionTitle, paragraph]);
36
- const tr = state.tr.insert(this.getPos() + this.node.nodeSize - 1, transAbstractNode);
37
- const titlePos = this.getPos() + this.node.nodeSize;
38
- const selection = prosemirror_state_1.TextSelection.create(tr.doc, titlePos);
39
- tr.setSelection(selection).scrollIntoView();
40
- this.view.dispatch(tr);
41
- };
42
25
  }
43
26
  initialise() {
44
27
  this.createDOM();
@@ -52,25 +35,6 @@ class AbstractsView extends base_node_view_1.BaseNodeView {
52
35
  createElement() {
53
36
  this.contentDOM = document.createElement(this.elementType);
54
37
  this.dom.appendChild(this.contentDOM);
55
- this.addTranslationBtn();
56
- }
57
- addTranslationBtn() {
58
- if (this.props.getCapabilities()?.editArticle) {
59
- const btnContainer = document.createElement('div');
60
- btnContainer.classList.add('add-translation-container');
61
- btnContainer.addEventListener('click', () => this.addTranslation());
62
- const addTranslationBtn = Object.assign(document.createElement('button'), {
63
- className: 'add-button',
64
- innerHTML: icons_1.addBtnIcon,
65
- title: 'Add Translation',
66
- });
67
- const textElement = document.createElement('span');
68
- textElement.textContent = 'Add translation';
69
- textElement.classList.add('add-translation-text');
70
- btnContainer.appendChild(addTranslationBtn);
71
- btnContainer.appendChild(textElement);
72
- this.dom.prepend(btnContainer);
73
- }
74
38
  }
75
39
  updateContents() {
76
40
  super.updateContents();
@@ -42,6 +42,7 @@ const EditableBlock = (Base) => {
42
42
  const nodeType = this.node.type;
43
43
  if (nodeType === transform_1.schema.nodes.hero_image ||
44
44
  nodeType === transform_1.schema.nodes.subtitles ||
45
+ nodeType === transform_1.schema.nodes.supplements ||
45
46
  (0, utils_1.hasParent)($pos, [
46
47
  transform_1.schema.nodes.keywords,
47
48
  transform_1.schema.nodes.bibliography_section,
@@ -19,6 +19,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.SectionView = void 0;
22
+ const transform_1 = require("@manuscripts/transform");
23
+ const prosemirror_state_1 = require("prosemirror-state");
24
+ const prosemirror_utils_1 = require("prosemirror-utils");
25
+ const icons_1 = require("../icons");
22
26
  const section_title_1 = require("../plugins/section_title");
23
27
  const block_view_1 = __importDefault(require("./block_view"));
24
28
  const creators_1 = require("./creators");
@@ -26,6 +30,26 @@ class SectionView extends block_view_1.default {
26
30
  constructor() {
27
31
  super(...arguments);
28
32
  this.elementType = 'section';
33
+ this.addTranslationButton = null;
34
+ this.addTranslation = () => {
35
+ const { state } = this.view;
36
+ const { schema } = state;
37
+ const documentLanguage = state.doc.attrs.primaryLanguageCode || 'en';
38
+ const sectionTitle = schema.nodes.section_title.create();
39
+ const paragraph = schema.nodes.paragraph.create();
40
+ const transAbstractNode = schema.nodes.trans_abstract.create({
41
+ lang: documentLanguage,
42
+ category: this.node.attrs.category,
43
+ }, [sectionTitle, paragraph]);
44
+ const abstracts = (0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)(this.view.state.doc.resolve(this.getPos()), schema.nodes.abstracts);
45
+ if (abstracts) {
46
+ const tr = state.tr.insert(abstracts.pos + abstracts.node.nodeSize - 1, transAbstractNode);
47
+ const titlePos = abstracts.pos + abstracts.node.nodeSize;
48
+ const selection = prosemirror_state_1.TextSelection.create(tr.doc, titlePos);
49
+ tr.setSelection(selection).scrollIntoView();
50
+ this.view.dispatch(tr);
51
+ }
52
+ };
29
53
  }
30
54
  initialise() {
31
55
  this.createDOM();
@@ -40,6 +64,7 @@ class SectionView extends block_view_1.default {
40
64
  super.updateContents();
41
65
  this.dom.setAttribute('data-category', this.node.attrs.category);
42
66
  this.handleSectionNumbering();
67
+ this.handleAddTranslationButton();
43
68
  }
44
69
  handleSectionNumbering() {
45
70
  const sections = section_title_1.sectionTitleKey.getState(this.view.state);
@@ -54,6 +79,64 @@ class SectionView extends block_view_1.default {
54
79
  }
55
80
  });
56
81
  }
82
+ handleAddTranslationButton() {
83
+ this.cleanupAddTranslationButton();
84
+ const $pos = this.view.state.doc.resolve(this.getPos());
85
+ const isInAbstracts = (0, prosemirror_utils_1.findParentNodeOfTypeClosestToPos)($pos, transform_1.schema.nodes.abstracts);
86
+ const isAbstractCategory = this.isAbstractCategory(this.node.attrs.category);
87
+ if (isInAbstracts &&
88
+ isAbstractCategory &&
89
+ this.props.getCapabilities()?.editArticle) {
90
+ this.createAddTranslationButton();
91
+ }
92
+ }
93
+ isAbstractCategory(category) {
94
+ const sectionCategories = this.props.sectionCategories;
95
+ if (!sectionCategories) {
96
+ return false;
97
+ }
98
+ const categoryObj = sectionCategories.get(category);
99
+ if (!categoryObj) {
100
+ return false;
101
+ }
102
+ return (categoryObj.group === 'abstracts' ||
103
+ categoryObj.group === 'abstracts-graphic');
104
+ }
105
+ createAddTranslationButton() {
106
+ const btnContainer = document.createElement('div');
107
+ btnContainer.classList.add('add-translation-container');
108
+ btnContainer.addEventListener('mousedown', (event) => {
109
+ event.preventDefault();
110
+ event.stopPropagation();
111
+ this.addTranslation();
112
+ });
113
+ const addTranslationBtn = Object.assign(document.createElement('button'), {
114
+ className: 'add-button',
115
+ innerHTML: icons_1.addBtnIcon,
116
+ title: 'Add Translation',
117
+ type: 'button',
118
+ });
119
+ const textElement = document.createElement('span');
120
+ textElement.textContent = 'Add translation';
121
+ textElement.classList.add('add-translation-text');
122
+ btnContainer.appendChild(addTranslationBtn);
123
+ btnContainer.appendChild(textElement);
124
+ this.dom.appendChild(btnContainer);
125
+ this.addTranslationButton = addTranslationBtn;
126
+ }
127
+ cleanupAddTranslationButton() {
128
+ if (this.addTranslationButton) {
129
+ const container = this.addTranslationButton.closest('.add-translation-container');
130
+ if (container) {
131
+ container.remove();
132
+ }
133
+ this.addTranslationButton = null;
134
+ }
135
+ }
136
+ destroy() {
137
+ this.cleanupAddTranslationButton();
138
+ super.destroy();
139
+ }
57
140
  }
58
141
  exports.SectionView = SectionView;
59
142
  exports.default = (0, creators_1.createNodeView)(SectionView);
@@ -32,6 +32,7 @@ class SectionTitleView extends block_view_1.default {
32
32
  transform_1.schema.nodes.bibliography_section,
33
33
  transform_1.schema.nodes.footnotes_section,
34
34
  transform_1.schema.nodes.graphical_abstract_section,
35
+ transform_1.schema.nodes.supplements,
35
36
  ];
36
37
  this.createElement = () => {
37
38
  this.contentDOM = document.createElement(this.elementType);
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2025 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.SupplementView = void 0;
19
+ const style_guide_1 = require("@manuscripts/style-guide");
20
+ const server_1 = require("react-dom/server");
21
+ const icons_1 = require("../icons");
22
+ const doc_1 = require("../lib/doc");
23
+ const base_node_view_1 = require("./base_node_view");
24
+ const creators_1 = require("./creators");
25
+ class SupplementView extends base_node_view_1.BaseNodeView {
26
+ constructor() {
27
+ super(...arguments);
28
+ this.ignoreMutation = () => true;
29
+ this.createElement = () => {
30
+ this.dom = document.createElement('div');
31
+ this.dom.classList.add('supplement-item');
32
+ this.dom.classList.add('block');
33
+ this.dom.setAttribute('id', this.node.attrs.id);
34
+ this.dom.setAttribute('href', this.node.attrs.href);
35
+ this.dom.draggable = true;
36
+ this.contentDOM = document.createElement('div');
37
+ this.contentDOM.classList.add('supplement-caption');
38
+ this.dom.appendChild(this.contentDOM);
39
+ this.addFileInfo();
40
+ this.addDragIcon();
41
+ };
42
+ }
43
+ initialise() {
44
+ this.createElement();
45
+ this.updateContents();
46
+ this.setupDragAndDrop();
47
+ }
48
+ updateContents() {
49
+ super.updateContents();
50
+ this.refreshFileInfo();
51
+ }
52
+ getDropSide(element, clientY) {
53
+ const { top, bottom } = element.getBoundingClientRect();
54
+ const middleY = (top + bottom) / 2;
55
+ return clientY > middleY ? 'after' : 'before';
56
+ }
57
+ noActualMove(currentPos, nodeSize, targetPos) {
58
+ return targetPos === currentPos || targetPos === currentPos + nodeSize;
59
+ }
60
+ handleDragStart() {
61
+ const supplementId = this.node.attrs.id;
62
+ SupplementView.currentDragSupplementId = supplementId;
63
+ this.dom.classList.add('dragging');
64
+ }
65
+ setupDragAndDrop() {
66
+ const clearDropClasses = () => {
67
+ this.dom.classList.remove('drop-target-above', 'drop-target-below');
68
+ };
69
+ this.dom.addEventListener('dragstart', () => {
70
+ if (this.node.attrs.id) {
71
+ this.handleDragStart();
72
+ }
73
+ });
74
+ this.dom.addEventListener('dragend', () => {
75
+ SupplementView.currentDragSupplementId = null;
76
+ this.dom.classList.remove('dragging');
77
+ clearDropClasses();
78
+ });
79
+ this.dom.addEventListener('dragover', (e) => {
80
+ if (SupplementView.currentDragSupplementId) {
81
+ e.preventDefault();
82
+ e.stopPropagation();
83
+ const side = this.getDropSide(this.dom, e.clientY);
84
+ clearDropClasses();
85
+ this.dom.classList.add(side === 'before' ? 'drop-target-above' : 'drop-target-below');
86
+ }
87
+ });
88
+ this.dom.addEventListener('dragleave', (e) => {
89
+ if (!this.dom.contains(e.relatedTarget)) {
90
+ clearDropClasses();
91
+ }
92
+ });
93
+ this.dom.addEventListener('drop', (e) => {
94
+ if (!SupplementView.currentDragSupplementId) {
95
+ return;
96
+ }
97
+ e.preventDefault();
98
+ e.stopPropagation();
99
+ const supplementId = SupplementView.currentDragSupplementId;
100
+ if (!supplementId) {
101
+ return;
102
+ }
103
+ const { state } = this.view;
104
+ const supplement = (0, doc_1.findNodeByID)(state.doc, supplementId);
105
+ if (!supplement) {
106
+ return;
107
+ }
108
+ const toPos = this.getPos();
109
+ const side = this.getDropSide(this.dom, e.clientY);
110
+ const targetPos = side === 'before' ? toPos : toPos + this.node.nodeSize;
111
+ if (this.noActualMove(supplement.pos, supplement.node.nodeSize, targetPos)) {
112
+ clearDropClasses();
113
+ return;
114
+ }
115
+ this.moveSupplement(supplement.pos, supplement.node, targetPos);
116
+ clearDropClasses();
117
+ });
118
+ }
119
+ moveSupplement(fromPos, fromNode, targetPos) {
120
+ const { state } = this.view;
121
+ const { tr } = state;
122
+ tr.insert(targetPos, fromNode);
123
+ const mappedFrom = tr.mapping.map(fromPos, -1);
124
+ tr.delete(mappedFrom, mappedFrom + fromNode.nodeSize);
125
+ this.view.dispatch(tr);
126
+ }
127
+ addFileInfo() {
128
+ this.supplementInfoEl = document.createElement('div');
129
+ this.supplementInfoEl.classList.add('supplement-file-info');
130
+ this.supplementInfoEl.contentEditable = 'false';
131
+ const files = this.props.getFiles();
132
+ const file = files.find((f) => f.id === this.node.attrs.href);
133
+ if (file) {
134
+ const iconElement = document.createElement('span');
135
+ iconElement.classList.add('supplement-file-icon');
136
+ const icon = (0, style_guide_1.getFileIcon)(file.name);
137
+ if (icon) {
138
+ iconElement.innerHTML = (0, server_1.renderToStaticMarkup)(icon);
139
+ }
140
+ this.supplementInfoEl.appendChild(iconElement);
141
+ const fileName = document.createElement('span');
142
+ fileName.classList.add('supplement-file-name');
143
+ fileName.textContent = file.name;
144
+ this.supplementInfoEl.appendChild(fileName);
145
+ }
146
+ else {
147
+ const placeholder = document.createElement('span');
148
+ placeholder.textContent = 'File not found';
149
+ this.supplementInfoEl.appendChild(placeholder);
150
+ }
151
+ this.dom.appendChild(this.supplementInfoEl);
152
+ }
153
+ refreshFileInfo() {
154
+ this.supplementInfoEl.remove();
155
+ this.addFileInfo();
156
+ }
157
+ addDragIcon() {
158
+ if (this.dragIcon) {
159
+ this.dragIcon.remove();
160
+ this.dragIcon = undefined;
161
+ }
162
+ const dragIcon = document.createElement('div');
163
+ dragIcon.className = 'drag-icon';
164
+ dragIcon.innerHTML = icons_1.draggableIcon;
165
+ dragIcon.draggable = false;
166
+ dragIcon.addEventListener('mousedown', (e) => {
167
+ e.stopPropagation();
168
+ });
169
+ this.dragIcon = dragIcon;
170
+ this.dom.appendChild(dragIcon);
171
+ }
172
+ }
173
+ exports.SupplementView = SupplementView;
174
+ SupplementView.currentDragSupplementId = null;
175
+ exports.default = (0, creators_1.createNodeView)(SupplementView);