@manuscripts/body-editor 1.7.37 → 1.7.39-LEAN-3049.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.alertIcon = exports.editAttrsTrackingIcon = exports.commentIcon = exports.editIcon = void 0;
18
+ exports.deleteIcon = exports.alertIcon = exports.editAttrsTrackingIcon = exports.commentIcon = exports.editIcon = void 0;
19
19
  exports.editIcon = `
20
20
  <svg
21
21
  width="14"
@@ -118,3 +118,49 @@ exports.alertIcon = `
118
118
  />
119
119
  </svg>
120
120
  `;
121
+ exports.deleteIcon = `
122
+ <svg
123
+ width="13"
124
+ height="15"
125
+ viewBox="0 0 13 15"
126
+ fill="none"
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ >
129
+ <path
130
+ fill-rule="evenodd"
131
+ clip-rule="evenodd"
132
+ d="M2.00001 3C2 3.00135 2 3.00269 2 3.00404V13.004C2 13.5563 2.44772 14.004 3 14.004H10C10.5523 14.004 11 13.5563 11 13.004V3.00404C11 3.00269 11 3.00135 11 3C11.5978 3.34581 12 3.99215 12 4.73244V13.004C12 14.1086 11.1046 15.004 10 15.004H3C1.89543 15.004 1 14.1086 1 13.004V4.73244C1 3.99215 1.4022 3.34581 2.00001 3Z"
133
+ fill="#C9C9C9"
134
+ />
135
+ <path
136
+ fill-rule="evenodd"
137
+ clip-rule="evenodd"
138
+ d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3.5C3 4.32843 3.67157 5 4.5 5H8.5C9.32843 5 10 4.32843 10 3.5V1.5C10 0.671573 9.32843 0 8.5 0H4.5ZM9 1.5C9 1.22386 8.77614 1 8.5 1H4.5C4.22386 1 4 1.22386 4 1.5C4 1.77614 4.22386 2 4.5 2H8.5C8.77614 2 9 1.77614 9 1.5Z"
139
+ fill="#C9C9C9"
140
+ />
141
+ <rect
142
+ y="2"
143
+ width="13"
144
+ height="3"
145
+ rx="1.5"
146
+ fill="#C9C9C9"
147
+ />
148
+ <path
149
+ fill-rule="evenodd"
150
+ clip-rule="evenodd"
151
+ d="M8 7.5C8 7.22386 8.22386 7 8.5 7C8.77614 7 9 7.22386 9 7.5V11.5C9 11.7761 8.77614 12 8.5 12C8.22386 12 8 11.7761 8 11.5V7.5Z"
152
+ fill="#C9C9C9"
153
+ />
154
+ <path
155
+ fill-rule="evenodd"
156
+ clip-rule="evenodd"
157
+ d="M4 7.5C4 7.22386 4.22386 7 4.5 7C4.77614 7 5 7.22386 5 7.5V11.5C5 11.7761 4.77614 12 4.5 12C4.22386 12 4 11.7761 4 11.5V7.5Z"
158
+ fill="#C9C9C9"
159
+ />
160
+ <path
161
+ fill-rule="evenodd"
162
+ clip-rule="evenodd"
163
+ d="M11.5 3C11.7761 3 12 3.22386 12 3.5C12 3.77614 11.7761 4 11.5 4L1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3L11.5 3Z"
164
+ fill="white"
165
+ />
166
+ </svg>`;
@@ -242,21 +242,23 @@ 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);
245
246
  const insertLink = (state, dispatch) => {
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);
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
+ }
257
259
  }
258
260
  else {
259
- tr.insert(state.selection.anchor, state.schema.nodes.link.create(attrs, contents));
261
+ tr.insert(state.selection.anchor, transform_1.schema.nodes.link.create());
260
262
  }
261
263
  if (dispatch) {
262
264
  const selection = prosemirror_state_1.NodeSelection.create(tr.doc, state.tr.selection.from);
@@ -0,0 +1,45 @@
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.DeleteFootnoteDialog = void 0;
27
+ const style_guide_1 = require("@manuscripts/style-guide");
28
+ const react_1 = __importStar(require("react"));
29
+ const DeleteFootnoteDialog = ({ footnoteType, footnoteMessage, handleDelete, }) => {
30
+ const [isOpen, setOpen] = (0, react_1.useState)(true);
31
+ return (react_1.default.createElement(style_guide_1.Dialog, { className: "delete-footnote-dialog", isOpen: isOpen, actions: {
32
+ primary: {
33
+ action: () => {
34
+ setOpen(false);
35
+ handleDelete();
36
+ },
37
+ title: 'Delete',
38
+ },
39
+ secondary: {
40
+ action: () => setOpen(false),
41
+ title: 'Cancel',
42
+ },
43
+ }, category: style_guide_1.Category.confirmation, header: `Delete ${footnoteType}`, message: `${footnoteMessage}` }));
44
+ };
45
+ exports.DeleteFootnoteDialog = DeleteFootnoteDialog;
@@ -46,42 +46,6 @@ 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;
85
49
  const Form = styled_components_1.default.form `
