@manuscripts/body-editor 3.16.1 → 3.16.2
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/components/references/CitationEditor.js +13 -19
- package/dist/cjs/components/references/ImportBibliography.js +77 -0
- package/dist/cjs/components/references/ImportBibliographyForm.js +1 -1
- package/dist/cjs/components/references/ImportBibliographyModal.js +12 -81
- package/dist/cjs/components/references/ImportReferencesConfirmation.js +113 -0
- package/dist/cjs/components/references/ImportSuccessPlaceholder.js +56 -0
- package/dist/cjs/components/references/ReferenceSearch.js +2 -5
- package/dist/cjs/components/references/ReferencesEditor.js +18 -2
- package/dist/cjs/components/references/ReferencesModal.js +86 -33
- package/dist/cjs/lib/view.js +39 -1
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/bibliography_element.js +1 -2
- package/dist/cjs/views/citation_editable.js +2 -29
- package/dist/es/components/references/CitationEditor.js +13 -19
- package/dist/es/components/references/ImportBibliography.js +70 -0
- package/dist/es/components/references/ImportBibliographyForm.js +1 -1
- package/dist/es/components/references/ImportBibliographyModal.js +13 -79
- package/dist/es/components/references/ImportReferencesConfirmation.js +73 -0
- package/dist/es/components/references/ImportSuccessPlaceholder.js +49 -0
- package/dist/es/components/references/ReferenceSearch.js +3 -6
- package/dist/es/components/references/ReferencesEditor.js +19 -3
- package/dist/es/components/references/ReferencesModal.js +88 -35
- package/dist/es/lib/view.js +36 -0
- package/dist/es/versions.js +1 -1
- package/dist/es/views/bibliography_element.js +2 -3
- package/dist/es/views/citation_editable.js +3 -30
- package/dist/types/components/references/CitationEditor.d.ts +1 -1
- package/dist/types/components/references/ImportBibliography.d.ts +7 -0
- package/dist/types/components/references/ImportReferencesConfirmation.d.ts +8 -0
- package/dist/types/components/references/ImportSuccessPlaceholder.d.ts +5 -0
- package/dist/types/components/references/ReferenceSearch.d.ts +0 -1
- package/dist/types/components/references/ReferencesEditor.d.ts +4 -1
- package/dist/types/components/references/ReferencesModal.d.ts +1 -0
- package/dist/types/lib/view.d.ts +3 -1
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/citation_editable.d.ts +0 -1
- package/package.json +1 -1
- package/src/components/references/CitationEditor.tsx +16 -25
- package/src/components/references/ImportBibliography.tsx +119 -0
- package/src/components/references/ImportBibliographyForm.tsx +1 -1
- package/src/components/references/ImportBibliographyModal.tsx +34 -110
- package/src/components/references/ImportReferencesConfirmation.tsx +133 -0
- package/src/components/references/ImportSuccessPlaceholder.tsx +93 -0
- package/src/components/references/ReferenceSearch.tsx +0 -7
- package/src/components/references/ReferencesEditor.tsx +35 -6
- package/src/components/references/ReferencesModal.tsx +164 -78
- package/src/lib/view.ts +65 -0
- package/src/versions.ts +1 -1
- package/src/views/bibliography_element.ts +3 -4
- package/src/views/citation_editable.ts +5 -50
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { CheckboxField, CheckboxLabel, FormActionsBar, ModalTitle, PrimaryButton, SecondaryButton, } from '@manuscripts/style-guide';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { ReferenceLine } from './ReferenceLine';
|
|
5
|
+
export const ImportReferencesConfirmation = ({ items, onCancel, onConfirm }) => {
|
|
6
|
+
const [selected, setSelected] = useState(() => items.map(() => true));
|
|
7
|
+
const selectedCount = selected.filter(Boolean).length;
|
|
8
|
+
const countLabel = selectedCount === 1 ? 'reference' : 'references';
|
|
9
|
+
const toggleItem = (index) => {
|
|
10
|
+
setSelected((current) => current.map((value, i) => (i === index ? !value : value)));
|
|
11
|
+
};
|
|
12
|
+
const handleConfirm = () => {
|
|
13
|
+
onConfirm(items.filter((_, index) => selected[index]));
|
|
14
|
+
};
|
|
15
|
+
return (React.createElement(React.Fragment, null,
|
|
16
|
+
React.createElement(Title, null, "Import References"),
|
|
17
|
+
React.createElement(Subtitle, null,
|
|
18
|
+
"Importing ",
|
|
19
|
+
selectedCount,
|
|
20
|
+
" ",
|
|
21
|
+
countLabel),
|
|
22
|
+
React.createElement(List, null, items.map((item, index) => (React.createElement(ListItem, { key: index },
|
|
23
|
+
React.createElement(ItemCheckbox, null,
|
|
24
|
+
React.createElement(CheckboxField, { checked: selected[index], "aria-label": `Select reference ${index + 1}`, onChange: () => toggleItem(index) }),
|
|
25
|
+
React.createElement("div", null)),
|
|
26
|
+
React.createElement(ReferenceLine, { item: item }))))),
|
|
27
|
+
React.createElement(FormActionsBar, null,
|
|
28
|
+
React.createElement(SecondaryButton, { type: "button", onClick: onCancel }, "Cancel"),
|
|
29
|
+
React.createElement(PrimaryButton, { type: "button", disabled: selectedCount === 0, onClick: handleConfirm },
|
|
30
|
+
"Import ",
|
|
31
|
+
selectedCount,
|
|
32
|
+
" ",
|
|
33
|
+
countLabel))));
|
|
34
|
+
};
|
|
35
|
+
const Title = styled(ModalTitle) `
|
|
36
|
+
border-bottom: 1px solid ${(props) => props.theme.colors.border.secondary};
|
|
37
|
+
margin: 0 -${(props) => 6 * props.theme.grid.unit}px 20px;
|
|
38
|
+
padding: 0 ${(props) => 6 * props.theme.grid.unit}px
|
|
39
|
+
${(props) => props.theme.grid.unit * 4}px;
|
|
40
|
+
`;
|
|
41
|
+
const Subtitle = styled.p `
|
|
42
|
+
color: ${(props) => props.theme.colors.text.secondary};
|
|
43
|
+
font-weight: ${(props) => props.theme.font.weight.bold};
|
|
44
|
+
margin: 0 0 16px;
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
`;
|
|
47
|
+
const List = styled.div `
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
margin-bottom: ${(props) => props.theme.grid.unit * 5}px;
|
|
51
|
+
overflow-y: auto;
|
|
52
|
+
`;
|
|
53
|
+
const ListItem = styled.div `
|
|
54
|
+
border-bottom: 1px solid ${(props) => props.theme.colors.border.secondary};
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: flex-start;
|
|
57
|
+
gap: ${(props) => props.theme.grid.unit * 3}px;
|
|
58
|
+
padding: ${(props) => props.theme.grid.unit * 3}px 0;
|
|
59
|
+
`;
|
|
60
|
+
const ItemCheckbox = styled(CheckboxLabel) `
|
|
61
|
+
flex-shrink: 0;
|
|
62
|
+
|
|
63
|
+
> div {
|
|
64
|
+
margin: 0;
|
|
65
|
+
|
|
66
|
+
&::before {
|
|
67
|
+
width: 18px;
|
|
68
|
+
height: 18px;
|
|
69
|
+
border-radius: 4px;
|
|
70
|
+
margin: 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
export const ImportSuccessPlaceholder = ({ count }) => {
|
|
4
|
+
const countLabel = count === 1 ? 'reference' : 'references';
|
|
5
|
+
return (React.createElement(Container, { "data-cy": "import-success-placeholder" },
|
|
6
|
+
React.createElement(IconCircle, null,
|
|
7
|
+
React.createElement(SuccessCheckIcon, null)),
|
|
8
|
+
React.createElement(Title, null, "Successfully Imported"),
|
|
9
|
+
React.createElement(Message, null,
|
|
10
|
+
"Your library has been updated with ",
|
|
11
|
+
count,
|
|
12
|
+
" new ",
|
|
13
|
+
countLabel,
|
|
14
|
+
".")));
|
|
15
|
+
};
|
|
16
|
+
const SuccessCheckIcon = () => (React.createElement("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" },
|
|
17
|
+
React.createElement("path", { d: "M26.6656 8L12.0004 22.6656L5.3344 15.9994", stroke: "#36B260", strokeWidth: "3", strokeLinecap: "round" })));
|
|
18
|
+
const Container = styled.div `
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
gap: ${(props) => props.theme.grid.unit * 4}px;
|
|
24
|
+
height: 100%;
|
|
25
|
+
padding: 40px;
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
text-align: center;
|
|
28
|
+
`;
|
|
29
|
+
const IconCircle = styled.div `
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
width: 64px;
|
|
34
|
+
height: 64px;
|
|
35
|
+
border-radius: 32px;
|
|
36
|
+
background: #f6ffed;
|
|
37
|
+
`;
|
|
38
|
+
const Title = styled.h2 `
|
|
39
|
+
margin: 0;
|
|
40
|
+
font-size: 24px;
|
|
41
|
+
line-height: 32px;
|
|
42
|
+
letter-spacing: -0.37px;
|
|
43
|
+
color: ${(props) => props.theme.colors.text.primary};
|
|
44
|
+
`;
|
|
45
|
+
const Message = styled.p `
|
|
46
|
+
margin: 0;
|
|
47
|
+
line-height: ${(props) => props.theme.font.lineHeight.large};
|
|
48
|
+
color: ${(props) => props.theme.colors.text.secondary};
|
|
49
|
+
`;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton,
|
|
16
|
+
import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, withFocusTrap, } from '@manuscripts/style-guide';
|
|
17
17
|
import debounce from 'lodash/debounce';
|
|
18
18
|
import React, { useState } from 'react';
|
|
19
19
|
import styled from 'styled-components';
|
|
@@ -50,7 +50,7 @@ const AddReferenceActions = styled(ButtonGroup) `
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
`;
|
|
53
|
-
export const ReferenceSearch = ({ query: initialQuery, sources, items, onAdd,
|
|
53
|
+
export const ReferenceSearch = ({ query: initialQuery, sources, items, onAdd, onCite, onCancel, }) => {
|
|
54
54
|
const [query, setQuery] = useState(initialQuery || '');
|
|
55
55
|
const [selections, setSelections] = useState(new Map());
|
|
56
56
|
const toggleSelection = (item) => {
|
|
@@ -86,10 +86,7 @@ export const ReferenceSearch = ({ query: initialQuery, sources, items, onAdd, on
|
|
|
86
86
|
React.createElement(AddReferenceActions, null,
|
|
87
87
|
React.createElement(IconTextButton, { onClick: onAdd },
|
|
88
88
|
React.createElement(AddNewIcon, null),
|
|
89
|
-
"Add new"),
|
|
90
|
-
React.createElement(IconTextButton, { onClick: onImport },
|
|
91
|
-
React.createElement(UploadIcon, null),
|
|
92
|
-
"Import new")),
|
|
89
|
+
"Add new")),
|
|
93
90
|
React.createElement(ButtonGroup, null,
|
|
94
91
|
React.createElement(SecondaryButton, { onClick: onCancel }, "Close"),
|
|
95
92
|
React.createElement(PrimaryButton, { onClick: handleClick, disabled: selections.size === 0 }, "Cite")))));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { generateNodeID, schema, } from '@manuscripts/transform';
|
|
2
|
+
import React, { useEffect, useReducer, useState } from 'react';
|
|
2
3
|
import { attrsReducer } from '../../lib/array-reducer';
|
|
3
4
|
import { cleanItemValues } from '../../lib/utils';
|
|
4
5
|
import { ReferencesModal } from './ReferencesModal';
|
|
@@ -6,9 +7,13 @@ const itemsReducer = attrsReducer();
|
|
|
6
7
|
export const ReferencesEditor = (props) => {
|
|
7
8
|
const [isOpen, setOpen] = useState(true);
|
|
8
9
|
const [items, dispatch] = useReducer(itemsReducer, props.items);
|
|
10
|
+
const [selectedItem, setSelectedItem] = useState(props.item);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
setSelectedItem(props.item);
|
|
13
|
+
}, [props.item]);
|
|
9
14
|
const handleSave = (item) => {
|
|
10
15
|
const cleanedItem = cleanItemValues(item);
|
|
11
|
-
props.onSave(cleanedItem);
|
|
16
|
+
props.onSave([cleanedItem]);
|
|
12
17
|
dispatch({
|
|
13
18
|
type: 'update',
|
|
14
19
|
items: [cleanedItem],
|
|
@@ -21,5 +26,16 @@ export const ReferencesEditor = (props) => {
|
|
|
21
26
|
item: item,
|
|
22
27
|
});
|
|
23
28
|
};
|
|
24
|
-
|
|
29
|
+
const handleImport = (data) => {
|
|
30
|
+
const newItems = data.map((item) => cleanItemValues({
|
|
31
|
+
...item,
|
|
32
|
+
id: generateNodeID(schema.nodes.bibliography_item),
|
|
33
|
+
}));
|
|
34
|
+
props.onSave(newItems);
|
|
35
|
+
dispatch({
|
|
36
|
+
type: 'set',
|
|
37
|
+
state: [...items, ...newItems],
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
return (React.createElement(ReferencesModal, { isOpen: isOpen, onCancel: () => setOpen(false), items: items, item: selectedItem, citationCounts: props.citationCounts, onSave: handleSave, onDelete: handleDelete, handleImport: handleImport }));
|
|
25
41
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
|
|
1
|
+
import { AddAuthorIcon, Category, CitationCountIcon, CloseButton, Dialog, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, useScrollDetection, withListNavigation, withNavigableListItem, } from '@manuscripts/style-guide';
|
|
2
2
|
import isEqual from 'lodash/isEqual';
|
|
3
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
import { ReferenceForm, } from './ReferenceForm/ReferenceForm';
|
|
6
6
|
import { ReferenceLine } from './ReferenceLine';
|
|
7
|
+
import { ImportBibliographyModal } from './ImportBibliographyModal';
|
|
8
|
+
import { ImportSuccessPlaceholder } from './ImportSuccessPlaceholder';
|
|
7
9
|
const ReferencesModalContainer = styled(ModalContainer) `
|
|
8
10
|
min-width: 960px;
|
|
9
11
|
`;
|
|
@@ -13,6 +15,33 @@ const ReferencesSidebar = styled(ModalSidebar) `
|
|
|
13
15
|
const ReferencesSidebarContent = styled(SidebarContent) `
|
|
14
16
|
overflow-y: auto;
|
|
15
17
|
`;
|
|
18
|
+
const ImportFromFileFooter = styled.div `
|
|
19
|
+
padding: 16px;
|
|
20
|
+
`;
|
|
21
|
+
const ImportFromFileButton = styled.button `
|
|
22
|
+
display: flex;
|
|
23
|
+
width: 100%;
|
|
24
|
+
padding: 8px 24px;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 8px;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
border: 1px dashed #c9c9c9;
|
|
30
|
+
background: #fafafa;
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
font-family: ${(props) => props.theme.font.family.sans};
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
color: #353535;
|
|
35
|
+
|
|
36
|
+
svg {
|
|
37
|
+
width: 20px;
|
|
38
|
+
height: 20px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
svg rect {
|
|
42
|
+
fill: #6e6e6e;
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
16
45
|
const ReferencesInnerWrapper = withListNavigation(styled.div `
|
|
17
46
|
width: 100%;
|
|
18
47
|
padding: 12px 0;
|
|
@@ -100,15 +129,25 @@ const normalize = (item) => ({
|
|
|
100
129
|
accessed: item.accessed,
|
|
101
130
|
comment: item.comment || '',
|
|
102
131
|
});
|
|
103
|
-
export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave, onDelete, }) => {
|
|
132
|
+
export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts, onSave, onDelete, handleImport, }) => {
|
|
133
|
+
const [importing, setImporting] = useState(false);
|
|
134
|
+
const [importSuccessCount, setImportSuccessCount] = useState(null);
|
|
104
135
|
const [confirm, setConfirm] = useState(false);
|
|
105
136
|
const valuesRef = useRef(undefined);
|
|
106
137
|
const [selection, setSelection] = useState();
|
|
107
138
|
const selectionRef = useRef(null);
|
|
139
|
+
const sortedItems = useMemo(() => [...items].sort((a, b) => {
|
|
140
|
+
const aUncited = (citationCounts.get(a.id) ?? 0) === 0;
|
|
141
|
+
const bUncited = (citationCounts.get(b.id) ?? 0) === 0;
|
|
142
|
+
if (aUncited === bUncited) {
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
return aUncited ? 1 : -1;
|
|
146
|
+
}), [items, citationCounts]);
|
|
108
147
|
const isSelected = (item) => {
|
|
109
148
|
return item.id === selection?.id;
|
|
110
149
|
};
|
|
111
|
-
const selectionIndex =
|
|
150
|
+
const selectionIndex = sortedItems.findIndex(isSelected);
|
|
112
151
|
useEffect(() => {
|
|
113
152
|
setSelection(item);
|
|
114
153
|
}, [item]);
|
|
@@ -126,8 +165,8 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
|
|
|
126
165
|
useEffect(() => {
|
|
127
166
|
const base = Math.max(0, selectionIndex - selectionTopOffset);
|
|
128
167
|
setStartIndex(base);
|
|
129
|
-
setEndIndex(Math.min(
|
|
130
|
-
}, [selectionIndex,
|
|
168
|
+
setEndIndex(Math.min(sortedItems.length - 1, base + pageSize));
|
|
169
|
+
}, [selectionIndex, sortedItems]);
|
|
131
170
|
useEffect(() => {
|
|
132
171
|
if (triggers.top) {
|
|
133
172
|
const newFirst = Math.max(0, startIndex - pageSize);
|
|
@@ -135,11 +174,11 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
|
|
|
135
174
|
setEndIndex(Math.min(newFirst + dropLimit, endIndex));
|
|
136
175
|
}
|
|
137
176
|
if (triggers.bottom) {
|
|
138
|
-
const newLast = Math.min(
|
|
177
|
+
const newLast = Math.min(sortedItems.length - 1, endIndex + pageSize);
|
|
139
178
|
setEndIndex(newLast);
|
|
140
179
|
setStartIndex(Math.max(newLast - dropLimit, startIndex));
|
|
141
180
|
}
|
|
142
|
-
}, [triggers,
|
|
181
|
+
}, [triggers, sortedItems]);
|
|
143
182
|
const actionsRef = useRef(undefined);
|
|
144
183
|
const reset = () => {
|
|
145
184
|
actionsRef.current?.reset();
|
|
@@ -173,7 +212,9 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
|
|
|
173
212
|
onDelete(selection);
|
|
174
213
|
setSelection(undefined);
|
|
175
214
|
};
|
|
215
|
+
const clearImportSuccess = () => setImportSuccessCount(null);
|
|
176
216
|
const handleItemClick = (item) => {
|
|
217
|
+
clearImportSuccess();
|
|
177
218
|
const values = valuesRef.current;
|
|
178
219
|
if (values && selection && !isEqual(values, normalize(selection))) {
|
|
179
220
|
setConfirm(true);
|
|
@@ -184,33 +225,45 @@ export const ReferencesModal = ({ isOpen, onCancel, items, item, citationCounts,
|
|
|
184
225
|
const handleChange = (values) => {
|
|
185
226
|
valuesRef.current = values;
|
|
186
227
|
};
|
|
187
|
-
|
|
228
|
+
const handleImportSave = (data) => {
|
|
229
|
+
handleImport(data);
|
|
230
|
+
setImporting(false);
|
|
231
|
+
setSelection(undefined);
|
|
232
|
+
setImportSuccessCount(data.length);
|
|
233
|
+
};
|
|
234
|
+
if (sortedItems.length <= 0) {
|
|
188
235
|
return React.createElement(React.Fragment, null);
|
|
189
236
|
}
|
|
190
|
-
return (React.createElement(
|
|
191
|
-
React.createElement(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
237
|
+
return (React.createElement(React.Fragment, null,
|
|
238
|
+
importing && (React.createElement(ImportBibliographyModal, { onCancel: () => setImporting(false), onSave: handleImportSave })),
|
|
239
|
+
React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: onCancel },
|
|
240
|
+
React.createElement(Dialog, { isOpen: confirm, category: Category.confirmation, header: "You've made changes to this option", message: "Would you like to save or discard your changes?", actions: {
|
|
241
|
+
secondary: {
|
|
242
|
+
action: () => reset(),
|
|
243
|
+
title: 'Discard',
|
|
244
|
+
},
|
|
245
|
+
primary: {
|
|
246
|
+
action: () => handleSave(valuesRef.current),
|
|
247
|
+
title: 'Save',
|
|
248
|
+
},
|
|
249
|
+
} }),
|
|
250
|
+
React.createElement(ReferencesModalContainer, { "data-cy": 'references-editor' },
|
|
251
|
+
React.createElement(ModalHeader, null,
|
|
252
|
+
React.createElement(CloseButton, { "data-cy": "modal-close-button", onClick: onCancel })),
|
|
253
|
+
React.createElement(ModalBody, null,
|
|
254
|
+
React.createElement(ReferencesSidebar, null,
|
|
255
|
+
React.createElement(ModalSidebarHeader, null,
|
|
256
|
+
React.createElement(ModalSidebarTitle, null, "References")),
|
|
257
|
+
React.createElement(ReferencesSidebarContent, { ref: ref },
|
|
258
|
+
React.createElement(ReferencesInnerWrapper, null, sortedItems.slice(startIndex, endIndex + 1).map((item) => (React.createElement(ReferenceButton, { key: item.id, id: item.id, className: isSelected(item) ? 'selected' : '', onClick: () => handleItemClick(item), ref: isSelected(item) ? selectionRef : null },
|
|
259
|
+
React.createElement(IconContainer, null,
|
|
260
|
+
React.createElement(CitationCountIcon, null),
|
|
261
|
+
(citationCounts.get(item.id) || 0) > 0 ? (React.createElement(CitationCount, { "data-tooltip-content": "Number of times used in the document" }, citationCounts.get(item.id))) : (React.createElement(CitationCount, { className: "unused" }, "0"))),
|
|
262
|
+
React.createElement(ReferenceLine, { item: item })))))),
|
|
263
|
+
React.createElement(ImportFromFileFooter, null,
|
|
264
|
+
React.createElement(ImportFromFileButton, { type: "button", "data-cy": "import-from-file-button", onClick: () => setImporting(true) },
|
|
265
|
+
React.createElement(AddAuthorIcon, null),
|
|
266
|
+
"Import from file"))),
|
|
267
|
+
React.createElement(ScrollableModalContent, null, importSuccessCount !== null ? (React.createElement(ImportSuccessPlaceholder, { count: importSuccessCount })) : (selection && (React.createElement(ReferenceForm, { values: normalize(selection), showDelete: !citationCounts.get(selection.id) &&
|
|
268
|
+
isNewItem(selection, ['id', 'type']), onChange: handleChange, onCancel: onCancel, onDelete: handleDelete, onSave: handleSave, actionsRef: actionsRef })))))))));
|
|
216
269
|
};
|
package/dist/es/lib/view.js
CHANGED
|
@@ -64,3 +64,39 @@ export const deleteNode = (view, id) => {
|
|
|
64
64
|
view.dispatch(view.state.tr.delete(pos, pos + node.nodeSize));
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
|
+
const createBibliographySection = (nodes) => schema.nodes.bibliography_section.createAndFill({}, [
|
|
68
|
+
schema.nodes.section_title.create({}, schema.text('References')),
|
|
69
|
+
schema.nodes.bibliography_element.create({}, nodes),
|
|
70
|
+
]);
|
|
71
|
+
export const insertBibliographyItems = (view, items) => {
|
|
72
|
+
const { doc } = view.state;
|
|
73
|
+
let tr = view.state.tr;
|
|
74
|
+
const biblioSection = utils.findChildrenByType(doc, schema.nodes.bibliography_element, true);
|
|
75
|
+
if (biblioSection.length) {
|
|
76
|
+
let insertPos = biblioSection[0].pos + 1;
|
|
77
|
+
for (const attrs of items) {
|
|
78
|
+
const node = schema.nodes.bibliography_item.create(attrs);
|
|
79
|
+
tr = tr.insert(insertPos, node);
|
|
80
|
+
insertPos += node.nodeSize;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const backmatter = utils.findChildrenByType(doc, schema.nodes.backmatter, true);
|
|
85
|
+
const backmatterEnd = backmatter[0]
|
|
86
|
+
? backmatter[0].node.nodeSize + backmatter[0].pos
|
|
87
|
+
: 0;
|
|
88
|
+
const nodes = items.map((attrs) => schema.nodes.bibliography_item.create(attrs));
|
|
89
|
+
tr = tr.insert(backmatterEnd ? backmatterEnd - 1 : tr.doc.content.size, createBibliographySection(nodes));
|
|
90
|
+
}
|
|
91
|
+
view.dispatch(tr);
|
|
92
|
+
};
|
|
93
|
+
export const saveBibliographyItem = (view, attrs) => {
|
|
94
|
+
if (attrs.length === 1) {
|
|
95
|
+
const item = attrs[0];
|
|
96
|
+
if (findChildByID(view, item.id)) {
|
|
97
|
+
updateNodeAttrs(view, schema.nodes.bibliography_item, item);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
insertBibliographyItems(view, attrs);
|
|
102
|
+
};
|
package/dist/es/versions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '3.16.
|
|
1
|
+
export const VERSION = '3.16.2';
|
|
2
2
|
export const MATHJAX_VERSION = '3.2.2';
|
|
@@ -14,14 +14,13 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { ContextMenu } from '@manuscripts/style-guide';
|
|
17
|
-
import { schema, } from '@manuscripts/transform';
|
|
18
17
|
import { NodeSelection } from 'prosemirror-state';
|
|
19
18
|
import { ReferencesEditor, } from '../components/references/ReferencesEditor';
|
|
20
19
|
import { createCommentMarker, handleComment } from '../lib/comments';
|
|
21
20
|
import { handleEnterKey } from '../lib/navigation-utils';
|
|
22
21
|
import { findNodeByID } from '../lib/doc';
|
|
23
22
|
import { sanitize } from '../lib/dompurify';
|
|
24
|
-
import { deleteNode, findChildByID,
|
|
23
|
+
import { deleteNode, findChildByID, saveBibliographyItem } from '../lib/view';
|
|
25
24
|
import { getBibliographyPluginState } from '../plugins/bibliography';
|
|
26
25
|
import { commentsKey, setCommentSelection } from '../plugins/comments';
|
|
27
26
|
import { selectedSuggestionKey } from '../plugins/selected-suggestion';
|
|
@@ -86,7 +85,7 @@ export class BibliographyElementBlockView extends BlockView {
|
|
|
86
85
|
this.dom.appendChild(this.container);
|
|
87
86
|
};
|
|
88
87
|
this.handleSave = (attrs) => {
|
|
89
|
-
|
|
88
|
+
saveBibliographyItem(this.view, attrs);
|
|
90
89
|
};
|
|
91
90
|
this.handleDelete = (item) => {
|
|
92
91
|
deleteNode(this.view, item.id);
|
|
@@ -15,23 +15,17 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { ContextMenu } from '@manuscripts/style-guide';
|
|
17
17
|
import { isDeleted } from '@manuscripts/track-changes-plugin';
|
|
18
|
-
import { schema, } from '@manuscripts/transform';
|
|
19
18
|
import { TextSelection } from 'prosemirror-state';
|
|
20
|
-
import { findChildrenByType } from 'prosemirror-utils';
|
|
21
19
|
import { CitationEditor, } from '../components/references/CitationEditor';
|
|
22
20
|
import { CitationViewer, } from '../components/references/CitationViewer';
|
|
23
21
|
import { handleComment } from '../lib/comments';
|
|
24
22
|
import { Crossref } from '../lib/crossref';
|
|
25
23
|
import { handleEnterKey } from '../lib/navigation-utils';
|
|
26
|
-
import { deleteNode,
|
|
24
|
+
import { deleteNode, saveBibliographyItem } from '../lib/view';
|
|
27
25
|
import { getBibliographyPluginState } from '../plugins/bibliography';
|
|
28
26
|
import { CitationView } from './citation';
|
|
29
27
|
import { createEditableNodeView } from './creators';
|
|
30
28
|
import ReactSubView from './ReactSubView';
|
|
31
|
-
const createBibliographySection = (node) => schema.nodes.bibliography_section.createAndFill({}, [
|
|
32
|
-
schema.nodes.section_title.create({}, schema.text('References')),
|
|
33
|
-
schema.nodes.bibliography_element.create({}, node ? [node] : []),
|
|
34
|
-
]);
|
|
35
29
|
export class CitationEditableView extends CitationView {
|
|
36
30
|
constructor() {
|
|
37
31
|
super(...arguments);
|
|
@@ -137,12 +131,7 @@ export class CitationEditableView extends CitationView {
|
|
|
137
131
|
this.props.popper.destroy();
|
|
138
132
|
};
|
|
139
133
|
this.handleSave = (attrs) => {
|
|
140
|
-
|
|
141
|
-
this.insertBibliographyNode(attrs);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
updateNodeAttrs(this.view, schema.nodes.bibliography_item, attrs);
|
|
145
|
-
}
|
|
134
|
+
saveBibliographyItem(this.view, attrs);
|
|
146
135
|
};
|
|
147
136
|
this.handleUncite = (id) => {
|
|
148
137
|
const attrs = this.node.attrs;
|
|
@@ -175,7 +164,7 @@ export class CitationEditableView extends CitationView {
|
|
|
175
164
|
item.id = existingItem.id;
|
|
176
165
|
}
|
|
177
166
|
else {
|
|
178
|
-
this.
|
|
167
|
+
saveBibliographyItem(this.view, [item]);
|
|
179
168
|
}
|
|
180
169
|
rids.push(item.id);
|
|
181
170
|
}
|
|
@@ -194,21 +183,5 @@ export class CitationEditableView extends CitationView {
|
|
|
194
183
|
this.dom.addEventListener('mouseup', () => this.handleClick(false));
|
|
195
184
|
this.dom.addEventListener('keydown', handleEnterKey(() => this.handleClick(true)));
|
|
196
185
|
}
|
|
197
|
-
insertBibliographyNode(attrs) {
|
|
198
|
-
const { doc, tr } = this.view.state;
|
|
199
|
-
const biblioSection = findChildrenByType(doc, schema.nodes.bibliography_element, true);
|
|
200
|
-
const backmatter = findChildrenByType(doc, schema.nodes.backmatter, true);
|
|
201
|
-
const backmatterEnd = backmatter[0]
|
|
202
|
-
? backmatter[0].node.nodeSize + backmatter[0].pos
|
|
203
|
-
: 0;
|
|
204
|
-
const node = schema.nodes.bibliography_item.create(attrs);
|
|
205
|
-
if (biblioSection.length) {
|
|
206
|
-
this.view.dispatch(tr.insert(biblioSection[0].pos + 1, node));
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
this.view.dispatch(tr.insert(backmatterEnd ? backmatterEnd - 1 : tr.doc.content.size, createBibliographySection(node)));
|
|
210
|
-
}
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
186
|
}
|
|
214
187
|
export default createEditableNodeView(CitationEditableView);
|
|
@@ -9,7 +9,7 @@ export interface CitationEditorProps {
|
|
|
9
9
|
sources: BibliographyItemSource[];
|
|
10
10
|
onCite: (items: BibliographyItemAttrs[]) => void;
|
|
11
11
|
onUncite: (id: string) => void;
|
|
12
|
-
onSave: (item: BibliographyItemAttrs) => void;
|
|
12
|
+
onSave: (item: BibliographyItemAttrs[]) => void;
|
|
13
13
|
onDelete: (item: BibliographyItemAttrs) => void;
|
|
14
14
|
onCancel: () => void;
|
|
15
15
|
canEdit: boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BibliographyItemAttrs } from '@manuscripts/transform';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface ImportBibliographyProps {
|
|
4
|
+
onCancel: () => void;
|
|
5
|
+
onContinue: (data: BibliographyItemAttrs[]) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const ImportBibliography: React.FC<ImportBibliographyProps>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BibliographyItemAttrs } from '@manuscripts/transform';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface ImportReferencesConfirmationProps {
|
|
4
|
+
items: BibliographyItemAttrs[];
|
|
5
|
+
onCancel: () => void;
|
|
6
|
+
onConfirm: (items: BibliographyItemAttrs[]) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const ImportReferencesConfirmation: React.FC<ImportReferencesConfirmationProps>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { BibliographyItemAttrs } from '@manuscripts/transform';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { ReferencesModalProps } from './ReferencesModal';
|
|
3
|
-
export type ReferencesEditorProps = Omit<ReferencesModalProps, 'isOpen' | 'onCancel'
|
|
4
|
+
export type ReferencesEditorProps = Omit<ReferencesModalProps, 'isOpen' | 'onCancel' | 'handleImport' | 'onSave'> & {
|
|
5
|
+
onSave: (item: BibliographyItemAttrs[]) => void;
|
|
6
|
+
};
|
|
4
7
|
export declare const ReferencesEditor: React.FC<ReferencesEditorProps>;
|
|
@@ -8,5 +8,6 @@ export interface ReferencesModalProps {
|
|
|
8
8
|
citationCounts: Map<string, number>;
|
|
9
9
|
onSave: (item: BibliographyItemAttrs) => void;
|
|
10
10
|
onDelete: (item: BibliographyItemAttrs) => void;
|
|
11
|
+
handleImport: (data: BibliographyItemAttrs[]) => void;
|
|
11
12
|
}
|
|
12
13
|
export declare const ReferencesModal: React.FC<ReferencesModalProps>;
|
package/dist/types/lib/view.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { ManuscriptEditorView, ManuscriptNodeType } from '@manuscripts/transform';
|
|
16
|
+
import { BibliographyItemAttrs, ManuscriptEditorView, ManuscriptNodeType } from '@manuscripts/transform';
|
|
17
17
|
import { Attrs } from 'prosemirror-model';
|
|
18
18
|
import * as utils from 'prosemirror-utils';
|
|
19
19
|
export declare const findChildByID: (view: ManuscriptEditorView, id: string) => utils.NodeWithPos | undefined;
|
|
@@ -22,3 +22,5 @@ export declare const findChildrenByType: (view: ManuscriptEditorView, type: Manu
|
|
|
22
22
|
export declare const findChildrenAttrsByType: <T extends Attrs>(view: ManuscriptEditorView, type: ManuscriptNodeType) => T[];
|
|
23
23
|
export declare const updateNodeAttrs: (view: ManuscriptEditorView, type: ManuscriptNodeType, attrs: Attrs) => boolean;
|
|
24
24
|
export declare const deleteNode: (view: ManuscriptEditorView, id: string) => void;
|
|
25
|
+
export declare const insertBibliographyItems: (view: ManuscriptEditorView, items: BibliographyItemAttrs[]) => void;
|
|
26
|
+
export declare const saveBibliographyItem: (view: ManuscriptEditorView, attrs: BibliographyItemAttrs[]) => void;
|
package/dist/types/versions.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "3.16.
|
|
1
|
+
export declare const VERSION = "3.16.2";
|
|
2
2
|
export declare const MATHJAX_VERSION = "3.2.2";
|
|
@@ -31,7 +31,6 @@ export declare class CitationEditableView extends CitationView {
|
|
|
31
31
|
private handleUncite;
|
|
32
32
|
private handleCite;
|
|
33
33
|
private handleDelete;
|
|
34
|
-
private insertBibliographyNode;
|
|
35
34
|
}
|
|
36
35
|
declare const _default: (props: import("../configs/ManuscriptsEditor").EditorProps, dispatch?: import("..").Dispatch) => import("../types").NodeViewCreator<CitationEditableView>;
|
|
37
36
|
export default _default;
|
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": "3.16.
|
|
4
|
+
"version": "3.16.2",
|
|
5
5
|
"repository": "github:Atypon-OpenSource/manuscripts-body-editor",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/cjs",
|