@manuscripts/body-editor 3.9.11 → 3.9.13
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.
- package/dist/cjs/commands.js +5 -2
- package/dist/cjs/components/keywords/AddKeywordInline.js +12 -1
- package/dist/cjs/components/views/FigureDropdown.js +65 -6
- package/dist/cjs/configs/ManuscriptsEditor.js +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/keys/misc.js +2 -1
- package/dist/cjs/keys/title.js +0 -38
- package/dist/cjs/lib/comments.js +1 -0
- package/dist/cjs/lib/context-menu.js +74 -8
- package/dist/cjs/lib/media.js +27 -3
- package/dist/cjs/lib/navigation-utils.js +132 -0
- package/dist/cjs/lib/popper.js +25 -1
- package/dist/cjs/lib/position-menu.js +3 -0
- package/dist/cjs/lib/utils.js +7 -2
- package/dist/cjs/plugins/accessibility_element.js +10 -2
- package/dist/cjs/plugins/add-subtitle.js +8 -2
- package/dist/cjs/plugins/alt-titles.js +6 -1
- package/dist/cjs/plugins/comments.js +27 -15
- package/dist/cjs/plugins/persistent-cursor.js +4 -6
- package/dist/cjs/plugins/section_category.js +42 -9
- package/dist/cjs/plugins/translations.js +49 -13
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/accessibility_element.js +30 -0
- package/dist/cjs/views/alt_title.js +29 -0
- package/dist/cjs/views/alt_titles_section.js +9 -1
- package/dist/cjs/views/attachment.js +1 -1
- package/dist/cjs/views/bibliography_element.js +39 -17
- package/dist/cjs/views/citation.js +1 -0
- package/dist/cjs/views/citation_editable.js +4 -2
- package/dist/cjs/views/contributors.js +23 -2
- package/dist/cjs/views/cross_reference.js +3 -0
- package/dist/cjs/views/editable_block.js +37 -3
- package/dist/cjs/views/embed.js +3 -3
- package/dist/cjs/views/figure_editable.js +1 -1
- package/dist/cjs/views/figure_element.js +3 -0
- package/dist/cjs/views/footnote.js +3 -0
- package/dist/cjs/views/hero_image.js +4 -1
- package/dist/cjs/views/image_element.js +15 -7
- package/dist/cjs/views/inline_footnote.js +3 -0
- package/dist/cjs/views/keyword.js +15 -0
- package/dist/cjs/views/keyword_group.js +38 -0
- package/dist/cjs/views/quote_image_editable.js +1 -0
- package/dist/cjs/views/supplements.js +4 -1
- package/dist/es/commands.js +5 -2
- package/dist/es/components/keywords/AddKeywordInline.js +12 -1
- package/dist/es/components/views/FigureDropdown.js +66 -7
- package/dist/es/configs/ManuscriptsEditor.js +1 -1
- package/dist/es/index.js +1 -0
- package/dist/es/keys/misc.js +2 -1
- package/dist/es/keys/title.js +1 -39
- package/dist/es/lib/comments.js +1 -0
- package/dist/es/lib/context-menu.js +74 -8
- package/dist/es/lib/media.js +27 -3
- package/dist/es/lib/navigation-utils.js +122 -0
- package/dist/es/lib/popper.js +25 -1
- package/dist/es/lib/position-menu.js +3 -0
- package/dist/es/lib/utils.js +7 -2
- package/dist/es/plugins/accessibility_element.js +10 -2
- package/dist/es/plugins/add-subtitle.js +8 -2
- package/dist/es/plugins/alt-titles.js +6 -1
- package/dist/es/plugins/comments.js +27 -15
- package/dist/es/plugins/persistent-cursor.js +4 -6
- package/dist/es/plugins/section_category.js +42 -9
- package/dist/es/plugins/translations.js +49 -13
- package/dist/es/versions.js +1 -1
- package/dist/es/views/accessibility_element.js +30 -0
- package/dist/es/views/alt_title.js +29 -0
- package/dist/es/views/alt_titles_section.js +9 -1
- package/dist/es/views/attachment.js +1 -1
- package/dist/es/views/bibliography_element.js +39 -17
- package/dist/es/views/citation.js +1 -0
- package/dist/es/views/citation_editable.js +4 -2
- package/dist/es/views/contributors.js +23 -2
- package/dist/es/views/cross_reference.js +3 -0
- package/dist/es/views/editable_block.js +37 -3
- package/dist/es/views/embed.js +3 -3
- package/dist/es/views/figure_editable.js +1 -1
- package/dist/es/views/figure_element.js +3 -0
- package/dist/es/views/footnote.js +3 -0
- package/dist/es/views/hero_image.js +4 -1
- package/dist/es/views/image_element.js +15 -7
- package/dist/es/views/inline_footnote.js +3 -0
- package/dist/es/views/keyword.js +15 -0
- package/dist/es/views/keyword_group.js +38 -0
- package/dist/es/views/quote_image_editable.js +1 -0
- package/dist/es/views/supplements.js +4 -1
- package/dist/types/configs/ManuscriptsEditor.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/lib/context-menu.d.ts +1 -0
- package/dist/types/lib/media.d.ts +1 -1
- package/dist/types/lib/navigation-utils.d.ts +45 -0
- package/dist/types/lib/popper.d.ts +3 -0
- package/dist/types/lib/utils.d.ts +1 -1
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/accessibility_element.d.ts +2 -0
- package/dist/types/views/alt_title.d.ts +2 -0
- package/dist/types/views/bibliography_element.d.ts +3 -0
- package/dist/types/views/citation_editable.d.ts +1 -1
- package/dist/types/views/contributors.d.ts +3 -1
- package/dist/types/views/keyword.d.ts +1 -0
- package/dist/types/views/keyword_group.d.ts +4 -0
- package/package.json +4 -4
- package/styles/AdvancedEditor.css +116 -10
- package/styles/Editor.css +61 -6
- package/styles/popper.css +3 -1
|
@@ -4,10 +4,18 @@ import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
|
4
4
|
import { createToggleButton } from '../lib/utils';
|
|
5
5
|
export const accessibilityElementKey = new PluginKey('accessibility-element');
|
|
6
6
|
const nodeTypes = [schema.nodes.alt_text, schema.nodes.long_desc];
|
|
7
|
-
const handleExpandButtonClick = (view, node) => {
|
|
7
|
+
const handleExpandButtonClick = (view, node, event) => {
|
|
8
8
|
const tr = view.state.tr;
|
|
9
9
|
toggleAccessibilitySection(tr, node);
|
|
10
10
|
view.dispatch(tr);
|
|
11
|
+
const isKeyboardEvent = event.type === 'keydown';
|
|
12
|
+
if (isKeyboardEvent) {
|
|
13
|
+
const parentElement = view.dom.querySelector(`[id="${node.attrs.id}"]`);
|
|
14
|
+
if (parentElement) {
|
|
15
|
+
const firstInput = parentElement.querySelector('.accessibility_element_input');
|
|
16
|
+
firstInput?.focus();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
11
19
|
};
|
|
12
20
|
const isSelectionWithin = (node, pos, selection) => {
|
|
13
21
|
if (!selection || !nodeTypes.includes(node.type)) {
|
|
@@ -24,7 +32,7 @@ const buildExpandButtonDecorations = (doc) => {
|
|
|
24
32
|
const container = document.createElement('div');
|
|
25
33
|
container.className =
|
|
26
34
|
'accessibility_element_expander_button_container';
|
|
27
|
-
container.appendChild(createToggleButton(() => handleExpandButtonClick(view, node), 'additional info'));
|
|
35
|
+
container.appendChild(createToggleButton((e) => handleExpandButtonClick(view, node, e), 'additional info'));
|
|
28
36
|
return container;
|
|
29
37
|
}, {
|
|
30
38
|
key: node.attrs.id,
|
|
@@ -18,15 +18,21 @@ import { Plugin, TextSelection } from 'prosemirror-state';
|
|
|
18
18
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
19
19
|
import { v4 as uuidv4 } from 'uuid';
|
|
20
20
|
import { addAuthorIcon } from '../icons';
|
|
21
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
21
22
|
import { findInsertionPosition } from '../lib/utils';
|
|
22
23
|
const createAddSubtitleButton = (handler) => {
|
|
23
24
|
const button = document.createElement('span');
|
|
24
25
|
button.className = 'add-subtitle';
|
|
25
26
|
button.innerHTML = `${addAuthorIcon} <span class="add-subtitle-text">Add subtitle</span>`;
|
|
26
|
-
button.
|
|
27
|
-
|
|
27
|
+
button.tabIndex = 0;
|
|
28
|
+
const activate = (event) => {
|
|
29
|
+
event.preventDefault();
|
|
28
30
|
handler();
|
|
31
|
+
};
|
|
32
|
+
button.addEventListener('mousedown', (e) => {
|
|
33
|
+
activate(e);
|
|
29
34
|
});
|
|
35
|
+
button.addEventListener('keydown', handleEnterKey(activate));
|
|
30
36
|
return button;
|
|
31
37
|
};
|
|
32
38
|
export default (props) => new Plugin({
|
|
@@ -131,11 +131,16 @@ export default () => {
|
|
|
131
131
|
else if (pState.title[0].textContent.length) {
|
|
132
132
|
const titleEnd = pState.title[0].nodeSize + pState.title[1];
|
|
133
133
|
decorations.push(Decoration.widget(titleEnd - 1, (view) => {
|
|
134
|
-
return createToggleButton(() => {
|
|
134
|
+
return createToggleButton((e) => {
|
|
135
135
|
const tr = view.state.tr.setMeta(altTitlesKey, {
|
|
136
136
|
collapsed: false,
|
|
137
137
|
});
|
|
138
138
|
view.dispatch(skipTracking(tr));
|
|
139
|
+
const isKeyboardEvent = e.type === 'keydown';
|
|
140
|
+
if (isKeyboardEvent) {
|
|
141
|
+
const altTitle = view.dom.querySelector('.alt-title-text');
|
|
142
|
+
altTitle?.focus();
|
|
143
|
+
}
|
|
139
144
|
}, 'alternative titles');
|
|
140
145
|
}, {
|
|
141
146
|
side: -1,
|
|
@@ -2,10 +2,28 @@ import { schema, } from '@manuscripts/transform';
|
|
|
2
2
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
3
3
|
import { findChildrenByType } from 'prosemirror-utils';
|
|
4
4
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
5
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
5
6
|
import { createCommentMarker, getCommentKey, isReply, } from '../lib/comments';
|
|
6
7
|
export const commentsKey = new PluginKey('comments');
|
|
7
8
|
const COMMENT_SELECTION = 'comment-selection';
|
|
8
9
|
const EMPTY_SELECTION = {};
|
|
10
|
+
const handleCommentMarkerInteraction = (view, target) => {
|
|
11
|
+
const state = view.state;
|
|
12
|
+
const com = commentsKey.getState(state);
|
|
13
|
+
const marker = target?.closest('[data-key]');
|
|
14
|
+
if (!marker && !com?.selection) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const tr = state.tr;
|
|
18
|
+
if (marker) {
|
|
19
|
+
const key = marker.dataset.key;
|
|
20
|
+
setCommentSelection(tr, key, undefined, false);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
clearCommentSelection(tr);
|
|
24
|
+
}
|
|
25
|
+
view.dispatch(tr);
|
|
26
|
+
};
|
|
9
27
|
export default () => {
|
|
10
28
|
return new Plugin({
|
|
11
29
|
key: commentsKey,
|
|
@@ -24,22 +42,16 @@ export default () => {
|
|
|
24
42
|
props: {
|
|
25
43
|
decorations: (state) => commentsKey.getState(state)?.decorations,
|
|
26
44
|
handleClick: (view, pos, e) => {
|
|
27
|
-
const state = view.state;
|
|
28
|
-
const com = commentsKey.getState(state);
|
|
29
45
|
const target = e.target;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
clearCommentSelection(tr);
|
|
41
|
-
}
|
|
42
|
-
view.dispatch(tr);
|
|
46
|
+
return handleCommentMarkerInteraction(view, target);
|
|
47
|
+
},
|
|
48
|
+
handleDOMEvents: {
|
|
49
|
+
keydown: (view, e) => {
|
|
50
|
+
return handleEnterKey(() => {
|
|
51
|
+
const target = document.activeElement;
|
|
52
|
+
handleCommentMarkerInteraction(view, target);
|
|
53
|
+
})(e);
|
|
54
|
+
},
|
|
43
55
|
},
|
|
44
56
|
},
|
|
45
57
|
});
|
|
@@ -46,12 +46,10 @@ export default () => {
|
|
|
46
46
|
},
|
|
47
47
|
handleDOMEvents: {
|
|
48
48
|
focus(view, event) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const newTr = view.state.tr.setMeta(persistentCursor, { on: true });
|
|
54
|
-
view.dispatch(newTr);
|
|
49
|
+
if (this.getState(view.state)?.on) {
|
|
50
|
+
const newTr = view.state.tr.setMeta(persistentCursor, { on: false });
|
|
51
|
+
view.dispatch(newTr);
|
|
52
|
+
}
|
|
55
53
|
},
|
|
56
54
|
},
|
|
57
55
|
},
|
|
@@ -3,6 +3,7 @@ import { Plugin, PluginKey } from 'prosemirror-state';
|
|
|
3
3
|
import { findChildrenByType, findParentNodeOfTypeClosestToPos, } from 'prosemirror-utils';
|
|
4
4
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
5
5
|
import { sectionCategoryIcon } from '../icons';
|
|
6
|
+
import { handleEnterKey, createKeyboardInteraction, } from '../lib/navigation-utils';
|
|
6
7
|
export const sectionCategoryKey = new PluginKey('section-category');
|
|
7
8
|
export default (props) => new Plugin({
|
|
8
9
|
key: sectionCategoryKey,
|
|
@@ -29,27 +30,51 @@ const createMenuItem = (props, contents, handler, isDisabled, isSelected) => {
|
|
|
29
30
|
item.classList.add('disabled');
|
|
30
31
|
}
|
|
31
32
|
item.textContent = contents;
|
|
32
|
-
item.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
33
|
+
item.setAttribute('tabindex', '0');
|
|
34
|
+
item.addEventListener('mousedown', handler);
|
|
35
|
+
item.addEventListener('keydown', handleEnterKey(handler));
|
|
36
36
|
return item;
|
|
37
37
|
};
|
|
38
38
|
const createMenu = (props, currentCategory, categories, usedCategoryIDs, onSelect) => {
|
|
39
39
|
const menu = document.createElement('div');
|
|
40
40
|
menu.className = 'section-category menu';
|
|
41
|
+
const menuItems = [];
|
|
42
|
+
const removeKeydownListener = createKeyboardInteraction({
|
|
43
|
+
container: document,
|
|
44
|
+
navigation: {
|
|
45
|
+
getItems: () => menuItems,
|
|
46
|
+
arrowKeys: {
|
|
47
|
+
forward: 'ArrowDown',
|
|
48
|
+
backward: 'ArrowUp',
|
|
49
|
+
},
|
|
50
|
+
getCurrentElement: () => document.activeElement,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const destroy = () => {
|
|
54
|
+
removeKeydownListener();
|
|
55
|
+
props.popper.destroy();
|
|
56
|
+
};
|
|
41
57
|
categories.forEach((category) => {
|
|
42
|
-
const item = createMenuItem(props, category.titles[0], () =>
|
|
58
|
+
const item = createMenuItem(props, category.titles[0], () => {
|
|
59
|
+
onSelect(category);
|
|
60
|
+
destroy();
|
|
61
|
+
}, category.isUnique && usedCategoryIDs.has(category.id), currentCategory === category);
|
|
62
|
+
menuItems.push(item);
|
|
43
63
|
menu.appendChild(item);
|
|
44
64
|
});
|
|
45
|
-
return menu;
|
|
65
|
+
return { menu, destroy };
|
|
46
66
|
};
|
|
47
67
|
const createButton = (props, view, pos, currentCategory, categories, usedCategoryIDs, canEdit = true, disabled) => {
|
|
68
|
+
let menuInstance = null;
|
|
48
69
|
const handleSelect = (category) => {
|
|
49
70
|
const tr = view.state.tr;
|
|
50
71
|
tr.setNodeAttribute(pos, 'category', category.id);
|
|
51
72
|
view.dispatch(tr);
|
|
52
73
|
};
|
|
74
|
+
const openMenu = () => {
|
|
75
|
+
menuInstance = createMenu(props, currentCategory, categories, usedCategoryIDs, handleSelect);
|
|
76
|
+
props.popper.show(button, menuInstance.menu, 'bottom-end', false);
|
|
77
|
+
};
|
|
53
78
|
const button = document.createElement('button');
|
|
54
79
|
button.innerHTML = sectionCategoryIcon;
|
|
55
80
|
button.classList.add('section-category-button');
|
|
@@ -62,9 +87,17 @@ const createButton = (props, view, pos, currentCategory, categories, usedCategor
|
|
|
62
87
|
button.classList.add('disabled');
|
|
63
88
|
}
|
|
64
89
|
else if (canEdit) {
|
|
65
|
-
button.addEventListener('
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
button.addEventListener('click', openMenu);
|
|
91
|
+
createKeyboardInteraction({
|
|
92
|
+
container: button,
|
|
93
|
+
additionalKeys: {
|
|
94
|
+
Enter: openMenu,
|
|
95
|
+
Escape: (e) => {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
menuInstance?.destroy();
|
|
98
|
+
menuInstance = null;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
68
101
|
});
|
|
69
102
|
}
|
|
70
103
|
return button;
|
|
@@ -20,24 +20,43 @@ import { insertTransAbstract, insertTransGraphicalAbstract } from '../commands';
|
|
|
20
20
|
import { addAuthorIcon, translateIcon } from '../icons';
|
|
21
21
|
import { getLanguage, getLanguageLabel } from '../lib/languages';
|
|
22
22
|
import { templateAllows } from '../lib/template';
|
|
23
|
-
|
|
23
|
+
import { handleEnterKey, createKeyboardInteraction, } from '../lib/navigation-utils';
|
|
24
|
+
const createMenuItem = (props, contents, handler, isSelected = false, tabIndex) => {
|
|
24
25
|
const item = document.createElement('div');
|
|
25
26
|
item.className = `menu-item ${isSelected ? 'selected' : ''}`;
|
|
26
27
|
item.textContent = contents;
|
|
27
|
-
item.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
28
|
+
item.tabIndex = tabIndex;
|
|
29
|
+
item.addEventListener('mousedown', handler);
|
|
30
|
+
item.addEventListener('keydown', handleEnterKey(handler));
|
|
31
31
|
return item;
|
|
32
32
|
};
|
|
33
33
|
const createLanguageMenu = (props, selectedCode, onSelect) => {
|
|
34
34
|
const menu = document.createElement('div');
|
|
35
35
|
menu.className = 'language menu';
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const menuItems = [];
|
|
37
|
+
const removeKeydownListener = createKeyboardInteraction({
|
|
38
|
+
container: document,
|
|
39
|
+
navigation: {
|
|
40
|
+
getItems: () => menuItems,
|
|
41
|
+
arrowKeys: {
|
|
42
|
+
forward: 'ArrowDown',
|
|
43
|
+
backward: 'ArrowUp',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
const destroy = () => {
|
|
48
|
+
removeKeydownListener();
|
|
49
|
+
props.popper.destroy();
|
|
50
|
+
};
|
|
51
|
+
props.languages.forEach((language, index) => {
|
|
52
|
+
const item = createMenuItem(props, getLanguageLabel(language), () => {
|
|
53
|
+
onSelect(language.code);
|
|
54
|
+
destroy();
|
|
55
|
+
}, selectedCode === language.code, index === 0 ? 0 : -1);
|
|
56
|
+
menuItems.push(item);
|
|
38
57
|
menu.appendChild(item);
|
|
39
58
|
});
|
|
40
|
-
return menu;
|
|
59
|
+
return { menu, destroy };
|
|
41
60
|
};
|
|
42
61
|
export default (props) => new Plugin({
|
|
43
62
|
props: {
|
|
@@ -64,10 +83,11 @@ export default (props) => new Plugin({
|
|
|
64
83
|
if (canEdit) {
|
|
65
84
|
widgets.push(Decoration.widget(pos + 1, (view) => {
|
|
66
85
|
const $span = document.createElement('span');
|
|
86
|
+
$span.tabIndex = 0;
|
|
67
87
|
$span.className = 'add-trans-abstract';
|
|
68
88
|
$span.title = 'Add translation';
|
|
69
89
|
$span.innerHTML = `${addAuthorIcon} <span class="add-trans-abstract-text">Add translation</span>`;
|
|
70
|
-
|
|
90
|
+
const handleActivate = (event) => {
|
|
71
91
|
event.preventDefault();
|
|
72
92
|
event.stopPropagation();
|
|
73
93
|
if (isGraphical && category) {
|
|
@@ -76,7 +96,9 @@ export default (props) => new Plugin({
|
|
|
76
96
|
else {
|
|
77
97
|
insertTransAbstract(view.state, view.dispatch, node.attrs.category, pos + node.nodeSize);
|
|
78
98
|
}
|
|
79
|
-
}
|
|
99
|
+
};
|
|
100
|
+
$span.addEventListener('mousedown', handleActivate);
|
|
101
|
+
$span.addEventListener('keydown', handleEnterKey(handleActivate));
|
|
80
102
|
return $span;
|
|
81
103
|
}));
|
|
82
104
|
}
|
|
@@ -92,12 +114,14 @@ export default (props) => new Plugin({
|
|
|
92
114
|
$btn.className = 'language-selector-btn';
|
|
93
115
|
$btn.setAttribute('data-cy', 'language-selector-btn');
|
|
94
116
|
$btn.contentEditable = 'false';
|
|
117
|
+
$btn.tabIndex = canEdit ? 0 : -1;
|
|
95
118
|
const code = node.attrs.lang || 'en';
|
|
96
119
|
const lang = getLanguage(code, props.languages);
|
|
97
120
|
const label = getLanguageLabel(lang);
|
|
98
121
|
$btn.innerHTML = `<span>${label}</span> ${translateIcon}`;
|
|
99
122
|
if (canEdit) {
|
|
100
|
-
|
|
123
|
+
let menuInstance = null;
|
|
124
|
+
const handleOpenMenu = (event) => {
|
|
101
125
|
event.preventDefault();
|
|
102
126
|
event.stopPropagation();
|
|
103
127
|
props.popper.destroy();
|
|
@@ -105,9 +129,21 @@ export default (props) => new Plugin({
|
|
|
105
129
|
const tr = view.state.tr.setNodeAttribute(pos, 'lang', code);
|
|
106
130
|
view.dispatch(tr);
|
|
107
131
|
};
|
|
108
|
-
|
|
109
|
-
props.popper.show($btn, menu, 'bottom-end', false);
|
|
132
|
+
menuInstance = createLanguageMenu(props, code, handleSelect);
|
|
133
|
+
props.popper.show($btn, menuInstance.menu, 'bottom-end', false);
|
|
134
|
+
};
|
|
135
|
+
createKeyboardInteraction({
|
|
136
|
+
container: $btn,
|
|
137
|
+
additionalKeys: {
|
|
138
|
+
Enter: handleOpenMenu,
|
|
139
|
+
Escape: (e) => {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
menuInstance?.destroy();
|
|
142
|
+
menuInstance = null;
|
|
143
|
+
},
|
|
144
|
+
},
|
|
110
145
|
});
|
|
146
|
+
$btn.addEventListener('mousedown', handleOpenMenu);
|
|
111
147
|
}
|
|
112
148
|
return $btn;
|
|
113
149
|
}));
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '3.9.
|
|
1
|
+
export const VERSION = '3.9.13';
|
|
2
2
|
export const MATHJAX_VERSION = '3.2.2';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { schema } from '@manuscripts/transform';
|
|
2
|
+
import { TextSelection } from 'prosemirror-state';
|
|
3
|
+
import { createKeyboardInteraction } from '../lib/navigation-utils';
|
|
2
4
|
import BlockView from './block_view';
|
|
3
5
|
import { createNodeView } from './creators';
|
|
4
6
|
export class AccessibilityElementView extends BlockView {
|
|
@@ -23,6 +25,34 @@ export class AccessibilityElementView extends BlockView {
|
|
|
23
25
|
super.createElement();
|
|
24
26
|
this.contentDOM.className = 'accessibility_element_input';
|
|
25
27
|
this.contentDOM.setAttribute('contenteditable', 'true');
|
|
28
|
+
this.contentDOM.tabIndex = this.node.type === schema.nodes.alt_text ? 0 : -1;
|
|
29
|
+
this.removeKeydownListener = createKeyboardInteraction({
|
|
30
|
+
container: this.contentDOM,
|
|
31
|
+
navigation: {
|
|
32
|
+
getItems: () => {
|
|
33
|
+
const parentEl = this.dom.parentElement;
|
|
34
|
+
if (!parentEl) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
return Array.from(parentEl.querySelectorAll('.accessibility_element_input'));
|
|
38
|
+
},
|
|
39
|
+
arrowKeys: { forward: 'ArrowDown', backward: 'ArrowUp' },
|
|
40
|
+
getCurrentElement: () => this.contentDOM,
|
|
41
|
+
},
|
|
42
|
+
additionalKeys: {
|
|
43
|
+
Enter: (e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
const pos = this.getPos();
|
|
46
|
+
const tr = this.view.state.tr.setSelection(TextSelection.create(this.view.state.doc, pos + 1));
|
|
47
|
+
this.view.dispatch(tr);
|
|
48
|
+
this.view.focus();
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
destroy() {
|
|
54
|
+
this.removeKeydownListener?.();
|
|
55
|
+
super.destroy();
|
|
26
56
|
}
|
|
27
57
|
}
|
|
28
58
|
export default createNodeView(AccessibilityElementView);
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { TextSelection } from 'prosemirror-state';
|
|
17
|
+
import { createKeyboardInteraction } from '../lib/navigation-utils';
|
|
16
18
|
import { BaseNodeView } from './base_node_view';
|
|
17
19
|
import { createNodeView } from './creators';
|
|
18
20
|
export class AltTitleView extends BaseNodeView {
|
|
@@ -31,10 +33,37 @@ export class AltTitleView extends BaseNodeView {
|
|
|
31
33
|
this.dom.setAttribute('data-type', this.node.attrs.type);
|
|
32
34
|
this.contentDOM = document.createElement('div');
|
|
33
35
|
this.contentDOM.classList.add('alt-title-text');
|
|
36
|
+
this.contentDOM.tabIndex = this.node.attrs.type === 'running' ? 0 : -1;
|
|
37
|
+
this.removeKeydownListener = createKeyboardInteraction({
|
|
38
|
+
container: this.contentDOM,
|
|
39
|
+
navigation: {
|
|
40
|
+
getItems: () => {
|
|
41
|
+
const allAltTitles = Array.from(this.view.dom.querySelectorAll('.alt-title-text'));
|
|
42
|
+
return allAltTitles;
|
|
43
|
+
},
|
|
44
|
+
arrowKeys: { forward: 'ArrowDown', backward: 'ArrowUp' },
|
|
45
|
+
getCurrentElement: () => this.contentDOM,
|
|
46
|
+
},
|
|
47
|
+
additionalKeys: {
|
|
48
|
+
Enter: (e) => {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
const pos = this.getPos();
|
|
51
|
+
if (typeof pos === 'number') {
|
|
52
|
+
const tr = this.view.state.tr.setSelection(TextSelection.create(this.view.state.doc, pos + 1));
|
|
53
|
+
this.view.dispatch(tr);
|
|
54
|
+
this.view.focus();
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
34
59
|
this.dom.appendChild(label);
|
|
35
60
|
this.dom.appendChild(this.contentDOM);
|
|
36
61
|
this.updateContents();
|
|
37
62
|
};
|
|
38
63
|
}
|
|
64
|
+
destroy() {
|
|
65
|
+
this.removeKeydownListener?.();
|
|
66
|
+
super.destroy();
|
|
67
|
+
}
|
|
39
68
|
}
|
|
40
69
|
export default createNodeView(AltTitleView);
|
|
@@ -19,6 +19,7 @@ import { arrowDown } from '../icons';
|
|
|
19
19
|
import { altTitlesKey } from '../plugins/alt-titles';
|
|
20
20
|
import BlockView from './block_view';
|
|
21
21
|
import { createNodeView } from './creators';
|
|
22
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
22
23
|
export class AltTitleSectionView extends BlockView {
|
|
23
24
|
constructor() {
|
|
24
25
|
super(...arguments);
|
|
@@ -41,7 +42,7 @@ export class AltTitleSectionView extends BlockView {
|
|
|
41
42
|
button.classList.add('alt-titles-closing-button', 'button-reset');
|
|
42
43
|
button.setAttribute('aria-label', 'Collapse alternative titles');
|
|
43
44
|
button.innerHTML = arrowDown;
|
|
44
|
-
|
|
45
|
+
const handleCollapse = () => {
|
|
45
46
|
const tr = this.view.state.tr.setMeta(altTitlesKey, {
|
|
46
47
|
collapsed: true,
|
|
47
48
|
});
|
|
@@ -53,7 +54,14 @@ export class AltTitleSectionView extends BlockView {
|
|
|
53
54
|
tr.setSelection(TextSelection.create(tr.doc, titleEndPos));
|
|
54
55
|
}
|
|
55
56
|
this.view.dispatch(tr);
|
|
57
|
+
const toggleButton = this.view.dom.querySelector('.toggle-button-open');
|
|
58
|
+
toggleButton?.focus();
|
|
59
|
+
};
|
|
60
|
+
button.addEventListener('click', (e) => {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
handleCollapse();
|
|
56
63
|
});
|
|
64
|
+
button.addEventListener('keydown', handleEnterKey(() => handleCollapse()));
|
|
57
65
|
closingPanel.appendChild(button);
|
|
58
66
|
return closingPanel;
|
|
59
67
|
}
|
|
@@ -18,6 +18,7 @@ import { schema, } from '@manuscripts/transform';
|
|
|
18
18
|
import { NodeSelection } from 'prosemirror-state';
|
|
19
19
|
import { ReferencesEditor, } from '../components/references/ReferencesEditor';
|
|
20
20
|
import { createCommentMarker, handleComment } from '../lib/comments';
|
|
21
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
21
22
|
import { findNodeByID } from '../lib/doc';
|
|
22
23
|
import { sanitize } from '../lib/dompurify';
|
|
23
24
|
import { addTrackChangesAttributes, addTrackChangesClassNames, } from '../lib/track-changes-utils';
|
|
@@ -33,31 +34,50 @@ export class BibliographyElementBlockView extends BlockView {
|
|
|
33
34
|
super(...arguments);
|
|
34
35
|
this.stopEvent = () => true;
|
|
35
36
|
this.ignoreMutation = () => true;
|
|
37
|
+
this.handleCommentMarkerInteraction = (marker) => {
|
|
38
|
+
const key = marker.dataset.key;
|
|
39
|
+
const tr = this.view.state.tr;
|
|
40
|
+
setCommentSelection(tr, key, undefined, false);
|
|
41
|
+
this.view.dispatch(tr);
|
|
42
|
+
};
|
|
43
|
+
this.handleBibItemInteraction = (item) => {
|
|
44
|
+
if (!this.props.getCapabilities().seeReferencesButtons) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this.showContextMenu(item);
|
|
48
|
+
const node = findChildByID(this.view, item.id);
|
|
49
|
+
if (node) {
|
|
50
|
+
const tr = this.view.state.tr;
|
|
51
|
+
tr.setSelection(NodeSelection.create(this.view.state.doc, node.pos));
|
|
52
|
+
this.view.dispatch(tr);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
36
55
|
this.handleClick = (event) => {
|
|
37
56
|
const element = event.target;
|
|
38
57
|
const marker = element.closest('.comment-marker');
|
|
39
58
|
if (marker) {
|
|
40
|
-
|
|
41
|
-
const tr = this.view.state.tr;
|
|
42
|
-
setCommentSelection(tr, key, undefined, false);
|
|
43
|
-
this.view.dispatch(tr);
|
|
59
|
+
this.handleCommentMarkerInteraction(marker);
|
|
44
60
|
return;
|
|
45
61
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.showContextMenu(item);
|
|
50
|
-
const node = findChildByID(this.view, item.id);
|
|
51
|
-
if (!node) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const view = this.view;
|
|
55
|
-
const tr = view.state.tr;
|
|
56
|
-
tr.setSelection(NodeSelection.create(view.state.doc, node.pos));
|
|
57
|
-
view.dispatch(tr);
|
|
58
|
-
}
|
|
62
|
+
const item = element.closest('.bib-item');
|
|
63
|
+
if (item) {
|
|
64
|
+
this.handleBibItemInteraction(item);
|
|
59
65
|
}
|
|
60
66
|
};
|
|
67
|
+
this.handleKeyDown = (event) => {
|
|
68
|
+
handleEnterKey(() => {
|
|
69
|
+
const target = document.activeElement;
|
|
70
|
+
const marker = target?.closest('.comment-marker');
|
|
71
|
+
if (marker) {
|
|
72
|
+
this.handleCommentMarkerInteraction(marker);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const bibItem = target?.closest('.bib-item');
|
|
76
|
+
if (bibItem) {
|
|
77
|
+
this.handleBibItemInteraction(bibItem);
|
|
78
|
+
}
|
|
79
|
+
})(event);
|
|
80
|
+
};
|
|
61
81
|
this.createElement = () => {
|
|
62
82
|
this.container = document.createElement('div');
|
|
63
83
|
this.container.classList.add('block');
|
|
@@ -164,6 +184,7 @@ export class BibliographyElementBlockView extends BlockView {
|
|
|
164
184
|
const wrapper = document.createElement('div');
|
|
165
185
|
wrapper.classList.add('contents');
|
|
166
186
|
wrapper.addEventListener('click', this.handleClick);
|
|
187
|
+
wrapper.addEventListener('keydown', this.handleKeyDown);
|
|
167
188
|
const [meta, bibliography] = bib.engine.makeBibliography();
|
|
168
189
|
for (let i = 0; i < bibliography.length; i++) {
|
|
169
190
|
const id = meta.entry_ids[i][0];
|
|
@@ -190,6 +211,7 @@ export class BibliographyElementBlockView extends BlockView {
|
|
|
190
211
|
}
|
|
191
212
|
}
|
|
192
213
|
const element = sanitize(`<div id="${id}" class="bib-item"><div class="csl-bib-body">${tempDiv.innerHTML}</div></div>`).firstElementChild;
|
|
214
|
+
element.tabIndex = 0;
|
|
193
215
|
const comment = createCommentMarker('div', id);
|
|
194
216
|
element.prepend(comment);
|
|
195
217
|
addTrackChangesAttributes(node.attrs, element);
|
|
@@ -21,6 +21,7 @@ import { CitationEditor, } from '../components/references/CitationEditor';
|
|
|
21
21
|
import { CitationViewer, } from '../components/references/CitationViewer';
|
|
22
22
|
import { handleComment } from '../lib/comments';
|
|
23
23
|
import { Crossref } from '../lib/crossref';
|
|
24
|
+
import { handleEnterKey } from '../lib/navigation-utils';
|
|
24
25
|
import { isDeleted } from '../lib/track-changes-utils';
|
|
25
26
|
import { deleteNode, findChildByID, updateNodeAttrs } from '../lib/view';
|
|
26
27
|
import { getBibliographyPluginState } from '../plugins/bibliography';
|
|
@@ -41,12 +42,12 @@ export class CitationEditableView extends CitationView {
|
|
|
41
42
|
element.classList.contains('comment-icon') ||
|
|
42
43
|
element.parentElement?.classList.contains('comment-icon'));
|
|
43
44
|
};
|
|
44
|
-
this.handleClick = (
|
|
45
|
+
this.handleClick = () => {
|
|
45
46
|
if (!this.can.seeReferencesButtons ||
|
|
46
47
|
this.dom.classList.contains('inconsistency-highlight')) {
|
|
47
48
|
this.showPopper();
|
|
48
49
|
}
|
|
49
|
-
else if (!isDeleted(this.node)
|
|
50
|
+
else if (!isDeleted(this.node)) {
|
|
50
51
|
const attrs = this.node.attrs;
|
|
51
52
|
if (attrs.rids.length) {
|
|
52
53
|
this.showContextMenu();
|
|
@@ -191,6 +192,7 @@ export class CitationEditableView extends CitationView {
|
|
|
191
192
|
createDOM() {
|
|
192
193
|
super.createDOM();
|
|
193
194
|
this.dom.addEventListener('mouseup', this.handleClick);
|
|
195
|
+
this.dom.addEventListener('keydown', handleEnterKey(() => this.handleClick()));
|
|
194
196
|
}
|
|
195
197
|
insertBibliographyNode(attrs) {
|
|
196
198
|
const { doc, tr } = this.view.state;
|