86
50
  padding: 16px;
87
51
  `;
@@ -127,3 +91,33 @@ const Open = styled_components_1.default.a `
127
91
  margin-left: 4px;
128
92
  }
129
93
  `;
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;
@@ -69,7 +69,7 @@ exports.default = (props) => {
69
69
  (0, prosemirror_tables_1.tableEditing)(),
70
70
  (0, highlight_1.default)(props),
71
71
  (0, selected_suggestion_ui_1.default)(props),
72
- (0, footnotes_1.default)(),
72
+ (0, footnotes_1.default)(props),
73
73
  (0, table_footnote_1.default)(),
74
74
  ];
75
75
  if (props.collabProvider) {
@@ -142,7 +142,7 @@ class ContextMenu {
142
142
  this.addPopperEventListeners();
143
143
  };
144
144
  this.showEditMenu = (target) => {
145
- var _a;
145
+ var _a, _b;
146
146
  const menu = document.createElement('div');
147
147
  menu.className = 'menu';
148
148
  const $pos = this.resolvePos();
@@ -176,9 +176,17 @@ class ContextMenu {
176
176
  if (type === transform_1.schema.nodes.table_element) {
177
177
  const isInTable = (0, prosemirror_utils_1.hasParentNodeOfType)(transform_1.schema.nodes.table)(this.view.state.selection);
178
178
  const tableElementFooter = (0, prosemirror_utils_1.findChildrenByType)(this.node, transform_1.schema.nodes.table_element_footer);
179
+ let isDeletedOrRejected = false;
179
180
  const hasGeneralNote = tableElementFooter.length &&
180
181
  ((_a = tableElementFooter[0].node.firstChild) === null || _a === void 0 ? void 0 : _a.type) === transform_1.schema.nodes.paragraph;
181
- if (!hasGeneralNote) {
182
+ if (hasGeneralNote) {
183
+ const generalFootnote = (_b = tableElementFooter[0]) === null || _b === void 0 ? void 0 : _b.node.firstChild;
184
+ if (generalFootnote) {
185
+ isDeletedOrRejected =
186
+ (0, track_changes_utils_1.isDeleted)(generalFootnote) || (0, track_changes_utils_1.isRejectedInsert)(generalFootnote);
187
+ }
188
+ }
189
+ if (!hasGeneralNote || isDeletedOrRejected) {
182
190
  menu.appendChild(this.createMenuSection((section) => {
183
191
  section.appendChild(this.createMenuItem('Add General Note', () => {
184
192
  (0, commands_1.insertGeneralFootnote)(this.node, this.getPos(), this.view, tableElementFooter);
@@ -14,6 +14,9 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
17
20
  Object.defineProperty(exports, "__esModule", { value: true });
18
21
  exports.uncitedFootnoteWidget = exports.buildPluginState = exports.footnotesKey = void 0;
19
22
  const transform_1 = require("@manuscripts/transform");
@@ -22,7 +25,9 @@ const prosemirror_state_1 = require("prosemirror-state");
22
25
  const prosemirror_utils_1 = require("prosemirror-utils");
23
26
  const prosemirror_view_1 = require("prosemirror-view");
24
27
  const assets_1 = require("../../assets");
28
+ const DeleteFootnoteDialog_1 = require("../../components/views/DeleteFootnoteDialog");
25
29
  const utils_1 = require("../../lib/utils");
30
+ const ReactSubView_1 = __importDefault(require("../../views/ReactSubView"));
26
31
  const placeholder_1 = require("../placeholder");
27
32
  const footnotes_utils_1 = require("./footnotes-utils");
28
33
  exports.footnotesKey = new prosemirror_state_1.PluginKey('footnotes');
@@ -68,7 +73,39 @@ const uncitedFootnoteWidget = () => () => {
68
73
  return element;
69
74
  };
70
75
  exports.uncitedFootnoteWidget = uncitedFootnoteWidget;
71
- exports.default = () => {
76
+ const deleteFootnoteWidget = (node, props, footnoteType, footnoteMessage) => (view, getPos) => {
77
+ const deleteBtn = document.createElement('span');
78
+ deleteBtn.className = 'delete-icon';
79
+ deleteBtn.innerHTML = assets_1.deleteIcon;
80
+ deleteBtn.addEventListener('click', () => {
81
+ const handleDelete = () => {
82
+ const tr = view.state.tr;
83
+ const pos = getPos();
84
+ if (node.type === transform_1.schema.nodes.table_element_footer) {
85
+ if (!(0, utils_1.getChildOfType)(node, transform_1.schema.nodes.footnotes_element, true) &&
86
+ pos) {
87
+ tr.delete(pos - 1, pos + node.nodeSize);
88
+ }
89
+ else {
90
+ node.content.forEach((item) => {
91
+ if (item.type === transform_1.schema.nodes.paragraph && pos) {
92
+ tr.delete(pos - 1, pos + item.nodeSize + 1);
93
+ }
94
+ });
95
+ }
96
+ }
97
+ view.dispatch(tr);
98
+ };
99
+ const componentProps = {
100
+ footnoteType: footnoteType,
101
+ footnoteMessage: footnoteMessage,
102
+ handleDelete: handleDelete,
103
+ };
104
+ (0, ReactSubView_1.default)(Object.assign(Object.assign({}, props), { dispatch: view.dispatch }), DeleteFootnoteDialog_1.DeleteFootnoteDialog, componentProps, node, () => getPos(), view);
105
+ });
106
+ return deleteBtn;
107
+ };
108
+ exports.default = (props) => {
72
109
  return new prosemirror_state_1.Plugin({
73
110
  key: exports.footnotesKey,
74
111
  state: {
@@ -101,6 +138,7 @@ exports.default = () => {
101
138
  decorations: (state) => {
102
139
  const decorations = [];
103
140
  const isInTableElementFooter = (0, prosemirror_utils_1.hasParentNodeOfType)(transform_1.schema.nodes.table_element_footer)(state.selection);
141
+ const isInTableElement = (0, prosemirror_utils_1.hasParentNodeOfType)(transform_1.schema.nodes.table_element)(state.selection);
104
142
  if (isInTableElementFooter) {
105
143
  const parent = (0, utils_1.findParentNodeWithIdValue)(state.selection);
106
144
  if (parent) {
@@ -111,6 +149,7 @@ exports.default = () => {
111
149
  }
112
150
  const { labels } = exports.footnotesKey.getState(state);
113
151
  let tableInlineFootnoteIds = undefined;
152
+ const can = props.getCapabilities();
114
153
  state.doc.descendants((node, pos, parent) => {
115
154
  var _a;
116
155
  if ((0, transform_1.isFootnoteNode)(node)) {
@@ -131,6 +170,30 @@ exports.default = () => {
131
170
  decorations.push(prosemirror_view_1.Decoration.widget(pos + node.nodeSize - 1, (0, exports.uncitedFootnoteWidget)()));
132
171
  }
133
172
  }
173
+ if (can.editArticle) {
174
+ if (isInTableElement) {
175
+ const footnote = (() => {
176
+ switch (node.type) {
177
+ case transform_1.schema.nodes.footnote:
178
+ return {
179
+ type: 'table footnote',
180
+ message: 'This action will entirely remove the table footnote from the list because it will no longer be used.',
181
+ };
182
+ default:
183
+ return {
184
+ type: 'table general note',
185
+ message: 'This action will entirely remove the table general note.',
186
+ };
187
+ }
188
+ })();
189
+ if (node.type === transform_1.schema.nodes.paragraph &&
190
+ (parent === null || parent === void 0 ? void 0 : parent.type) === transform_1.schema.nodes.table_element_footer) {
191
+ decorations.push(prosemirror_view_1.Decoration.widget(pos + 1, deleteFootnoteWidget(parent, props, footnote.type, footnote.message), {
192
+ key: parent.attrs.id,
193
+ }));
194
+ }
195
+ }
196
+ }
134
197
  if (node.type === transform_1.schema.nodes.footnotes_element) {
135
198
  if ((parent === null || parent === void 0 ? void 0 : parent.type) === transform_1.schema.nodes.table_element_footer) {
136
199
  decorations.push(prosemirror_view_1.Decoration.node(pos, pos + node.nodeSize, {
@@ -16,44 +16,9 @@
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");
21
19
  const base_node_view_1 = require("./base_node_view");
22
20
  const creators_1 = require("./creators");
23
21
  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
- }
57
22
  }
58
23
  exports.LinkView = LinkView;
59
24
  exports.default = (0, creators_1.createNodeView)(LinkView);
@@ -19,76 +19,119 @@ 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");
22
23
  const prosemirror_state_1 = require("prosemirror-state");
23
24
  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");
24
27
  const creators_1 = require("./creators");
25
28
  const link_1 = require("./link");
26
29
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
27
30
  class LinkEditableView extends link_1.LinkView {
28
31
  constructor() {
29
32
  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
+ };
30
58
  this.selectNode = () => {
31
- this.showForm();
59
+ if (!(0, track_changes_utils_1.isDeleted)(this.node)) {
60
+ this.showForm();
61
+ }
32
62
  };
33
63
  this.destroy = () => {
34
64
  this.closeForm();
35
65
  };
36
66
  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
+ }
37
71
  this.closeForm();
38
72
  };
39
- this.showForm = (event) => {
40
- if (event) {
41
- event.preventDefault();
42
- }
73
+ this.showForm = () => {
43
74
  if (!this.props.getCapabilities().editArticle) {
44
75
  return;
45
76
  }
46
- const originalValue = {
47
- href: this.node.attrs.href,
48
- title: this.node.attrs.title,
77
+ const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
78
+ const value = {
79
+ href: attrs.href,
80
+ title: attrs.title,
49
81
  text: this.node.textContent,
50
82
  };
51
83
  const componentProps = {
52
- value: originalValue,
53
- handleCancel: this.handleCancel,
54
- handleRemove: this.handleRemove,
55
- handleSave: this.handleSave,
84
+ value,
85
+ onCancel: this.handleCancel,
86
+ onRemove: this.handleRemove,
87
+ onSave: this.handleSave,
56
88
  };
57
89
  this.popperContainer = (0, ReactSubView_1.default)(this.props, LinkForm_1.LinkForm, componentProps, this.node, this.getPos, this.view, 'link-editor');
58
90
  this.props.popper.show(this.dom, this.popperContainer, 'bottom');
59
91
  };
92
+ this.handleClick = (e) => {
93
+ if (this.props.getCapabilities().editArticle) {
94
+ e.preventDefault();
95
+ }
96
+ };
60
97
  this.handleCancel = () => {
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);
98
+ const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
99
+ if (!this.node.content.size || !attrs.href) {
100
+ this.removeLink();
101
+ }
66
102
  this.closeForm();
67
103
  };
68
104
  this.handleRemove = () => {
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);
105
+ this.removeLink();
75
106
  this.closeForm();
76
107
  };
77
108
  this.handleSave = (value) => {
78
109
  const tr = this.view.state.tr;
79
- const link = this.node;
110
+ const attrs = (0, track_changes_utils_1.getActualAttrs)(this.node);
80
111
  const pos = this.getPos();
81
- if (value.href !== link.attrs.href || value.title !== link.attrs.title) {
112
+ if (value.href !== attrs.href || value.title !== attrs.title) {
82
113
  tr.setNodeMarkup(pos, undefined, Object.assign(Object.assign({}, this.node.attrs), { href: value.href, title: value.title }));
83
114
  }
84
- if (value.text !== link.textContent) {
85
- tr.insertText(value.text, pos + 1, pos + this.node.nodeSize - 1);
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));
86
118
  }
87
119
  tr.setSelection(prosemirror_state_1.TextSelection.create(tr.doc, pos));
88
120
  this.view.focus();
89
121
  this.view.dispatch(tr);
90
122
  this.closeForm();
91
123
  };
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
+ };
92
135
  this.closeForm = () => {
93
136
  var _a;
94
137
  this.props.popper.destroy();
package/dist/es/assets.js CHANGED
@@ -115,3 +115,49 @@ export const alertIcon = `
115
115
  />
