@manuscripts/body-editor 1.7.39-LEAN-3049.0 → 1.7.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -242,23 +242,21 @@ const insertSectionLabel = (state, dispatch, currentTr) => {
242
242
  return true;
243
243
  };
244
244
  exports.insertSectionLabel = insertSectionLabel;
245
- const isLink = (text) => /^\s*(https?:\S+)/.test(text);
246
245
  const insertLink = (state, dispatch) => {
247
- const tr = state.tr;
248
- const selection = state.selection;
249
- if (!selection.empty) {
250
- const text = selectedText();
251
- const attrs = {
252
- href: isLink(text) ? text.trim() : '',
253
- };
254
- const range = new prosemirror_model_1.NodeRange(selection.$from, selection.$to, selection.$from.depth);
255
- const wrapping = (0, prosemirror_transform_1.findWrapping)(range, transform_1.schema.nodes.link, attrs);
256
- if (wrapping) {
257
- tr.wrap(range, wrapping);
258
- }
246
+ const text = selectedText();
247
+ const contents = text ? state.schema.text(text) : undefined;
248
+ const matches = text.match(/^\s*(https?:\S+)/);
249
+ const attrs = {
250
+ href: matches ? matches[1] : '',
251
+ };
252
+ const range = new prosemirror_model_1.NodeRange(state.selection.$from, state.selection.$to, state.selection.$from.depth);
253
+ const { tr } = state;
254
+ const wrapping = (0, prosemirror_transform_1.findWrapping)(range, state.schema.nodes.link, attrs);
255
+ if (wrapping) {
256
+ tr.wrap(range, wrapping);
259
257
  }
260
258
  else {
261
- tr.insert(state.selection.anchor, transform_1.schema.nodes.link.create());
259
+ tr.insert(state.selection.anchor, state.schema.nodes.link.create(attrs, contents));
262
260
  }
263
261
  if (dispatch) {
264
262
  const selection = prosemirror_state_1.NodeSelection.create(tr.doc, state.tr.selection.from);
@@ -112,6 +112,15 @@ const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author,
112
112
  setSelection(author);
113
113
  }
114
114
  };
115
+ const handleClose = () => {
116
+ const values = valuesRef.current;
117
+ if (values && selection && !(0, lodash_1.isEqual)(values, normalize(selection))) {
118
+ setShowConfirmationDialog(true);
119
+ }
120
+ else {
121
+ setOpen(false);
122
+ }
123
+ };
115
124
  const handleSaveAuthor = (values) => {
116
125
  if (!values || !selection) {
117
126
  return;
@@ -202,10 +211,10 @@ const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author,
202
211
  const handleChangeAuthor = (values) => {
203
212
  valuesRef.current = values;
204
213
  };
205
- return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: () => setOpen(false), shouldCloseOnOverlayClick: true },
214
+ return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
206
215
  react_1.default.createElement(style_guide_1.ModalContainer, null,
207
216
  react_1.default.createElement(style_guide_1.ModalHeader, null,
208
- react_1.default.createElement(style_guide_1.CloseButton, { onClick: () => setOpen(false), "data-cy": "modal-close-button" })),
217
+ react_1.default.createElement(style_guide_1.CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
209
218
  react_1.default.createElement(style_guide_1.ModalBody, null,
210
219
  react_1.default.createElement(style_guide_1.ModalSidebar, { "data-cy": "authors-sidebar" },
211
220
  react_1.default.createElement(style_guide_1.ModalSidebarHeader, null,
@@ -46,6 +46,42 @@ const style_guide_1 = require("@manuscripts/style-guide");
46
46
  const react_1 = __importStar(require("react"));
47
47
  const styled_components_1 = __importDefault(require("styled-components"));
48
48
  const url_1 = require("../../lib/url");
49
+ const LinkForm = ({ handleCancel, handleRemove, handleSave, value }) => {
50
+ const [href, setHref] = (0, react_1.useState)(value.href);
51
+ const [text, setText] = (0, react_1.useState)(value.text);
52
+ const [title, setTitle] = (0, react_1.useState)(value.title || '');
53
+ const handleSubmit = (0, react_1.useCallback)((event) => {
54
+ event.preventDefault();
55
+ handleSave({ href, text, title });
56
+ }, [href, text, title, handleSave]);
57
+ return (react_1.default.createElement(Form, { onSubmit: handleSubmit },
58
+ react_1.default.createElement(Field, null,
59
+ react_1.default.createElement(FieldHeading, null,
60
+ react_1.default.createElement(Label, null, "URL"),
61
+ href && (0, url_1.allowedHref)(href) && (react_1.default.createElement(Open, { href: href, target: '_blank', rel: 'noopener' }))),
62
+ react_1.default.createElement(style_guide_1.TextField, { type: 'url', name: 'href', value: href, autoComplete: 'off', autoFocus: true, required: true, onChange: (event) => {
63
+ setHref(event.target.value);
64
+ } })),
65
+ react_1.default.createElement(Field, null,
66
+ react_1.default.createElement(FieldHeading, null,
67
+ react_1.default.createElement(Label, null, "Text")),
68
+ react_1.default.createElement(style_guide_1.TextField, { type: 'text', name: 'text', value: text, autoComplete: 'off', required: true, onChange: (event) => {
69
+ setText(event.target.value);
70
+ } })),
71
+ react_1.default.createElement(Field, null,
72
+ react_1.default.createElement(FieldHeading, null,
73
+ react_1.default.createElement(Label, null, "Title (optional)")),
74
+ react_1.default.createElement(style_guide_1.TextField, { type: 'text', name: 'title', value: title, autoComplete: 'off', required: false, onChange: (event) => {
75
+ setTitle(event.target.value);
76
+ } })),
77
+ react_1.default.createElement(Actions, null,
78
+ react_1.default.createElement(ActionGroup, null,
79
+ react_1.default.createElement(style_guide_1.SecondaryButton, { type: 'button', mini: true, onClick: handleRemove }, "Remove Link")),
80
+ react_1.default.createElement(ActionGroup, null,
81
+ react_1.default.createElement(style_guide_1.SecondaryButton, { type: 'button', onClick: handleCancel }, "Cancel"),
82
+ react_1.default.createElement(style_guide_1.PrimaryButton, { type: 'submit' }, "Save")))));
83
+ };
84
+ exports.LinkForm = LinkForm;
49
85
  const Form = styled_components_1.default.form `
50
86
  padding: 16px;
51
87
  `;
@@ -91,33 +127,3 @@ const Open = styled_components_1.default.a `
91
127
  margin-left: 4px;
92
128
  }
93
129
  `;
94
- const LinkForm = ({ onCancel, onRemove, onSave, value, }) => {
95
- const [href, setHref] = (0, react_1.useState)(value.href);
96
- const [text, setText] = (0, react_1.useState)(value.text);
97
- const [title, setTitle] = (0, react_1.useState)(value.title || '');
98
- const handleSubmit = (0, react_1.useCallback)((event) => {
99
- event.preventDefault();
100
- onSave({ href, text, title });
101
- }, [href, text, title, onSave]);
102
- return (react_1.default.createElement(Form, { onSubmit: handleSubmit },
103
- react_1.default.createElement(Field, null,
104
- react_1.default.createElement(FieldHeading, null,
105
- react_1.default.createElement(Label, null, "URL"),
106
- href && (0, url_1.allowedHref)(href) && (react_1.default.createElement(Open, { href: href, target: '_blank', rel: 'noopener' }))),
107
- react_1.default.createElement(style_guide_1.TextField, { type: 'url', name: 'href', value: href, autoComplete: 'off', autoFocus: true, required: true, onChange: (e) => setHref(e.target.value) })),
108
- react_1.default.createElement(Field, null,
109
- react_1.default.createElement(FieldHeading, null,
110
- react_1.default.createElement(Label, null, "Text")),
111
- react_1.default.createElement(style_guide_1.TextField, { type: 'text', name: 'text', value: text, autoComplete: 'off', required: true, onChange: (e) => setText(e.target.value) })),
112
- react_1.default.createElement(Field, null,
113
- react_1.default.createElement(FieldHeading, null,
114
- react_1.default.createElement(Label, null, "Title (optional)")),
115
- react_1.default.createElement(style_guide_1.TextField, { type: 'text', name: 'title', value: title, autoComplete: 'off', required: false, onChange: (e) => setTitle(e.target.value) })),
116
- react_1.default.createElement(Actions, null,
117
- react_1.default.createElement(ActionGroup, null,
118
- react_1.default.createElement(style_guide_1.SecondaryButton, { type: 'button', mini: true, onClick: onRemove }, "Remove Link")),
119
- react_1.default.createElement(ActionGroup, null,
120
- react_1.default.createElement(style_guide_1.SecondaryButton, { type: 'button', onClick: onCancel }, "Cancel"),
121
- react_1.default.createElement(style_guide_1.PrimaryButton, { type: 'submit' }, "Save")))));
122
- };
123
- exports.LinkForm = LinkForm;
@@ -16,9 +16,44 @@
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.LinkView = void 0;
19
+ const track_changes_utils_1 = require("../lib/track-changes-utils");
20
+ const url_1 = require("../lib/url");
19
21
  const base_node_view_1 = require("./base_node_view");
20
22
  const creators_1 = require("./creators");
21
23
  class LinkView extends base_node_view_1.BaseNodeView {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.initialise = () => {
27
+ this.createDOM();
28
+ this.updateContents();
29
+ };
30
+ this.updateContents = () => {
31
+ var _a, _b, _c;
32
+ const linkText = ((_c = (_b = (_a = this.node) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.firstChild) === null || _c === void 0 ? void 0 : _c.text) || '';
33
+ if (!(0, track_changes_utils_1.isRejectedInsert)(this.node)) {
34
+ const { href, title } = this.node.attrs;
35
+ const linkElement = document.createElement('a');
36
+ linkElement.classList.add('link');
37
+ linkElement.style.position = 'relative';
38
+ if (href && (0, url_1.allowedHref)(href)) {
39
+ linkElement.setAttribute('href', href);
40
+ }
41
+ if (title) {
42
+ linkElement.setAttribute('title', title);
43
+ }
44
+ linkElement.innerHTML = linkText;
45
+ this.dom.innerHTML = '';
46
+ this.dom.appendChild(linkElement);
47
+ }
48
+ else {
49
+ this.dom.innerHTML = linkText;
50
+ }
51
+ };
52
+ this.createDOM = () => {
53
+ this.dom = document.createElement('span');
54
+ this.contentDOM = this.dom;
55
+ };
56
+ }
22
57
  }
23
58
  exports.LinkView = LinkView;
24
59
  exports.default = (0, creators_1.createNodeView)(LinkView);
@@ -19,119 +19,76 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.LinkEditableView = void 0;
22
- const transform_1 = require("@manuscripts/transform");
23
22
  const prosemirror_state_1 = require("prosemirror-state");
24
23
  const LinkForm_1 = require("../components/views/LinkForm");
25
- const track_changes_utils_1 = require("../lib/track-changes-utils");
26
- const url_1 = require("../lib/url");
27
24
  const creators_1 = require("./creators");
28
25
  const link_1 = require("./link");
29
26
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
30
27
  class LinkEditableView extends link_1.LinkView {
31
28
  constructor() {
32
29
  super(...arguments);
33
- this.ignoreMutation = () => true;
34
- this.initialise = () => {
35
- this.createDOM();
36
- this.updateContents();
37
- };
38
- this.updateContents = () => {
39
- if ((0, track_changes_utils_1.isRejectedInsert)(this.node)) {
40
- this.dom.innerHTML = '';
41
- this.contentDOM = undefined;
42
- return;
43
- }
44
- this.contentDOM = this.dom;
45
- const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
46
- const href = attrs.href;
47
- const title = attrs.title;
48
- const classes = ['link', ...(0, track_changes_utils_1.getChangeClasses)(this.node.attrs.dataTracked)];
49
- this.dom.className = classes.join(' ');
50
- this.dom.setAttribute('href', (0, url_1.allowedHref)(href) ? href : '');
51
- this.dom.setAttribute('target', '_blank');
52
- this.dom.setAttribute('title', title || '');
53
- };
54
- this.createDOM = () => {
55
- this.dom = document.createElement('a');
56
- this.dom.addEventListener('click', this.handleClick);
57
- };
58
30
  this.selectNode = () => {
59
- if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
60
- this.showForm();
61
- }
31
+ this.showForm();
62
32
  };
63
33
  this.destroy = () => {
64
34
  this.closeForm();
65
35
  };
66
36
  this.deselectNode = () => {
67
- const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
68
- if (!this.node.content.size || !attrs.href) {
69
- this.removeLink();
70
- }
71
37
  this.closeForm();
72
38
  };
73
- this.showForm = () => {
39
+ this.showForm = (event) => {
40
+ if (event) {
41
+ event.preventDefault();
42
+ }
74
43
  if (!this.props.getCapabilities().editArticle) {
75
44
  return;
76
45
  }
77
- const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
78
- const value = {
79
- href: attrs.href,
80
- title: attrs.title,
46
+ const originalValue = {
47
+ href: this.node.attrs.href,
48
+ title: this.node.attrs.title,
81
49
  text: this.node.textContent,
82
50
  };
83
51
  const componentProps = {
84
- value,
85
- onCancel: this.handleCancel,
86
- onRemove: this.handleRemove,
87
- onSave: this.handleSave,
52
+ value: originalValue,
53
+ handleCancel: this.handleCancel,
54
+ handleRemove: this.handleRemove,
55
+ handleSave: this.handleSave,
88
56
  };
89
57
  this.popperContainer = (0, ReactSubView_1.default)(this.props, LinkForm_1.LinkForm, componentProps, this.node, this.getPos, this.view, 'link-editor');
90
58
  this.props.popper.show(this.dom, this.popperContainer, 'bottom');
91
59
  };
92
- this.handleClick = (e) => {
93
- if (this.props.getCapabilities().editArticle) {
94
- e.preventDefault();
95
- }
96
- };
97
60
  this.handleCancel = () => {
98
- const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
99
- if (!this.node.content.size || !attrs.href) {
100
- this.removeLink();
101
- }
61
+ const tr = this.view.state.tr;
62
+ const pos = this.getPos();
63
+ tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
64
+ this.view.focus();
65
+ this.view.dispatch(tr);
102
66
  this.closeForm();
103
67
  };
104
68
  this.handleRemove = () => {
105
- this.removeLink();
69
+ const tr = this.view.state.tr;
70
+ const pos = this.getPos();
71
+ const to = pos + this.node.nodeSize;
72
+ tr.replaceWith(pos, to, this.node.content).setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
73
+ this.view.focus();
74
+ this.view.dispatch(tr);
106
75
  this.closeForm();
107
76
  };
108
77
  this.handleSave = (value) => {
109
78
  const tr = this.view.state.tr;
110
- const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
79
+ const link = this.node;
111
80
  const pos = this.getPos();
112
- if (value.href !== attrs.href || value.title !== attrs.title) {
81
+ if (value.href !== link.attrs.href || value.title !== link.attrs.title) {
113
82
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, this.node.attrs), { href: value.href, title: value.title }));
114
83
  }
115
- if (value.text !== this.node.textContent) {
116
- tr.delete(pos + 1, pos + this.node.nodeSize - 1);
117
- tr.insert(pos + 1, transform_1.schema.text(value.text));
84
+ if (value.text !== link.textContent) {
85
+ tr.insertText(value.text, pos + 1, pos + this.node.nodeSize - 1);
118
86
  }
119
87
  tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
120
88
  this.view.focus();
121
89
  this.view.dispatch(tr);
122
90
  this.closeForm();
123
91
  };
124
- this.removeLink = () => {
125
- const tr = this.view.state.tr;
126
- const pos = this.getPos();
127
- tr.delete(pos, pos + this.node.nodeSize);
128
- const text = this.node.textContent;
129
- if (text) {
130
- tr.insert(pos, transform_1.schema.text(text));
131
- }
132
- tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
133
- this.view.dispatch(tr);
134
- };
135
92
  this.closeForm = () => {
136
93
  var _a;
137
94
  this.props.popper.destroy();
@@ -227,23 +227,21 @@ export const insertSectionLabel = (state, dispatch, currentTr) => {
227
227
  }
228
228
  return true;
229
229
  };
230
- const isLink = (text) => /^\s*(https?:\S+)/.test(text);
231
230
  export const insertLink = (state, dispatch) => {
232
- const tr = state.tr;
233
- const selection = state.selection;
234
- if (!selection.empty) {
235
- const text = selectedText();
236
- const attrs = {
237
- href: isLink(text) ? text.trim() : '',
238
- };
239
- const range = new NodeRange(selection.$from, selection.$to, selection.$from.depth);
240
- const wrapping = findWrapping(range, schema.nodes.link, attrs);
241
- if (wrapping) {
242
- tr.wrap(range, wrapping);
243
- }
231
+ const text = selectedText();
232
+ const contents = text ? state.schema.text(text) : undefined;
233
+ const matches = text.match(/^\s*(https?:\S+)/);
234
+ const attrs = {
235
+ href: matches ? matches[1] : '',
236
+ };
237
+ const range = new NodeRange(state.selection.$from, state.selection.$to, state.selection.$from.depth);
238
+ const { tr } = state;
239
+ const wrapping = findWrapping(range, state.schema.nodes.link, attrs);
240
+ if (wrapping) {
241
+ tr.wrap(range, wrapping);
244
242
  }
245
243
  else {
246
- tr.insert(state.selection.anchor, schema.nodes.link.create());
244
+ tr.insert(state.selection.anchor, state.schema.nodes.link.create(attrs, contents));
247
245
  }
248
246
  if (dispatch) {
249
247
  const selection = NodeSelection.create(tr.doc, state.tr.selection.from);
@@ -83,6 +83,15 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
83
83
  setSelection(author);
84
84
  }
85
85
  };
86
+ const handleClose = () => {
87
+ const values = valuesRef.current;
88
+ if (values && selection && !isEqual(values, normalize(selection))) {
89
+ setShowConfirmationDialog(true);
90
+ }
91
+ else {
92
+ setOpen(false);
93
+ }
94
+ };
86
95
  const handleSaveAuthor = (values) => {
87
96
  if (!values || !selection) {
88
97
  return;
@@ -173,10 +182,10 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
173
182
  const handleChangeAuthor = (values) => {
174
183
  valuesRef.current = values;
175
184
  };
176
- return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => setOpen(false), shouldCloseOnOverlayClick: true },
185
+ return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
177
186
  React.createElement(ModalContainer, null,
178
187
  React.createElement(ModalHeader, null,
179
- React.createElement(CloseButton, { onClick: () => setOpen(false), "data-cy": "modal-close-button" })),
188
+ React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
180
189
  React.createElement(ModalBody, null,
181
190
  React.createElement(ModalSidebar, { "data-cy": "authors-sidebar" },
182
191
  React.createElement(ModalSidebarHeader, null,
@@ -17,6 +17,41 @@ import { PrimaryButton, SecondaryButton, TextField, } from '@manuscripts/style-g
17
17
  import React, { useCallback, useState } from 'react';
18
18
  import styled from 'styled-components';
19
19
  import { allowedHref } from '../../lib/url';
20
+ export const LinkForm = ({ handleCancel, handleRemove, handleSave, value }) => {
21
+ const [href, setHref] = useState(value.href);
22
+ const [text, setText] = useState(value.text);
23
+ const [title, setTitle] = useState(value.title || '');
24
+ const handleSubmit = useCallback((event) => {
25
+ event.preventDefault();
26
+ handleSave({ href, text, title });
27
+ }, [href, text, title, handleSave]);
28
+ return (React.createElement(Form, { onSubmit: handleSubmit },
29
+ React.createElement(Field, null,
30
+ React.createElement(FieldHeading, null,
31
+ React.createElement(Label, null, "URL"),
32
+ href && allowedHref(href) && (React.createElement(Open, { href: href, target: '_blank', rel: 'noopener' }))),
33
+ React.createElement(TextField, { type: 'url', name: 'href', value: href, autoComplete: 'off', autoFocus: true, required: true, onChange: (event) => {
34
+ setHref(event.target.value);
35
+ } })),
36
+ React.createElement(Field, null,
37
+ React.createElement(FieldHeading, null,
38
+ React.createElement(Label, null, "Text")),
39
+ React.createElement(TextField, { type: 'text', name: 'text', value: text, autoComplete: 'off', required: true, onChange: (event) => {
40
+ setText(event.target.value);
41
+ } })),
42
+ React.createElement(Field, null,
43
+ React.createElement(FieldHeading, null,
44
+ React.createElement(Label, null, "Title (optional)")),
45
+ React.createElement(TextField, { type: 'text', name: 'title', value: title, autoComplete: 'off', required: false, onChange: (event) => {
46
+ setTitle(event.target.value);
47
+ } })),
48
+ React.createElement(Actions, null,
49
+ React.createElement(ActionGroup, null,
50
+ React.createElement(SecondaryButton, { type: 'button', mini: true, onClick: handleRemove }, "Remove Link")),
51
+ React.createElement(ActionGroup, null,
52
+ React.createElement(SecondaryButton, { type: 'button', onClick: handleCancel }, "Cancel"),
53
+ React.createElement(PrimaryButton, { type: 'submit' }, "Save")))));
54
+ };
20
55
  const Form = styled.form `
21
56
  padding: 16px;
22
57
  `;
@@ -62,32 +97,3 @@ const Open = styled.a `
62
97
  margin-left: 4px;
63
98
  }
64
99
  `;
65
- export const LinkForm = ({ onCancel, onRemove, onSave, value, }) => {
66
- const [href, setHref] = useState(value.href);
67
- const [text, setText] = useState(value.text);
68
- const [title, setTitle] = useState(value.title || '');
69
- const handleSubmit = useCallback((event) => {
70
- event.preventDefault();
71
- onSave({ href, text, title });
72
- }, [href, text, title, onSave]);
73
- return (React.createElement(Form, { onSubmit: handleSubmit },
74
- React.createElement(Field, null,
75
- React.createElement(FieldHeading, null,
76
- React.createElement(Label, null, "URL"),
77
- href && allowedHref(href) && (React.createElement(Open, { href: href, target: '_blank', rel: 'noopener' }))),
78
- React.createElement(TextField, { type: 'url', name: 'href', value: href, autoComplete: 'off', autoFocus: true, required: true, onChange: (e) => setHref(e.target.value) })),
79
- React.createElement(Field, null,
80
- React.createElement(FieldHeading, null,
81
- React.createElement(Label, null, "Text")),
82
- React.createElement(TextField, { type: 'text', name: 'text', value: text, autoComplete: 'off', required: true, onChange: (e) => setText(e.target.value) })),
83
- React.createElement(Field, null,
84
- React.createElement(FieldHeading, null,
85
- React.createElement(Label, null, "Title (optional)")),
86
- React.createElement(TextField, { type: 'text', name: 'title', value: title, autoComplete: 'off', required: false, onChange: (e) => setTitle(e.target.value) })),
87
- React.createElement(Actions, null,
88
- React.createElement(ActionGroup, null,
89
- React.createElement(SecondaryButton, { type: 'button', mini: true, onClick: onRemove }, "Remove Link")),
90
- React.createElement(ActionGroup, null,
91
- React.createElement(SecondaryButton, { type: 'button', onClick: onCancel }, "Cancel"),
92
- React.createElement(PrimaryButton, { type: 'submit' }, "Save")))));
93
- };
@@ -13,8 +13,43 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
+ import { isRejectedInsert } from '../lib/track-changes-utils';
17
+ import { allowedHref } from '../lib/url';
16
18
  import { BaseNodeView } from './base_node_view';
17
19
  import { createNodeView } from './creators';
18
20
  export class LinkView extends BaseNodeView {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.initialise = () => {
24
+ this.createDOM();
25
+ this.updateContents();
26
+ };
27
+ this.updateContents = () => {
28
+ var _a, _b, _c;
29
+ const linkText = ((_c = (_b = (_a = this.node) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.firstChild) === null || _c === void 0 ? void 0 : _c.text) || '';
30
+ if (!isRejectedInsert(this.node)) {
31
+ const { href, title } = this.node.attrs;
32
+ const linkElement = document.createElement('a');
33
+ linkElement.classList.add('link');
34
+ linkElement.style.position = 'relative';
35
+ if (href && allowedHref(href)) {
36
+ linkElement.setAttribute('href', href);
37
+ }
38
+ if (title) {
39
+ linkElement.setAttribute('title', title);
40
+ }
41
+ linkElement.innerHTML = linkText;
42
+ this.dom.innerHTML = '';
43
+ this.dom.appendChild(linkElement);
44
+ }
45
+ else {
46
+ this.dom.innerHTML = linkText;
47
+ }
48
+ };
49
+ this.createDOM = () => {
50
+ this.dom = document.createElement('span');
51
+ this.contentDOM = this.dom;
52
+ };
53
+ }
19
54
  }
20
55
  export default createNodeView(LinkView);
@@ -13,119 +13,76 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { schema } from '@manuscripts/transform';
17
16
  import { TextSelection } from 'prosemirror-state';
18
- import { LinkForm, } from '../components/views/LinkForm';
19
- import { getActualAttrs, getChangeClasses, isDeleted, isRejectedInsert, } from '../lib/track-changes-utils';
20
- import { allowedHref } from '../lib/url';
17
+ import { LinkForm } from '../components/views/LinkForm';
21
18
  import { createEditableNodeView } from './creators';
22
19
  import { LinkView } from './link';
23
20
  import ReactSubView from './ReactSubView';
24
21
  export class LinkEditableView extends LinkView {
25
22
  constructor() {
26
23
  super(...arguments);
27
- this.ignoreMutation = () => true;
28
- this.initialise = () => {
29
- this.createDOM();
30
- this.updateContents();
31
- };
32
- this.updateContents = () => {
33
- if (isRejectedInsert(this.node)) {
34
- this.dom.innerHTML = '';
35
- this.contentDOM = undefined;
36
- return;
37
- }
38
- this.contentDOM = this.dom;
39
- const attrs = getActualAttrs(this.node);
40
- const href = attrs.href;
41
- const title = attrs.title;
42
- const classes = ['link', ...getChangeClasses(this.node.attrs.dataTracked)];
43
- this.dom.className = classes.join(' ');
44
- this.dom.setAttribute('href', allowedHref(href) ? href : '');
45
- this.dom.setAttribute('target', '_blank');
46
- this.dom.setAttribute('title', title || '');
47
- };
48
- this.createDOM = () => {
49
- this.dom = document.createElement('a');
50
- this.dom.addEventListener('click', this.handleClick);
51
- };
52
24
  this.selectNode = () => {
53
- if (!isDeleted(this.node)) {
54
- this.showForm();
55
- }
25
+ this.showForm();
56
26
  };
57
27
  this.destroy = () => {
58
28
  this.closeForm();
59
29
  };
60
30
  this.deselectNode = () => {
61
- const attrs = getActualAttrs(this.node);
62
- if (!this.node.content.size || !attrs.href) {
63
- this.removeLink();
64
- }
65
31
  this.closeForm();
66
32
  };
67
- this.showForm = () => {
33
+ this.showForm = (event) => {
34
+ if (event) {
35
+ event.preventDefault();
36
+ }
68
37
  if (!this.props.getCapabilities().editArticle) {
69
38
  return;
70
39
  }
71
- const attrs = getActualAttrs(this.node);
72
- const value = {
73
- href: attrs.href,
74
- title: attrs.title,
40
+ const originalValue = {
41
+ href: this.node.attrs.href,
42
+ title: this.node.attrs.title,
75
43
  text: this.node.textContent,
76
44
  };
77
45
  const componentProps = {
78
- value,
79
- onCancel: this.handleCancel,
80
- onRemove: this.handleRemove,
81
- onSave: this.handleSave,
46
+ value: originalValue,
47
+ handleCancel: this.handleCancel,
48
+ handleRemove: this.handleRemove,
49
+ handleSave: this.handleSave,
82
50
  };
83
51
  this.popperContainer = ReactSubView(this.props, LinkForm, componentProps, this.node, this.getPos, this.view, 'link-editor');
84
52
  this.props.popper.show(this.dom, this.popperContainer, 'bottom');
85
53
  };
86
- this.handleClick = (e) => {
87
- if (this.props.getCapabilities().editArticle) {
88
- e.preventDefault();
89
- }
90
- };
91
54
  this.handleCancel = () => {
92
- const attrs = getActualAttrs(this.node);
93
- if (!this.node.content.size || !attrs.href) {
94
- this.removeLink();
95
- }
55
+ const tr = this.view.state.tr;
56
+ const pos = this.getPos();
57
+ tr.setSelection(TextSelection.create(tr.doc, pos));
58
+ this.view.focus();
59
+ this.view.dispatch(tr);
96
60
  this.closeForm();
97
61
  };
98
62
  this.handleRemove = () => {
99
- this.removeLink();
63
+ const tr = this.view.state.tr;
64
+ const pos = this.getPos();
65
+ const to = pos + this.node.nodeSize;
66
+ tr.replaceWith(pos, to, this.node.content).setSelection(TextSelection.create(tr.doc, pos));
67
+ this.view.focus();
68
+ this.view.dispatch(tr);
100
69
  this.closeForm();
101
70
  };
102
71
  this.handleSave = (value) => {
103
72
  const tr = this.view.state.tr;
104
- const attrs = getActualAttrs(this.node);
73
+ const link = this.node;
105
74
  const pos = this.getPos();
106
- if (value.href !== attrs.href || value.title !== attrs.title) {
75
+ if (value.href !== link.attrs.href || value.title !== link.attrs.title) {
107
76
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, this.node.attrs), { href: value.href, title: value.title }));
108
77
  }
109
- if (value.text !== this.node.textContent) {
110
- tr.delete(pos + 1, pos + this.node.nodeSize - 1);
111
- tr.insert(pos + 1, schema.text(value.text));
78
+ if (value.text !== link.textContent) {
79
+ tr.insertText(value.text, pos + 1, pos + this.node.nodeSize - 1);
112
80
  }
113
81
  tr.setSelection(TextSelection.create(tr.doc, pos));
114
82
  this.view.focus();
115
83
  this.view.dispatch(tr);
116
84
  this.closeForm();
117
85
  };
118
- this.removeLink = () => {
119
- const tr = this.view.state.tr;
120
- const pos = this.getPos();
121
- tr.delete(pos, pos + this.node.nodeSize);
122
- const text = this.node.textContent;
123
- if (text) {
124
- tr.insert(pos, schema.text(text));
125
- }
126
- tr.setSelection(TextSelection.create(tr.doc, pos));
127
- this.view.dispatch(tr);
128
- };
129
86
  this.closeForm = () => {
130
87
  var _a;
131
88
  this.props.popper.destroy();
@@ -19,10 +19,9 @@ export interface LinkValue {
19
19
  href: string;
20
20
  title?: string;
21
21
  }
22
- export interface LinkFormProps {
23
- onCancel: () => void;
24
- onRemove: () => void;
25
- onSave: (value: LinkValue) => void;
22
+ export declare const LinkForm: React.FC<{
23
+ handleCancel: () => void;
24
+ handleRemove: () => void;
25
+ handleSave: (value: LinkValue) => void;
26
26
  value: LinkValue;
27
- }
28
- export declare const LinkForm: React.FC<LinkFormProps>;
27
+ }>;
@@ -16,6 +16,9 @@
16
16
  import { ManuscriptNodeView } from '@manuscripts/transform';
17
17
  import { BaseNodeProps, BaseNodeView } from './base_node_view';
18
18
  export declare class LinkView<PropsType extends BaseNodeProps> extends BaseNodeView<PropsType> implements ManuscriptNodeView {
19
+ initialise: () => void;
20
+ updateContents: () => void;
21
+ protected createDOM: () => void;
19
22
  }
20
23
  declare const _default: (props: BaseNodeProps, dispatch?: import("..").Dispatch | undefined) => import("../types").NodeViewCreator<LinkView<any>>;
21
24
  export default _default;
@@ -17,19 +17,13 @@ import { EditableBlockProps } from './editable_block';
17
17
  import { LinkView } from './link';
18
18
  export declare class LinkEditableView extends LinkView<EditableBlockProps> {
19
19
  protected popperContainer: HTMLDivElement;
20
- ignoreMutation: () => boolean;
21
- initialise: () => void;
22
- updateContents: () => void;
23
- protected createDOM: () => void;
24
20
  selectNode: () => void;
25
21
  destroy: () => void;
26
22
  deselectNode: () => void;
27
23
  private showForm;
28
- private handleClick;
29
24
  private handleCancel;
30
25
  private handleRemove;
31
26
  private handleSave;
32
- private removeLink;
33
27
  private closeForm;
34
28
  }
35
29
  declare const _default: (props: EditableBlockProps, dispatch?: import("..").Dispatch | undefined) => import("../types").NodeViewCreator<LinkEditableView>;
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.7.39-LEAN-3049.0",
4
+ "version": "1.7.39",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -31,9 +31,9 @@
31
31
  "@manuscripts/assets": "^0.6.4",
32
32
  "@manuscripts/json-schema": "^2.2.7",
33
33
  "@manuscripts/library": "^1.3.6",
34
- "@manuscripts/style-guide": "1.8.8-LEAN-3049.5",
34
+ "@manuscripts/style-guide": "1.8.7",
35
35
  "@manuscripts/track-changes-plugin": "1.7.9",
36
- "@manuscripts/transform": "2.1.14-LEAN-3049.0",
36
+ "@manuscripts/transform": "2.1.13",
37
37
  "astrocite-eutils": "^0.16.4",
38
38
  "axios": "^1.6.7",
39
39
  "mathjax-full": "^3.2.2",