@eeacms/volto-slate-footnote 7.0.0 → 7.1.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.
- package/CHANGELOG.md +16 -1
- package/package.json +2 -1
- package/src/Blocks/Footnote/FootnotesBlockView.jsx +34 -6
- package/src/editor/render.jsx +57 -45
- package/src/editor/utils.js +8 -9
- package/src/editor/utils.test.js +0 -14
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,22 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
-
### [7.
|
|
7
|
+
### [7.1.0](https://github.com/eea/volto-slate-footnote/compare/7.0.1...7.1.0) - 13 September 2024
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: autodetect links and use universal link - refs #274052 [dobri1408 - [`9c13101`](https://github.com/eea/volto-slate-footnote/commit/9c13101b62b1df150e1b3dbb93807df60a074ad5)]
|
|
12
|
+
|
|
13
|
+
#### :hammer_and_wrench: Others
|
|
14
|
+
|
|
15
|
+
- Release 7.1.0 [alin - [`c15afb0`](https://github.com/eea/volto-slate-footnote/commit/c15afb0be79ba9c4e3a46e3c190a41db468e88cd)]
|
|
16
|
+
### [7.0.1](https://github.com/eea/volto-slate-footnote/compare/7.0.0...7.0.1) - 23 August 2024
|
|
17
|
+
|
|
18
|
+
#### :hammer_and_wrench: Others
|
|
19
|
+
|
|
20
|
+
- test: Fix tests on Volto 16 [Alin Voinea - [`1de9cc0`](https://github.com/eea/volto-slate-footnote/commit/1de9cc0dc69f1e6316654c149e7e9c0912f27749)]
|
|
21
|
+
- Squashed commit of the following: [Alin Voinea - [`207a2d3`](https://github.com/eea/volto-slate-footnote/commit/207a2d3be243d8ff60e64dfe627c7b32443ea222)]
|
|
22
|
+
## [7.0.0](https://github.com/eea/volto-slate-footnote/compare/6.3.0...7.0.0) - 22 April 2024
|
|
8
23
|
|
|
9
24
|
#### :rocket: New Features
|
|
10
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-slate-footnote",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "volto-slate-footnote: Volto add-on",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"@cypress/code-coverage": "^3.10.0",
|
|
24
24
|
"@plone/scripts": "*",
|
|
25
25
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
|
26
|
+
"cypress": "13.1.0",
|
|
26
27
|
"dotenv": "^16.3.2",
|
|
27
28
|
"husky": "^8.0.3",
|
|
28
29
|
"lint-staged": "^14.0.1",
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
openAccordionOrTabIfContainsFootnoteReference,
|
|
4
4
|
getAllBlocksAndSlateFields,
|
|
5
5
|
makeFootnoteListOfUniqueItems,
|
|
6
|
-
makeFootnote,
|
|
7
6
|
} from '@eeacms/volto-slate-footnote/editor/utils';
|
|
8
7
|
import './less/public.less';
|
|
9
8
|
|
|
10
9
|
import { UniversalLink } from '@plone/volto/components';
|
|
11
10
|
|
|
12
11
|
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
|
12
|
+
const urlRegex = /https?:\/\/[^\s]+/g;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @summary The React component that displays the list of footnotes inserted
|
|
@@ -19,6 +19,7 @@ const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
|
|
19
19
|
* @param {Object} props Contains the properties `data` and `properties` as
|
|
20
20
|
* received from the Volto form.
|
|
21
21
|
*/
|
|
22
|
+
|
|
22
23
|
const FootnotesBlockView = (props) => {
|
|
23
24
|
const { data, properties, tabData, content } = props;
|
|
24
25
|
const { title, global, placeholder = 'Footnotes' } = data;
|
|
@@ -75,6 +76,30 @@ const FootnotesBlockView = (props) => {
|
|
|
75
76
|
startList = citationIndice;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
const renderTextWithLinks = (text) => {
|
|
80
|
+
if (!text) return null;
|
|
81
|
+
const parts = text.split(urlRegex);
|
|
82
|
+
const links = text.match(urlRegex);
|
|
83
|
+
let result = [];
|
|
84
|
+
|
|
85
|
+
parts.forEach((part, index) => {
|
|
86
|
+
result.push(<span key={`text-${index}`}>{part}</span>);
|
|
87
|
+
|
|
88
|
+
if (links && links[index]) {
|
|
89
|
+
result.push(
|
|
90
|
+
<UniversalLink
|
|
91
|
+
key={`link-${index}`}
|
|
92
|
+
href={links[index]}
|
|
93
|
+
openLinkInNewTab={false}
|
|
94
|
+
>
|
|
95
|
+
{links[index]}
|
|
96
|
+
</UniversalLink>,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
};
|
|
78
103
|
return (
|
|
79
104
|
<div className="footnotes-listing-block">
|
|
80
105
|
<h3 title={placeholder}>{title}</h3>
|
|
@@ -85,16 +110,19 @@ const FootnotesBlockView = (props) => {
|
|
|
85
110
|
const { uid, footnote, zoteroId, parentUid } = note;
|
|
86
111
|
const { refs } = note;
|
|
87
112
|
const refsList = refs ? Object.keys(refs) : null;
|
|
113
|
+
|
|
114
|
+
// const history = createBrowserHistory();
|
|
115
|
+
// const api = new Api();
|
|
116
|
+
// const store = configureStore(window.__data, history, api);
|
|
117
|
+
const footnoteText = !footnote
|
|
118
|
+
? ''
|
|
119
|
+
: footnote.replace('<?xml version="1.0"?>', '');
|
|
88
120
|
return (
|
|
89
121
|
<li
|
|
90
122
|
key={`footnote-${zoteroId || uid}`}
|
|
91
123
|
id={`footnote-${zoteroId || uid}`}
|
|
92
124
|
>
|
|
93
|
-
<div
|
|
94
|
-
dangerouslySetInnerHTML={{
|
|
95
|
-
__html: makeFootnote(footnote),
|
|
96
|
-
}}
|
|
97
|
-
/>
|
|
125
|
+
<div>{renderTextWithLinks(footnoteText)}</div>
|
|
98
126
|
{refsList ? (
|
|
99
127
|
<>
|
|
100
128
|
{/** some footnotes are never parent so we need the parent to reference */}
|
package/src/editor/render.jsx
CHANGED
|
@@ -15,9 +15,8 @@ import { UniversalLink } from '@plone/volto/components';
|
|
|
15
15
|
* @param {string} footnote
|
|
16
16
|
* @returns {string} formatted footnote
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
18
|
+
|
|
19
|
+
const urlRegex = /https?:\/\/[^\s]+/g;
|
|
21
20
|
|
|
22
21
|
export const FootnoteElement = (props) => {
|
|
23
22
|
const { attributes, children, element, mode, extras } = props;
|
|
@@ -37,7 +36,7 @@ export const FootnoteElement = (props) => {
|
|
|
37
36
|
const notesObjResult = isEmpty(metadata)
|
|
38
37
|
? makeFootnoteListOfUniqueItems(storeBlocks)
|
|
39
38
|
: makeFootnoteListOfUniqueItems(blocks);
|
|
40
|
-
// will
|
|
39
|
+
// will consider zotero citations and footnote
|
|
41
40
|
// notesObjResult contains all zotero/footnote as unique, and contain refs for other zotero/footnote
|
|
42
41
|
const indiceIfZoteroId = data.extra
|
|
43
42
|
? [
|
|
@@ -52,6 +51,29 @@ export const FootnoteElement = (props) => {
|
|
|
52
51
|
: // no extra citations (no multiples)
|
|
53
52
|
`[${Object.keys(notesObjResult).indexOf(zoteroId) + 1}]`;
|
|
54
53
|
|
|
54
|
+
const renderTextWithLinks = (text) => {
|
|
55
|
+
if (!text) return null;
|
|
56
|
+
const parts = text.split(urlRegex);
|
|
57
|
+
const links = text.match(urlRegex);
|
|
58
|
+
let result = [];
|
|
59
|
+
|
|
60
|
+
parts.forEach((part, index) => {
|
|
61
|
+
result.push(<span key={`text-${index}`}>{part}</span>);
|
|
62
|
+
if (links && links[index]) {
|
|
63
|
+
result.push(
|
|
64
|
+
<UniversalLink
|
|
65
|
+
key={`link-${index}`}
|
|
66
|
+
href={links[index]}
|
|
67
|
+
openLinkInNewTab={false}
|
|
68
|
+
>
|
|
69
|
+
{links[index]}
|
|
70
|
+
</UniversalLink>,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
};
|
|
55
77
|
const citationIndice = zoteroId // ZOTERO
|
|
56
78
|
? indiceIfZoteroId
|
|
57
79
|
: // FOOTNOTES
|
|
@@ -76,13 +98,17 @@ export const FootnoteElement = (props) => {
|
|
|
76
98
|
Object.keys(notesObjResult).find(
|
|
77
99
|
(noteKey) => notesObjResult[noteKey].uid === uid,
|
|
78
100
|
) ||
|
|
79
|
-
// if not found in parent, search in refs, it might be a footnote
|
|
101
|
+
// if not found in parent, search in refs, it might be a footnote referenced multiple times
|
|
80
102
|
Object.keys(notesObjResult).find(
|
|
81
103
|
(noteKey) =>
|
|
82
104
|
notesObjResult[noteKey].uid === uid ||
|
|
83
105
|
(notesObjResult[noteKey].refs && notesObjResult[noteKey].refs[uid]),
|
|
84
106
|
);
|
|
85
107
|
|
|
108
|
+
const footnoteText = !data.footnote
|
|
109
|
+
? ''
|
|
110
|
+
: data.footnote.replace('<?xml version="1.0"?>', '');
|
|
111
|
+
|
|
86
112
|
return (
|
|
87
113
|
<>
|
|
88
114
|
{mode === 'view' ? (
|
|
@@ -109,7 +135,6 @@ export const FootnoteElement = (props) => {
|
|
|
109
135
|
<Popup.Content>
|
|
110
136
|
<List divided relaxed selection>
|
|
111
137
|
<List.Item
|
|
112
|
-
as={UniversalLink}
|
|
113
138
|
href={`#footnote-${citationRefId}`}
|
|
114
139
|
onClick={() =>
|
|
115
140
|
openAccordionOrTabIfContainsFootnoteReference(
|
|
@@ -120,37 +145,34 @@ export const FootnoteElement = (props) => {
|
|
|
120
145
|
>
|
|
121
146
|
<List.Content>
|
|
122
147
|
<List.Description>
|
|
123
|
-
|
|
124
|
-
dangerouslySetInnerHTML={{
|
|
125
|
-
__html: makeFootnote(data.footnote),
|
|
126
|
-
}}
|
|
127
|
-
/>{' '}
|
|
148
|
+
{renderTextWithLinks(footnoteText)}
|
|
128
149
|
</List.Description>
|
|
129
150
|
</List.Content>
|
|
130
151
|
</List.Item>
|
|
131
152
|
{data.extra &&
|
|
132
|
-
data.extra.map((item) =>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
data.extra.map((item) => {
|
|
154
|
+
const footnoteText = !item.footnote
|
|
155
|
+
? ''
|
|
156
|
+
: item.footnote.replace('<?xml version="1.0"?>', '');
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<List.Item
|
|
160
|
+
href={`#footnote-${item.zoteroId || item.uid}`}
|
|
161
|
+
onClick={() =>
|
|
162
|
+
openAccordionOrTabIfContainsFootnoteReference(
|
|
163
|
+
`#footnote-${item.zoteroId || item.uid}`,
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
key={`#footnote-${item.zoteroId || item.uid}`}
|
|
167
|
+
>
|
|
168
|
+
<List.Content>
|
|
169
|
+
<List.Description>
|
|
170
|
+
{renderTextWithLinks(footnoteText)}
|
|
171
|
+
</List.Description>
|
|
172
|
+
</List.Content>
|
|
173
|
+
</List.Item>
|
|
174
|
+
);
|
|
175
|
+
})}
|
|
154
176
|
</List>
|
|
155
177
|
</Popup.Content>
|
|
156
178
|
</Popup>
|
|
@@ -173,7 +195,6 @@ export const FootnoteElement = (props) => {
|
|
|
173
195
|
<Popup.Content>
|
|
174
196
|
<List divided relaxed selection>
|
|
175
197
|
<List.Item
|
|
176
|
-
as={UniversalLink}
|
|
177
198
|
href={`#footnote-${citationRefId}`}
|
|
178
199
|
onClick={() =>
|
|
179
200
|
openAccordionOrTabIfContainsFootnoteReference(
|
|
@@ -184,18 +205,13 @@ export const FootnoteElement = (props) => {
|
|
|
184
205
|
>
|
|
185
206
|
<List.Content>
|
|
186
207
|
<List.Description>
|
|
187
|
-
|
|
188
|
-
dangerouslySetInnerHTML={{
|
|
189
|
-
__html: makeFootnote(data.footnote),
|
|
190
|
-
}}
|
|
191
|
-
/>{' '}
|
|
208
|
+
{renderTextWithLinks(footnoteText)}
|
|
192
209
|
</List.Description>
|
|
193
210
|
</List.Content>
|
|
194
211
|
</List.Item>
|
|
195
212
|
{data.extra &&
|
|
196
213
|
data.extra.map((item) => (
|
|
197
214
|
<List.Item
|
|
198
|
-
as={UniversalLink}
|
|
199
215
|
href={`#footnote-${item.zoteroId || item.uid}`}
|
|
200
216
|
onClick={() =>
|
|
201
217
|
openAccordionOrTabIfContainsFootnoteReference(
|
|
@@ -206,11 +222,7 @@ export const FootnoteElement = (props) => {
|
|
|
206
222
|
>
|
|
207
223
|
<List.Content>
|
|
208
224
|
<List.Description>
|
|
209
|
-
|
|
210
|
-
dangerouslySetInnerHTML={{
|
|
211
|
-
__html: makeFootnote(item.footnote),
|
|
212
|
-
}}
|
|
213
|
-
/>{' '}
|
|
225
|
+
{renderTextWithLinks(item.footnote)}
|
|
214
226
|
</List.Description>
|
|
215
227
|
</List.Content>
|
|
216
228
|
</List.Item>
|
package/src/editor/utils.js
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import config from '@plone/volto/registry';
|
|
2
2
|
import { Node } from 'slate';
|
|
3
3
|
import { getAllBlocks } from '@plone/volto-slate/utils';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* remove <?xml version="1.0"?> from the string
|
|
7
|
-
* @param {*} footnote - xml format
|
|
8
|
-
* @returns string
|
|
9
|
-
*/
|
|
10
|
-
export const makeFootnote = (footnote) => {
|
|
11
|
-
return footnote ? footnote.replace('<?xml version="1.0"?>', '') : '';
|
|
12
|
-
};
|
|
13
4
|
/**
|
|
14
5
|
* retrive all slate children of nested objects
|
|
15
6
|
* @param {object} path - the keys that we want to extract the slate children from
|
|
@@ -79,6 +70,14 @@ export const openAccordionOrTabIfContainsFootnoteReference = (footnoteId) => {
|
|
|
79
70
|
return true;
|
|
80
71
|
};
|
|
81
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Will open accordion if contains footnote reference
|
|
75
|
+
* @param {string} footnoteId
|
|
76
|
+
* @deprecated This function got renamed to {@link openAccordionOrTabIfContainsFootnoteReference}
|
|
77
|
+
*/
|
|
78
|
+
export const openAccordionIfContainsFootnoteReference =
|
|
79
|
+
openAccordionOrTabIfContainsFootnoteReference;
|
|
80
|
+
|
|
82
81
|
const blockTypesOperations = {
|
|
83
82
|
metadataSection: (block, properties) => {
|
|
84
83
|
const fields = block?.fields || [];
|
package/src/editor/utils.test.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
makeFootnote,
|
|
3
2
|
openAccordionOrTabIfContainsFootnoteReference,
|
|
4
3
|
getAllBlocksAndSlateFields,
|
|
5
4
|
} from './utils';
|
|
@@ -9,19 +8,6 @@ jest.mock('@plone/volto-slate/utils', () => ({
|
|
|
9
8
|
getAllBlocks: jest.fn(),
|
|
10
9
|
}));
|
|
11
10
|
|
|
12
|
-
describe('makeFootnote', () => {
|
|
13
|
-
it('should remove xml version string from footnote', () => {
|
|
14
|
-
const xmlString = '<?xml version="1.0"?>Test text';
|
|
15
|
-
const expectedResult = 'Test text';
|
|
16
|
-
expect(makeFootnote(xmlString)).toEqual(expectedResult);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should return empty string when footnote is null or undefined', () => {
|
|
20
|
-
expect(makeFootnote(null)).toEqual('');
|
|
21
|
-
expect(makeFootnote(undefined)).toEqual('');
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
11
|
describe('openAccordionOrTabIfContainsFootnoteReference', () => {
|
|
26
12
|
it('should open accordion if it contains footnote reference', () => {
|
|
27
13
|
document.body.innerHTML = `
|