116
116
  </svg>
117
117
  `;
118
+ export const deleteIcon = `
119
+ <svg
120
+ width="13"
121
+ height="15"
122
+ viewBox="0 0 13 15"
123
+ fill="none"
124
+ xmlns="http://www.w3.org/2000/svg"
125
+ >
126
+ <path
127
+ fill-rule="evenodd"
128
+ clip-rule="evenodd"
129
+ d="M2.00001 3C2 3.00135 2 3.00269 2 3.00404V13.004C2 13.5563 2.44772 14.004 3 14.004H10C10.5523 14.004 11 13.5563 11 13.004V3.00404C11 3.00269 11 3.00135 11 3C11.5978 3.34581 12 3.99215 12 4.73244V13.004C12 14.1086 11.1046 15.004 10 15.004H3C1.89543 15.004 1 14.1086 1 13.004V4.73244C1 3.99215 1.4022 3.34581 2.00001 3Z"
130
+ fill="#C9C9C9"
131
+ />
132
+ <path
133
+ fill-rule="evenodd"
134
+ clip-rule="evenodd"
135
+ d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3.5C3 4.32843 3.67157 5 4.5 5H8.5C9.32843 5 10 4.32843 10 3.5V1.5C10 0.671573 9.32843 0 8.5 0H4.5ZM9 1.5C9 1.22386 8.77614 1 8.5 1H4.5C4.22386 1 4 1.22386 4 1.5C4 1.77614 4.22386 2 4.5 2H8.5C8.77614 2 9 1.77614 9 1.5Z"
136
+ fill="#C9C9C9"
137
+ />
138
+ <rect
139
+ y="2"
140
+ width="13"
141
+ height="3"
142
+ rx="1.5"
143
+ fill="#C9C9C9"
144
+ />
145
+ <path
146
+ fill-rule="evenodd"
147
+ clip-rule="evenodd"
148
+ d="M8 7.5C8 7.22386 8.22386 7 8.5 7C8.77614 7 9 7.22386 9 7.5V11.5C9 11.7761 8.77614 12 8.5 12C8.22386 12 8 11.7761 8 11.5V7.5Z"
149
+ fill="#C9C9C9"
150
+ />
151
+ <path
152
+ fill-rule="evenodd"
153
+ clip-rule="evenodd"
154
+ d="M4 7.5C4 7.22386 4.22386 7 4.5 7C4.77614 7 5 7.22386 5 7.5V11.5C5 11.7761 4.77614 12 4.5 12C4.22386 12 4 11.7761 4 11.5V7.5Z"
155
+ fill="#C9C9C9"
156
+ />
157
+ <path
158
+ fill-rule="evenodd"
159
+ clip-rule="evenodd"
160
+ d="M11.5 3C11.7761 3 12 3.22386 12 3.5C12 3.77614 11.7761 4 11.5 4L1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3L11.5 3Z"
161
+ fill="white"
162
+ />
163
+ </svg>`;
@@ -227,21 +227,23 @@ export const insertSectionLabel = (state, dispatch, currentTr) => {
227
227
  }
228
228
  return true;
229
229
  };
230
+ const isLink = (text) => /^\s*(https?:\S+)/.test(text);
230
231
  export const insertLink = (state, dispatch) => {
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);
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
+ }
242
244
  }
243
245
  else {
244
- tr.insert(state.selection.anchor, state.schema.nodes.link.create(attrs, contents));
246
+ tr.insert(state.selection.anchor, schema.nodes.link.create());
245
247
  }
246
248
  if (dispatch) {
247
249
  const selection = NodeSelection.create(tr.doc, state.tr.selection.from);