@eeacms/volto-slate-footnote 3.2.0 → 4.0.3
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 +30 -5
- package/Jenkinsfile +53 -22
- package/README.md +87 -0
- package/package.json +4 -2
- package/src/Blocks/Footnote/FootnotesBlockView.jsx +24 -3
- package/src/editor/FootnoteEditor.jsx +50 -41
- package/src/editor/MultiSelectSearchWidget.jsx +53 -34
- package/src/editor/render.jsx +26 -86
- package/src/editor/utils.js +93 -42
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,38 @@ 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
|
+
#### [4.0.3](https://github.com/eea/volto-slate-footnote/compare/4.0.2...4.0.3)
|
|
8
|
+
|
|
9
|
+
- Add SonarQube badges [`5d05ecf`](https://github.com/eea/volto-slate-footnote/commit/5d05ecfd933ec64693998d88f6b6c69e3866cb0b)
|
|
10
|
+
- Refs #142010 - Optimize Volto-addons gitflow pipelines [`1081079`](https://github.com/eea/volto-slate-footnote/commit/1081079444f5ac806e9d56765c4ccf0b9e415a73)
|
|
11
|
+
|
|
12
|
+
#### [4.0.2](https://github.com/eea/volto-slate-footnote/compare/4.0.1...4.0.2)
|
|
13
|
+
|
|
14
|
+
> 30 September 2021
|
|
15
|
+
|
|
16
|
+
- Make footnotes aware of Metadata / Metadata section block / Slate Table [`#27`](https://github.com/eea/volto-slate-footnote/pull/27)
|
|
17
|
+
- Multiple citations [`#26`](https://github.com/eea/volto-slate-footnote/pull/26)
|
|
18
|
+
- Remove :asDefault dependency from volto-slate [`13dad5e`](https://github.com/eea/volto-slate-footnote/commit/13dad5ed23043fa7a24682e1ac6addc86632bfe0)
|
|
19
|
+
|
|
20
|
+
#### [4.0.1](https://github.com/eea/volto-slate-footnote/compare/4.0.0...4.0.1)
|
|
21
|
+
|
|
22
|
+
> 29 September 2021
|
|
23
|
+
|
|
24
|
+
- Make footnotes aware of Metadata / Metadata section block (#22) [`#25`](https://github.com/eea/volto-slate-footnote/pull/25)
|
|
25
|
+
- make footnotes aware of Metadata / Metadata section block [`#22`](https://github.com/eea/volto-slate-footnote/pull/22)
|
|
26
|
+
|
|
27
|
+
### [4.0.0](https://github.com/eea/volto-slate-footnote/compare/3.2.0...4.0.0)
|
|
28
|
+
|
|
29
|
+
> 24 September 2021
|
|
30
|
+
|
|
31
|
+
- Release 4.0.0 [`#24`](https://github.com/eea/volto-slate-footnote/pull/24)
|
|
32
|
+
- Use new slate namespaced pluginids [`#23`](https://github.com/eea/volto-slate-footnote/pull/23)
|
|
33
|
+
|
|
7
34
|
#### [3.2.0](https://github.com/eea/volto-slate-footnote/compare/3.1.1...3.2.0)
|
|
8
35
|
|
|
36
|
+
> 13 September 2021
|
|
37
|
+
|
|
38
|
+
- Release Multiple citations (#20) [`#21`](https://github.com/eea/volto-slate-footnote/pull/21)
|
|
9
39
|
- Multiple citations [`#20`](https://github.com/eea/volto-slate-footnote/pull/20)
|
|
10
40
|
- Release 3.2.0 [`6795fcd`](https://github.com/eea/volto-slate-footnote/commit/6795fcd1a4fc429bb70334fbdfa2cb0eedd748fa)
|
|
11
41
|
|
|
@@ -18,7 +48,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
18
48
|
- Remove console.log [`b5d83e7`](https://github.com/eea/volto-slate-footnote/commit/b5d83e7c13240151f602d122ecf09ba9b8e335f3)
|
|
19
49
|
- Fix slate json field default value in DX layout [`f2805bb`](https://github.com/eea/volto-slate-footnote/commit/f2805bbc15c51ebd914ee5f4eb9dd34ef32e095b)
|
|
20
50
|
- Fix cypress api_url [`6a4966a`](https://github.com/eea/volto-slate-footnote/commit/6a4966a2f92e932e1d0df35351989cda535f15c8)
|
|
21
|
-
- Add Sonarqube tag using ims-frontend addons list [`aed3984`](https://github.com/eea/volto-slate-footnote/commit/aed39840ecd467689eaf0adb352bd00ce95bdbbe)
|
|
22
51
|
|
|
23
52
|
#### [3.1.0](https://github.com/eea/volto-slate-footnote/compare/3.0.0...3.1.0)
|
|
24
53
|
|
|
@@ -49,7 +78,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
49
78
|
- Bump version to 2.4.0 [`bef0d34`](https://github.com/eea/volto-slate-footnote/commit/bef0d34c2b9c20915578ffaefb4fd30cbf42f0a1)
|
|
50
79
|
- Fix Slate point from DOM crash [`c852f79`](https://github.com/eea/volto-slate-footnote/commit/c852f7987ffe8db433235b70792002d40ade690f)
|
|
51
80
|
- Fix crash on copy&paste beforeInsert condition [`85172cf`](https://github.com/eea/volto-slate-footnote/commit/85172cff3e2ea95a86d4b4fb452f3c0287b80e8f)
|
|
52
|
-
- Add Sonarqube tag using frontend addons list [`b471c41`](https://github.com/eea/volto-slate-footnote/commit/b471c418d198b1bde95acfe0b256f642bacc6865)
|
|
53
81
|
|
|
54
82
|
#### [2.3.1](https://github.com/eea/volto-slate-footnote/compare/2.3.0...2.3.1)
|
|
55
83
|
|
|
@@ -73,7 +101,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
73
101
|
|
|
74
102
|
> 13 May 2021
|
|
75
103
|
|
|
76
|
-
- [JENKINS] - Auto-release pipeline [`#7`](https://github.com/eea/volto-slate-footnote/pull/7)
|
|
77
104
|
|
|
78
105
|
#### [2.2.0](https://github.com/eea/volto-slate-footnote/compare/2.1.1...2.2.0)
|
|
79
106
|
|
|
@@ -122,7 +149,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
122
149
|
- Fix show multiple footnotes for the same citation on copy paste [`#3`](https://github.com/eea/volto-slate-footnote/pull/3)
|
|
123
150
|
- Release 1.0.1 [`7efbb88`](https://github.com/eea/volto-slate-footnote/commit/7efbb8877ac7c1cce40a6799527102e1d131d08f)
|
|
124
151
|
- Release on npm by default [`0e96df2`](https://github.com/eea/volto-slate-footnote/commit/0e96df2605d86ebe4260ba43fa78c10227c87526)
|
|
125
|
-
- [JENKINS] - Fix eslint [`7c01ec2`](https://github.com/eea/volto-slate-footnote/commit/7c01ec2a70916788541eaa00a3757e2593fb7ff7)
|
|
126
152
|
- fix show multiple footnotes for the same citation on copy paste [`fe3391d`](https://github.com/eea/volto-slate-footnote/commit/fe3391d3b27f77cc2df663532497e27986509b14)
|
|
127
153
|
|
|
128
154
|
### [1.0.0](https://github.com/eea/volto-slate-footnote/compare/0.3.1...1.0.0)
|
|
@@ -132,7 +158,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
132
158
|
- Release 1.0.0 [`7ae4302`](https://github.com/eea/volto-slate-footnote/commit/7ae4302133411806168b5ea17bec5a267413e2cb)
|
|
133
159
|
- Add missing dependency: volto-slate [`e2a6625`](https://github.com/eea/volto-slate-footnote/commit/e2a662538b3b53006a30c171e84e6cbce0c20720)
|
|
134
160
|
- Update docs [`9efeb4e`](https://github.com/eea/volto-slate-footnote/commit/9efeb4e33ec8f58e6101875b593e34f1098cac20)
|
|
135
|
-
- [JENKINS] - Add pipeline, update docs [`d5b6d50`](https://github.com/eea/volto-slate-footnote/commit/d5b6d50d878e596aac4713d7b2293ab4e001d993)
|
|
136
161
|
|
|
137
162
|
#### [0.3.1](https://github.com/eea/volto-slate-footnote/compare/0.3.0...0.3.1)
|
|
138
163
|
|
package/Jenkinsfile
CHANGED
|
@@ -4,13 +4,37 @@ pipeline {
|
|
|
4
4
|
environment {
|
|
5
5
|
GIT_NAME = "volto-slate-footnote"
|
|
6
6
|
NAMESPACE = "@eeacms"
|
|
7
|
-
SONARQUBE_TAGS = "volto.eea.europa.eu,biodiversity.europa.eu,www.eea.europa.eu-ims"
|
|
8
|
-
DEPENDENCIES = ""
|
|
7
|
+
SONARQUBE_TAGS = "volto.eea.europa.eu,biodiversity.europa.eu,www.eea.europa.eu-ims,climate-energy.eea.europa.eu,sustainability.eionet.europa.eu,forest.eea.europa.eu,clms.land.copernicus.eu,industry.eea.europa.eu,water.europa.eu-freshwater"
|
|
8
|
+
DEPENDENCIES = "volto-slate:asDefault"
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
stages {
|
|
12
12
|
|
|
13
|
+
stage('Release') {
|
|
14
|
+
when {
|
|
15
|
+
allOf {
|
|
16
|
+
environment name: 'CHANGE_ID', value: ''
|
|
17
|
+
branch 'master'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
steps {
|
|
21
|
+
node(label: 'docker') {
|
|
22
|
+
withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN'),string(credentialsId: 'eea-jenkins-npm-token', variable: 'NPM_TOKEN')]) {
|
|
23
|
+
sh '''docker pull eeacms/gitflow'''
|
|
24
|
+
sh '''docker run -i --rm --name="$BUILD_TAG-gitflow-master" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" -e GIT_TOKEN="$GITHUB_TOKEN" -e NPM_TOKEN="$NPM_TOKEN" -e LANGUAGE=javascript eeacms/gitflow'''
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
stage('Code') {
|
|
31
|
+
when {
|
|
32
|
+
allOf {
|
|
33
|
+
environment name: 'CHANGE_ID', value: ''
|
|
34
|
+
not { changelog '.*^Automated release [0-9\\.]+$' }
|
|
35
|
+
not { branch 'master' }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
14
38
|
steps {
|
|
15
39
|
parallel(
|
|
16
40
|
|
|
@@ -36,6 +60,15 @@ pipeline {
|
|
|
36
60
|
}
|
|
37
61
|
|
|
38
62
|
stage('Tests') {
|
|
63
|
+
when {
|
|
64
|
+
allOf {
|
|
65
|
+
environment name: 'CHANGE_ID', value: ''
|
|
66
|
+
anyOf {
|
|
67
|
+
not { changelog '.*^Automated release [0-9\\.]+$' }
|
|
68
|
+
branch 'master'
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
39
72
|
steps {
|
|
40
73
|
parallel(
|
|
41
74
|
|
|
@@ -75,6 +108,15 @@ pipeline {
|
|
|
75
108
|
}
|
|
76
109
|
|
|
77
110
|
stage('Integration tests') {
|
|
111
|
+
when {
|
|
112
|
+
allOf {
|
|
113
|
+
environment name: 'CHANGE_ID', value: ''
|
|
114
|
+
anyOf {
|
|
115
|
+
not { changelog '.*^Automated release [0-9\\.]+$' }
|
|
116
|
+
branch 'master'
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
78
120
|
steps {
|
|
79
121
|
parallel(
|
|
80
122
|
|
|
@@ -122,10 +164,16 @@ pipeline {
|
|
|
122
164
|
}
|
|
123
165
|
|
|
124
166
|
stage('Report to SonarQube') {
|
|
125
|
-
// Exclude Pull-Requests
|
|
126
167
|
when {
|
|
127
168
|
allOf {
|
|
128
169
|
environment name: 'CHANGE_ID', value: ''
|
|
170
|
+
anyOf {
|
|
171
|
+
branch 'master'
|
|
172
|
+
allOf {
|
|
173
|
+
branch 'develop'
|
|
174
|
+
not { changelog '.*^Automated release [0-9\\.]+$' }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
129
177
|
}
|
|
130
178
|
}
|
|
131
179
|
steps {
|
|
@@ -156,8 +204,8 @@ pipeline {
|
|
|
156
204
|
steps {
|
|
157
205
|
node(label: 'docker') {
|
|
158
206
|
script {
|
|
159
|
-
if ( env.CHANGE_BRANCH != "develop"
|
|
160
|
-
error "Pipeline aborted due to PR not made from develop
|
|
207
|
+
if ( env.CHANGE_BRANCH != "develop" ) {
|
|
208
|
+
error "Pipeline aborted due to PR not made from develop branch"
|
|
161
209
|
}
|
|
162
210
|
withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN')]) {
|
|
163
211
|
sh '''docker pull eeacms/gitflow'''
|
|
@@ -168,23 +216,6 @@ pipeline {
|
|
|
168
216
|
}
|
|
169
217
|
}
|
|
170
218
|
|
|
171
|
-
stage('Release') {
|
|
172
|
-
when {
|
|
173
|
-
allOf {
|
|
174
|
-
environment name: 'CHANGE_ID', value: ''
|
|
175
|
-
branch 'master'
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
steps {
|
|
179
|
-
node(label: 'docker') {
|
|
180
|
-
withCredentials([string(credentialsId: 'eea-jenkins-token', variable: 'GITHUB_TOKEN'),string(credentialsId: 'eea-jenkins-npm-token', variable: 'NPM_TOKEN')]) {
|
|
181
|
-
sh '''docker pull eeacms/gitflow'''
|
|
182
|
-
sh '''docker run -i --rm --name="$BUILD_TAG-gitflow-master" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" -e GIT_TOKEN="$GITHUB_TOKEN" -e NPM_TOKEN="$NPM_TOKEN" -e LANGUAGE=javascript eeacms/gitflow'''
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
219
|
}
|
|
189
220
|
|
|
190
221
|
post {
|
package/README.md
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# volto-slate-footnote
|
|
2
|
+
|
|
2
3
|
[](https://github.com/eea/volto-slate-footnote/releases)
|
|
4
|
+
|
|
3
5
|
[](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-slate-footnote/job/master/display/redirect)
|
|
6
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-master)
|
|
7
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-master)
|
|
8
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-master)
|
|
9
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-master)
|
|
10
|
+
|
|
4
11
|
[](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-slate-footnote/job/develop/display/redirect)
|
|
12
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-develop)
|
|
13
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-develop)
|
|
14
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-develop)
|
|
15
|
+
[](https://sonarqube.eea.europa.eu/dashboard?id=volto-slate-footnote-develop)
|
|
16
|
+
|
|
5
17
|
|
|
6
18
|
[Volto Slate](https://github.com/eea/volto-slate/tree/develop) Footnotes
|
|
7
19
|
|
|
@@ -75,6 +87,81 @@
|
|
|
75
87
|
|
|
76
88
|
1. Happy editing!
|
|
77
89
|
|
|
90
|
+
## Release
|
|
91
|
+
|
|
92
|
+
### Automatic release using Jenkins
|
|
93
|
+
|
|
94
|
+
* The automatic release is started by creating a [Pull Request](../../compare/master...develop) from `develop` to `master`. The pull request status checks correlated to the branch and PR Jenkins jobs need to be processed successfully. 1 review from a github user with rights is mandatory.
|
|
95
|
+
* It runs on every commit on `master` branch, which is protected from direct commits, only allowing pull request merge commits.
|
|
96
|
+
* The automatic release is done by [Jenkins](https://ci.eionet.europa.eu). The status of the release job can be seen both in the Readme.md badges and the green check/red cross/yellow circle near the last commit information. If you click on the icon, you will have the list of checks that were run. The `continuous-integration/jenkins/branch` link goes to the Jenkins job execution webpage.
|
|
97
|
+
* Automated release scripts are located in the `eeacms/gitflow` docker image, specifically [js-release.sh](https://github.com/eea/eea.docker.gitflow/blob/master/src/js-release.sh) script. It uses the `release-it` tool.
|
|
98
|
+
* As long as a PR request is open from develop to master, the PR Jenkins job will automatically re-create the CHANGELOG.md and package.json files to be production-ready.
|
|
99
|
+
* The version format must be MAJOR.MINOR.PATCH. By default, next release is set to next minor version (with patch 0).
|
|
100
|
+
* You can manually change the version in `package.json`. The new version must not be already present in the tags/releases of the repository, otherwise it will be automatically increased by the script. Any changes to the version will trigger a `CHANGELOG.md` re-generation.
|
|
101
|
+
* Automated commits and commits with [JENKINS] or [YARN] in the commit log are excluded from `CHANGELOG.md` file.
|
|
102
|
+
|
|
103
|
+
### Manual release from the develop branch ( beta release )
|
|
104
|
+
|
|
105
|
+
#### Installation and configuration of release-it
|
|
106
|
+
|
|
107
|
+
You need to first install the [release-it](https://github.com/release-it/release-it) client.
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
npm install -g release-it
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Release-it uses the configuration written in the [`.release-it.json`](./.release-it.json) file located in the root of the repository.
|
|
114
|
+
|
|
115
|
+
Release-it is a tool that automates 4 important steps in the release process:
|
|
116
|
+
|
|
117
|
+
1. Version increase in `package.json` ( increased from the current version in `package.json`)
|
|
118
|
+
2. `CHANGELOG.md` automatic generation from commit messages ( grouped by releases )
|
|
119
|
+
3. GitHub release on the commit with the changelog and package.json modification on the develop branch
|
|
120
|
+
4. NPM release ( by default it's disabled, but can be enabled in the configuration file )
|
|
121
|
+
|
|
122
|
+
To configure the authentification, you need to export GITHUB_TOKEN for [GitHub](https://github.com/settings/tokens)
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
export GITHUB_TOKEN=XXX-XXXXXXXXXXXXXXXXXXXXXX
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
To configure npm, you can use the `npm login` command or use a configuration file with a TOKEN :
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
echo "//registry.npmjs.org/:_authToken=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" > .npmrc
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Using release-it tool
|
|
135
|
+
|
|
136
|
+
There are 3 yarn scripts that can be run to do the release
|
|
137
|
+
|
|
138
|
+
##### yarn release-beta
|
|
139
|
+
|
|
140
|
+
Automatically calculates and presents 3 beta versions - patch, minor and major for you to choose ( or Other for manual input).
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
? Select increment (next version):
|
|
144
|
+
❯ prepatch (0.1.1-beta.0)
|
|
145
|
+
preminor (0.2.0-beta.0)
|
|
146
|
+
premajor (1.0.0-beta.0)
|
|
147
|
+
Other, please specify...
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
##### yarn release-major-beta
|
|
151
|
+
|
|
152
|
+
Same as `yarn release-beta`, but with premajor version pre-selected.
|
|
153
|
+
|
|
154
|
+
##### yarn release
|
|
155
|
+
|
|
156
|
+
Generic command, does not automatically add the `beta` to version, but you can still manually write it if you choose Other.
|
|
157
|
+
|
|
158
|
+
#### Important notes
|
|
159
|
+
|
|
160
|
+
> Do not use release-it tool on master branch, the commit on CHANGELOG.md file and the version increase in the package.json file can't be done without a PULL REQUEST.
|
|
161
|
+
|
|
162
|
+
> Do not keep Pull Requests from develop to master branches open when you are doing beta releases from the develop branch. As long as a PR to master is open, an automatic script will run on every commit and will update both the version and the changelog to a production-ready state - ( MAJOR.MINOR.PATCH mandatory format for version).
|
|
163
|
+
|
|
164
|
+
|
|
78
165
|
## How to contribute
|
|
79
166
|
|
|
80
167
|
See [DEVELOP.md](DEVELOP.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-slate-footnote",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "volto-slate-footnote: Volto add-on",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"url": "git@github.com:eea/volto-slate-footnote.git"
|
|
20
20
|
},
|
|
21
21
|
"addons": [
|
|
22
|
-
"volto-slate
|
|
22
|
+
"volto-slate"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"volto-slate": "*"
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"release": "release-it",
|
|
33
|
+
"release-major-beta": "release-it major --preRelease=beta",
|
|
34
|
+
"release-beta": "release-it --preRelease=beta",
|
|
33
35
|
"bootstrap": "npm install -g ejs; npm link ejs; node bootstrap",
|
|
34
36
|
"test": "make test",
|
|
35
37
|
"test:fix": "make test-update",
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
openAccordionIfContainsFootnoteReference,
|
|
4
|
+
getAllBlocksAndSlateFields,
|
|
5
|
+
} from '@eeacms/volto-slate-footnote/editor/utils';
|
|
3
6
|
|
|
4
7
|
import './less/public.less';
|
|
5
8
|
import {
|
|
@@ -57,7 +60,7 @@ const FootnotesBlockView = (props) => {
|
|
|
57
60
|
{refsList ? (
|
|
58
61
|
<>
|
|
59
62
|
{/** some footnotes are never parent so we need the parent to reference */}
|
|
60
|
-
{/**
|
|
63
|
+
{/** in this case the first from refs has reference to the parent*/}
|
|
61
64
|
<sup
|
|
62
65
|
id={`cite_ref-${refsList[0]}`}
|
|
63
66
|
key={`indice-${refsList[0]}`}
|
|
@@ -65,6 +68,11 @@ const FootnotesBlockView = (props) => {
|
|
|
65
68
|
<a
|
|
66
69
|
href={`#ref-${parentUid || uid}`}
|
|
67
70
|
aria-label="Back to content"
|
|
71
|
+
onClick={() =>
|
|
72
|
+
openAccordionIfContainsFootnoteReference(
|
|
73
|
+
`#ref-${parentUid || uid}`,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
68
76
|
>
|
|
69
77
|
{alphabet[0]}
|
|
70
78
|
</a>{' '}
|
|
@@ -72,7 +80,15 @@ const FootnotesBlockView = (props) => {
|
|
|
72
80
|
{/** following refs will have the uid of the one that references it*/}
|
|
73
81
|
{refsList.slice(1).map((ref, index) => (
|
|
74
82
|
<sup id={`cite_ref-${ref}`} key={`indice-${ref}`}>
|
|
75
|
-
<a
|
|
83
|
+
<a
|
|
84
|
+
href={`#ref-${ref}`}
|
|
85
|
+
aria-label="Back to content"
|
|
86
|
+
onClick={() =>
|
|
87
|
+
openAccordionIfContainsFootnoteReference(
|
|
88
|
+
`#ref-${ref}`,
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
>
|
|
76
92
|
{alphabet[index + 1]}
|
|
77
93
|
</a>{' '}
|
|
78
94
|
</sup>
|
|
@@ -84,6 +100,11 @@ const FootnotesBlockView = (props) => {
|
|
|
84
100
|
<a
|
|
85
101
|
href={`#ref-${parentUid || uid}`}
|
|
86
102
|
aria-label="Back to content"
|
|
103
|
+
onClick={() =>
|
|
104
|
+
openAccordionIfContainsFootnoteReference(
|
|
105
|
+
`#ref-${parentUid || uid}`,
|
|
106
|
+
)
|
|
107
|
+
}
|
|
87
108
|
>
|
|
88
109
|
↵
|
|
89
110
|
</a>{' '}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isEqual } from 'lodash';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
import { ReactEditor } from 'slate-react';
|
|
5
5
|
import { setPluginOptions } from 'volto-slate/actions';
|
|
@@ -8,6 +8,8 @@ import briefcaseSVG from '@plone/volto/icons/briefcase.svg';
|
|
|
8
8
|
import checkSVG from '@plone/volto/icons/check.svg';
|
|
9
9
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
10
10
|
import { Node } from 'slate';
|
|
11
|
+
import { useSelector } from 'react-redux';
|
|
12
|
+
import { isEmpty } from 'lodash';
|
|
11
13
|
import { getAllBlocksAndSlateFields } from '@eeacms/volto-slate-footnote/editor/utils';
|
|
12
14
|
|
|
13
15
|
const FootnoteEditor = (props) => {
|
|
@@ -23,8 +25,10 @@ const FootnoteEditor = (props) => {
|
|
|
23
25
|
onChangeValues,
|
|
24
26
|
} = props;
|
|
25
27
|
const dispatch = useDispatch();
|
|
28
|
+
const pid = `${editor.uid}-${pluginId}`;
|
|
26
29
|
const [formData, setFormData] = React.useState({});
|
|
27
30
|
const active = getActiveElement(editor);
|
|
31
|
+
const initialFormData = useSelector((state) => state?.content?.data || {});
|
|
28
32
|
|
|
29
33
|
if (!active) {
|
|
30
34
|
/* eslint no-console: 0 */
|
|
@@ -35,53 +39,43 @@ const FootnoteEditor = (props) => {
|
|
|
35
39
|
|
|
36
40
|
const blockProps = editor?.getBlockProps ? editor.getBlockProps() : {};
|
|
37
41
|
const metadata = blockProps.metadata || blockProps.properties || {};
|
|
38
|
-
const
|
|
39
|
-
const
|
|
42
|
+
const metadataBlocks = getAllBlocksAndSlateFields(metadata);
|
|
43
|
+
const storeBlocks = getAllBlocksAndSlateFields(initialFormData);
|
|
44
|
+
const uniqueFootnoteBlocks = [];
|
|
40
45
|
|
|
46
|
+
const flatAllBlocks = isEmpty(metadata) ? storeBlocks : metadataBlocks;
|
|
47
|
+
/**
|
|
48
|
+
* Will add only the items that are unique by text
|
|
49
|
+
* @param {Object[]} uniqueFootnoteBlocks
|
|
50
|
+
* @param {Object} itemToManage
|
|
51
|
+
*/
|
|
52
|
+
const manageAddBlockToUniqueBlocks = (uniqueFootnoteBlocks, itemToManage) => {
|
|
53
|
+
if (
|
|
54
|
+
!uniqueFootnoteBlocks.find((item) => item.title === itemToManage.footnote)
|
|
55
|
+
) {
|
|
56
|
+
uniqueFootnoteBlocks.push({
|
|
57
|
+
...itemToManage,
|
|
58
|
+
title: itemToManage.footnote || itemToManage.value,
|
|
59
|
+
label: itemToManage.footnote || itemToManage.value,
|
|
60
|
+
value: itemToManage.footnote || itemToManage.value,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
41
64
|
// make a list of filtered footnotes that have unique title
|
|
42
65
|
// to be used as choices for the multi search widget
|
|
43
66
|
// add label and value for the multi search widget
|
|
44
67
|
// flatten blocks to add all extra in the list
|
|
45
|
-
|
|
68
|
+
flatAllBlocks
|
|
46
69
|
.filter((b) => b['@type'] === 'slate')
|
|
47
70
|
.forEach(({ value }) => {
|
|
48
71
|
if (!value) return;
|
|
49
72
|
|
|
50
73
|
Array.from(Node.elements(value[0])).forEach(([block]) => {
|
|
51
74
|
block.children.forEach((node) => {
|
|
52
|
-
if (node.data && node.type === 'footnote'
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
filteredBlocks.push({
|
|
57
|
-
...node.data,
|
|
58
|
-
title: node.data.footnote || node.data.value,
|
|
59
|
-
label: node.data.footnote || node.data.value,
|
|
60
|
-
value: node.data.footnote || node.data.value,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
node.data.extra.forEach((ftitem) => {
|
|
64
|
-
if (
|
|
65
|
-
!filteredBlocks.find((item) => item.title === ftitem.footnote)
|
|
66
|
-
) {
|
|
67
|
-
filteredBlocks.push({
|
|
68
|
-
...ftitem,
|
|
69
|
-
title: ftitem.footnote || ftitem.value,
|
|
70
|
-
label: ftitem.footnote || ftitem.value,
|
|
71
|
-
value: ftitem.footnote || ftitem.value,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
} else if (
|
|
76
|
-
node.data &&
|
|
77
|
-
node.type === 'footnote' &&
|
|
78
|
-
!filteredBlocks.find((item) => item.title === node.data.footnote)
|
|
79
|
-
) {
|
|
80
|
-
filteredBlocks.push({
|
|
81
|
-
...node.data,
|
|
82
|
-
title: node.data.footnote,
|
|
83
|
-
label: node.data.footnote,
|
|
84
|
-
value: node.data.footnote,
|
|
75
|
+
if (node.data && node.type === 'footnote') {
|
|
76
|
+
manageAddBlockToUniqueBlocks(uniqueFootnoteBlocks, node.data);
|
|
77
|
+
(node.data.extra || []).forEach((ftitem) => {
|
|
78
|
+
manageAddBlockToUniqueBlocks(uniqueFootnoteBlocks, ftitem);
|
|
85
79
|
});
|
|
86
80
|
}
|
|
87
81
|
});
|
|
@@ -105,6 +99,21 @@ const FootnoteEditor = (props) => {
|
|
|
105
99
|
elRef.current = null;
|
|
106
100
|
}
|
|
107
101
|
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (isElement) {
|
|
104
|
+
elRef.current = elementNode;
|
|
105
|
+
setFormData({
|
|
106
|
+
footnote: {
|
|
107
|
+
...elementNode.data,
|
|
108
|
+
label: elementNode.data.footnote,
|
|
109
|
+
value: elementNode.data.footnote,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
} else if (!isElement) {
|
|
113
|
+
elRef.current = null;
|
|
114
|
+
}
|
|
115
|
+
}, [isElement, elRef, elementNode]); // eslint-disable-line
|
|
116
|
+
|
|
108
117
|
const saveDataToEditor = React.useCallback(
|
|
109
118
|
(formData) => {
|
|
110
119
|
if (hasValue(formData.footnote)) {
|
|
@@ -132,7 +141,7 @@ const FootnoteEditor = (props) => {
|
|
|
132
141
|
...schema.properties,
|
|
133
142
|
footnote: {
|
|
134
143
|
...schema.properties.footnote,
|
|
135
|
-
choices:
|
|
144
|
+
choices: uniqueFootnoteBlocks,
|
|
136
145
|
},
|
|
137
146
|
},
|
|
138
147
|
};
|
|
@@ -150,14 +159,14 @@ const FootnoteEditor = (props) => {
|
|
|
150
159
|
}}
|
|
151
160
|
formData={formData}
|
|
152
161
|
dataBoss={formData}
|
|
153
|
-
source={
|
|
162
|
+
source={uniqueFootnoteBlocks}
|
|
154
163
|
headerActions={
|
|
155
164
|
<>
|
|
156
165
|
<button
|
|
157
166
|
onClick={() => {
|
|
158
167
|
saveDataToEditor(formData);
|
|
159
168
|
dispatch(
|
|
160
|
-
setPluginOptions(
|
|
169
|
+
setPluginOptions(pid, {
|
|
161
170
|
show_sidebar_editor: false,
|
|
162
171
|
}),
|
|
163
172
|
);
|
|
@@ -170,7 +179,7 @@ const FootnoteEditor = (props) => {
|
|
|
170
179
|
onClick={() => {
|
|
171
180
|
checkForCancel();
|
|
172
181
|
dispatch(
|
|
173
|
-
setPluginOptions(
|
|
182
|
+
setPluginOptions(pid, {
|
|
174
183
|
show_sidebar_editor: false,
|
|
175
184
|
}),
|
|
176
185
|
);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module components/manage/Widgets/ArrayWidget
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React, { useState } from 'react';
|
|
6
|
+
import React, { useState, useEffect } from 'react';
|
|
7
7
|
import { defineMessages } from 'react-intl';
|
|
8
8
|
import {
|
|
9
9
|
Option,
|
|
@@ -30,11 +30,33 @@ const messages = defineMessages({
|
|
|
30
30
|
|
|
31
31
|
const MultiSelectSearchWidget = injectLazyLibs('reactSelectAsyncCreateable')(
|
|
32
32
|
(props) => {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const [
|
|
36
|
-
|
|
37
|
-
)
|
|
33
|
+
const [selectedOption, setSelectedOption] = useState([]);
|
|
34
|
+
const [defaultOptions, setDefaultOptions] = useState([]);
|
|
35
|
+
const [parentFootnote, setParentFootnote] = useState(props.value);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (props.value) {
|
|
39
|
+
const parentFootnoteCurrent = props.value;
|
|
40
|
+
|
|
41
|
+
const extraValues =
|
|
42
|
+
parentFootnoteCurrent && props.value.extra ? props.value.extra : [];
|
|
43
|
+
const selectedOptionCurrent = parentFootnoteCurrent.value
|
|
44
|
+
? [...[parentFootnoteCurrent], ...extraValues]
|
|
45
|
+
: [];
|
|
46
|
+
setSelectedOption(selectedOptionCurrent);
|
|
47
|
+
|
|
48
|
+
// from choices (list of all footnotes available including current in value) get all not
|
|
49
|
+
// found in current in value
|
|
50
|
+
// consider that new footnotes have value and footnote undefined
|
|
51
|
+
const defaultOptions = (props.choices || []).filter(
|
|
52
|
+
(item) =>
|
|
53
|
+
!selectedOption.find(({ label }) => label === item.label) &&
|
|
54
|
+
item.value,
|
|
55
|
+
);
|
|
56
|
+
setDefaultOptions(defaultOptions);
|
|
57
|
+
setParentFootnote(props.value);
|
|
58
|
+
}
|
|
59
|
+
}, [props]); // eslint-disable-line
|
|
38
60
|
|
|
39
61
|
/**
|
|
40
62
|
* evaluate on Regex to filter results
|
|
@@ -53,77 +75,74 @@ const MultiSelectSearchWidget = injectLazyLibs('reactSelectAsyncCreateable')(
|
|
|
53
75
|
|
|
54
76
|
/**
|
|
55
77
|
* If the list is empty or the first is not parent, return true
|
|
56
|
-
* @param {Object[]}
|
|
78
|
+
* @param {Object[]} optionsList list of objects - footnotes
|
|
57
79
|
* @returns {boolean}
|
|
58
80
|
*/
|
|
59
|
-
const isParetFootnoteRemoved = (
|
|
60
|
-
!
|
|
81
|
+
const isParetFootnoteRemoved = (optionsList) =>
|
|
82
|
+
!optionsList[0] || optionsList[0].value !== parentFootnote.value;
|
|
61
83
|
|
|
62
84
|
/**
|
|
63
85
|
* replace all parentFootnote data except uid, with the first from the list
|
|
64
|
-
* @param {Object[]}
|
|
86
|
+
* @param {Object[]} optionsList list of objects - footnotes
|
|
65
87
|
* @returns {Object}
|
|
66
88
|
*/
|
|
67
|
-
const setParentFootnoteFromExtra = (
|
|
68
|
-
const { footnote, label, value } =
|
|
89
|
+
const setParentFootnoteFromExtra = (optionsList) => {
|
|
90
|
+
const { footnote, label, value } = optionsList[0] || [];
|
|
69
91
|
|
|
70
92
|
return {
|
|
71
93
|
...parentFootnote,
|
|
72
|
-
footnote: footnote ||
|
|
94
|
+
footnote: footnote || optionsList[0]?.value,
|
|
73
95
|
label,
|
|
74
96
|
value,
|
|
75
|
-
extra:
|
|
97
|
+
extra: optionsList.slice(1),
|
|
76
98
|
};
|
|
77
99
|
};
|
|
78
100
|
|
|
79
101
|
/**
|
|
80
|
-
* Will make the footnotes object, that will be saved as first from
|
|
102
|
+
* Will make the footnotes object, that will be saved as first from optionsList
|
|
81
103
|
* the rest will be added to extra
|
|
82
|
-
* @param {
|
|
104
|
+
* @param {Object[]} optionsList
|
|
83
105
|
* @returns
|
|
84
106
|
*/
|
|
85
|
-
const setFootnoteFromSelection = (
|
|
86
|
-
const extra =
|
|
107
|
+
const setFootnoteFromSelection = (optionsList) => {
|
|
108
|
+
const extra = optionsList.slice(1).map((item) => {
|
|
87
109
|
const obj = {
|
|
88
|
-
uid: nanoid(5),
|
|
89
110
|
...item,
|
|
90
111
|
footnote: item.value,
|
|
91
112
|
};
|
|
92
113
|
|
|
93
|
-
const { __isNew__: remove, ...rest } = obj;
|
|
114
|
+
const { __isNew__: remove, extra, ...rest } = obj;
|
|
94
115
|
return rest;
|
|
95
116
|
});
|
|
96
|
-
|
|
97
117
|
return { ...parentFootnote, extra };
|
|
98
118
|
};
|
|
99
119
|
|
|
100
120
|
/**
|
|
101
121
|
* Handle the field change, will remake the result based on the new selected list
|
|
102
122
|
* @method handleChange
|
|
103
|
-
* @param {array}
|
|
123
|
+
* @param {array} optionsList The selected options (already aggregated).
|
|
104
124
|
* @returns {undefined}
|
|
105
125
|
*/
|
|
106
|
-
const handleChange = (
|
|
107
|
-
|
|
126
|
+
const handleChange = (optionsList) => {
|
|
127
|
+
const formattedSelectedOptions = optionsList.map((option) => ({
|
|
128
|
+
footnoteId: nanoid(5), // to be overwritten if already exists (keep as a reference to same text)
|
|
129
|
+
...option,
|
|
130
|
+
uid: nanoid(5), // overwrite existing, thus creating new record for the same text
|
|
131
|
+
footnote: option.value,
|
|
132
|
+
}));
|
|
133
|
+
setSelectedOption(formattedSelectedOptions);
|
|
108
134
|
|
|
109
135
|
// manage case if parent footnotes (first from the options) was removed
|
|
110
|
-
const resultSelected = isParetFootnoteRemoved(
|
|
111
|
-
? setParentFootnoteFromExtra(
|
|
112
|
-
: setFootnoteFromSelection(
|
|
136
|
+
const resultSelected = isParetFootnoteRemoved(formattedSelectedOptions)
|
|
137
|
+
? setParentFootnoteFromExtra(formattedSelectedOptions)
|
|
138
|
+
: setFootnoteFromSelection(formattedSelectedOptions);
|
|
113
139
|
|
|
114
140
|
props.onChange({
|
|
115
141
|
footnote: resultSelected,
|
|
116
142
|
});
|
|
117
143
|
};
|
|
118
144
|
|
|
119
|
-
// from choices (list of all footnotes available including current in value) get all not found in current in value
|
|
120
|
-
// consider that new footnotes have value and footnote undefined
|
|
121
|
-
const defaultOptions = (props.choices || []).filter(
|
|
122
|
-
(item) =>
|
|
123
|
-
!selectedOption.find(({ label }) => label === item.label) && item.value,
|
|
124
|
-
);
|
|
125
145
|
const AsyncCreatableSelect = props.reactSelectAsyncCreateable.default;
|
|
126
|
-
|
|
127
146
|
return (
|
|
128
147
|
<FormFieldWrapper {...props}>
|
|
129
148
|
<AsyncCreatableSelect
|
package/src/editor/render.jsx
CHANGED
|
@@ -2,7 +2,12 @@ import React, { useEffect, useState } from 'react';
|
|
|
2
2
|
import { Popup, List } from 'semantic-ui-react';
|
|
3
3
|
import { useEditorContext } from 'volto-slate/hooks';
|
|
4
4
|
import { getAllBlocksAndSlateFields } from '@eeacms/volto-slate-footnote/editor/utils';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
makeFootnoteListOfUniqueItems,
|
|
7
|
+
openAccordionIfContainsFootnoteReference,
|
|
8
|
+
} from './utils';
|
|
9
|
+
import { isEmpty } from 'lodash';
|
|
10
|
+
import { useSelector } from 'react-redux';
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* Removes '<?xml version="1.0"?>' from footnote
|
|
@@ -15,24 +20,6 @@ const makeFootnote = (footnote) => {
|
|
|
15
20
|
return free;
|
|
16
21
|
};
|
|
17
22
|
|
|
18
|
-
/**
|
|
19
|
-
* Will open accordion if contains footnote reference
|
|
20
|
-
* @param {string} footnoteId
|
|
21
|
-
*/
|
|
22
|
-
const openAccordionIfContainsFootnoteReference = (footnoteId) => {
|
|
23
|
-
if (typeof window !== 'undefined') {
|
|
24
|
-
const footnote = document.querySelector(footnoteId);
|
|
25
|
-
if (footnote !== null && footnote.closest('.accordion') !== null) {
|
|
26
|
-
const comp = footnote.closest('.accordion').querySelector('.title');
|
|
27
|
-
if (!comp.className.includes('active')) {
|
|
28
|
-
comp.click();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return true;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
23
|
export const FootnoteElement = (props) => {
|
|
37
24
|
const { attributes, children, element, mode, extras } = props;
|
|
38
25
|
const { data = {} } = element;
|
|
@@ -40,6 +27,7 @@ export const FootnoteElement = (props) => {
|
|
|
40
27
|
const editor = useEditorContext();
|
|
41
28
|
const [citationIndice, setCitationIndice] = useState(null); // list of indices to reference
|
|
42
29
|
const [citationRefId, setCitationRefId] = useState(null); // indice of element to be referenced
|
|
30
|
+
const initialFormData = useSelector((state) => state?.content?.data || {});
|
|
43
31
|
|
|
44
32
|
useEffect(() => {
|
|
45
33
|
const blockProps = editor?.getBlockProps ? editor.getBlockProps() : null;
|
|
@@ -47,7 +35,11 @@ export const FootnoteElement = (props) => {
|
|
|
47
35
|
? blockProps.metadata || blockProps.properties
|
|
48
36
|
: extras?.metadata || {};
|
|
49
37
|
const blocks = getAllBlocksAndSlateFields(metadata);
|
|
50
|
-
const
|
|
38
|
+
const storeBlocks = getAllBlocksAndSlateFields(initialFormData);
|
|
39
|
+
|
|
40
|
+
const notesObjResult = isEmpty(metadata)
|
|
41
|
+
? makeFootnoteListOfUniqueItems(storeBlocks)
|
|
42
|
+
: makeFootnoteListOfUniqueItems(blocks);
|
|
51
43
|
|
|
52
44
|
// will cosider zotero citations and footnote
|
|
53
45
|
// notesObjResult contains all zotero/footnote as unique, and contain refs for other zotero/footnote
|
|
@@ -67,72 +59,20 @@ export const FootnoteElement = (props) => {
|
|
|
67
59
|
: // no extra citations (no multiples)
|
|
68
60
|
`[${Object.keys(notesObjResult).indexOf(zoteroId) + 1}]`
|
|
69
61
|
: // FOOTNOTES
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`[${
|
|
85
|
-
Object.keys(notesObjResult).indexOf(
|
|
86
|
-
Object.keys(notesObjResult).find(
|
|
87
|
-
(noteKey) =>
|
|
88
|
-
notesObjResult[noteKey].refs &&
|
|
89
|
-
notesObjResult[noteKey].refs[data.uid],
|
|
90
|
-
),
|
|
91
|
-
) + 1
|
|
92
|
-
}]`;
|
|
93
|
-
}),
|
|
94
|
-
].join('')
|
|
95
|
-
: // no extra footnotes (no multiples)
|
|
96
|
-
`[${Object.keys(notesObjResult).indexOf(data.uid) + 1}]`
|
|
97
|
-
: // footnotes not found in notesObjResult
|
|
98
|
-
data.extra
|
|
99
|
-
? [
|
|
100
|
-
// look for it in other footnotes refs - parent
|
|
101
|
-
`[${
|
|
102
|
-
Object.keys(notesObjResult).indexOf(
|
|
103
|
-
Object.keys(notesObjResult).find(
|
|
104
|
-
(noteKey) =>
|
|
105
|
-
notesObjResult[noteKey].refs &&
|
|
106
|
-
notesObjResult[noteKey].refs[data.uid],
|
|
107
|
-
),
|
|
108
|
-
) + 1
|
|
109
|
-
}]`,
|
|
110
|
-
...data.extra.map((footnoteObj, index) => {
|
|
111
|
-
return notesObjResult[footnoteObj.uid]
|
|
112
|
-
? // footnotes from extra might be found in notesObjResult
|
|
113
|
-
`[${Object.keys(notesObjResult).indexOf(footnoteObj.uid) + 1}]`
|
|
114
|
-
: // if uid is not found look for it in other footnotes refs
|
|
115
|
-
`[${
|
|
116
|
-
Object.keys(notesObjResult).indexOf(
|
|
117
|
-
Object.keys(notesObjResult).find(
|
|
118
|
-
(noteKey) =>
|
|
119
|
-
notesObjResult[noteKey].refs &&
|
|
120
|
-
notesObjResult[noteKey].refs[data.uid],
|
|
121
|
-
),
|
|
122
|
-
) + 1
|
|
123
|
-
}]`;
|
|
124
|
-
}),
|
|
125
|
-
].join('')
|
|
126
|
-
: // no extra footnotes
|
|
127
|
-
`[${
|
|
128
|
-
Object.keys(notesObjResult).indexOf(
|
|
129
|
-
Object.keys(notesObjResult).find(
|
|
130
|
-
(noteKey) =>
|
|
131
|
-
notesObjResult[noteKey].refs &&
|
|
132
|
-
notesObjResult[noteKey].refs[data.uid],
|
|
133
|
-
),
|
|
134
|
-
) + 1
|
|
135
|
-
}]`;
|
|
62
|
+
// parent footnote
|
|
63
|
+
[data, ...(data.extra || [])]
|
|
64
|
+
.map((footnoteObj, index) => {
|
|
65
|
+
return `[${
|
|
66
|
+
Object.keys(notesObjResult).indexOf(
|
|
67
|
+
Object.keys(notesObjResult).find(
|
|
68
|
+
(key) =>
|
|
69
|
+
notesObjResult[key].footnote === footnoteObj.footnote,
|
|
70
|
+
),
|
|
71
|
+
) + 1
|
|
72
|
+
}]`;
|
|
73
|
+
})
|
|
74
|
+
.join('');
|
|
75
|
+
|
|
136
76
|
const findReferenceId =
|
|
137
77
|
// search within parent citations first, otherwise the uid might be inside a refs obj that comes before
|
|
138
78
|
Object.keys(notesObjResult).find(
|
package/src/editor/utils.js
CHANGED
|
@@ -13,6 +13,76 @@ export const makeFootnote = (footnote) => {
|
|
|
13
13
|
return free;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Will open accordion if contains footnote reference
|
|
18
|
+
* @param {string} footnoteId
|
|
19
|
+
*/
|
|
20
|
+
export const openAccordionIfContainsFootnoteReference = (footnoteId) => {
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
const footnote = document.querySelector(footnoteId);
|
|
23
|
+
if (footnote !== null && footnote.closest('.accordion') !== null) {
|
|
24
|
+
const comp = footnote.closest('.accordion').querySelector('.title');
|
|
25
|
+
if (!comp.className.includes('active')) {
|
|
26
|
+
comp.click();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return true;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const blockTypesOperations = {
|
|
35
|
+
metadataSection: (block, properties) => {
|
|
36
|
+
const fields = block.fields;
|
|
37
|
+
|
|
38
|
+
const flatMetadataSectionBlocks = fields
|
|
39
|
+
.filter((field) => field?.field?.widget === 'slate')
|
|
40
|
+
.reduce((accumulator, currentField) => {
|
|
41
|
+
const fieldId = currentField.field.id;
|
|
42
|
+
const propertiesBlocks = (properties[fieldId] || []).map(
|
|
43
|
+
(propertyBlockValue) => ({
|
|
44
|
+
'@type': 'slate',
|
|
45
|
+
id: fieldId,
|
|
46
|
+
value: [propertyBlockValue],
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
return [...accumulator, ...propertiesBlocks];
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return flatMetadataSectionBlocks;
|
|
53
|
+
},
|
|
54
|
+
metadata: (block, properties) => {
|
|
55
|
+
const fId = block.data.id;
|
|
56
|
+
|
|
57
|
+
return block?.data?.widget === 'slate'
|
|
58
|
+
? [
|
|
59
|
+
{
|
|
60
|
+
'@type': 'slate',
|
|
61
|
+
id: fId,
|
|
62
|
+
value: properties[fId]?.length ? properties[fId] : null,
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
: [];
|
|
66
|
+
},
|
|
67
|
+
slateTable: (block) => {
|
|
68
|
+
const flatSlateBlocks = (block?.table?.rows || []).reduce(
|
|
69
|
+
(accumulator, currentRow) => {
|
|
70
|
+
const cellsBlocks = (currentRow.cells || []).map((cell) => ({
|
|
71
|
+
'@type': 'slate',
|
|
72
|
+
...cell,
|
|
73
|
+
}));
|
|
74
|
+
return [...accumulator, ...cellsBlocks];
|
|
75
|
+
},
|
|
76
|
+
[],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return flatSlateBlocks;
|
|
80
|
+
},
|
|
81
|
+
defaultOperation: (block) => {
|
|
82
|
+
return [block];
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
16
86
|
/**
|
|
17
87
|
* Extends volto-slate getAllBlocks functionality also to SlateJSONFields
|
|
18
88
|
* inserted within blocks via Metadata / Metadata section block
|
|
@@ -21,36 +91,17 @@ export const makeFootnote = (footnote) => {
|
|
|
21
91
|
*/
|
|
22
92
|
export const getAllBlocksAndSlateFields = (properties) => {
|
|
23
93
|
const blocks = getAllBlocks(properties, []);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
id: field_id,
|
|
36
|
-
value: properties[field_id]?.length ? properties[field_id] : null,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else if (block['@type'] === 'metadata') {
|
|
41
|
-
if (block?.data?.widget === 'slate') {
|
|
42
|
-
const f_id = block.data.id;
|
|
43
|
-
flat_blocks.push({
|
|
44
|
-
'@type': 'slate',
|
|
45
|
-
id: f_id,
|
|
46
|
-
value: properties[f_id]?.length ? properties[f_id] : null,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
flat_blocks.push(block);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return flat_blocks;
|
|
94
|
+
|
|
95
|
+
const flatBlocksResult = blocks.reduce((accumulator, currentblock) => {
|
|
96
|
+
return [
|
|
97
|
+
...accumulator,
|
|
98
|
+
...(blockTypesOperations[currentblock['@type']]
|
|
99
|
+
? blockTypesOperations[currentblock['@type']](currentblock, properties)
|
|
100
|
+
: blockTypesOperations.defaultOperation(currentblock)),
|
|
101
|
+
];
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
return flatBlocksResult;
|
|
54
105
|
};
|
|
55
106
|
|
|
56
107
|
/**
|
|
@@ -85,18 +136,18 @@ export const makeFootnoteListOfUniqueItems = (blocks) => {
|
|
|
85
136
|
);
|
|
86
137
|
}
|
|
87
138
|
// for footnotes - create refs, on identical text
|
|
88
|
-
} else if (node.data.extra) {
|
|
89
|
-
iterateFootnoteObj(notesObjResult, node.data);
|
|
90
|
-
node.data.extra.forEach((footnoteObjItem) =>
|
|
91
|
-
// since is called in case of extra, the parent is needed
|
|
92
|
-
iterateFootnoteObj(
|
|
93
|
-
notesObjResult,
|
|
94
|
-
footnoteObjItem,
|
|
95
|
-
node.data.uid,
|
|
96
|
-
),
|
|
97
|
-
);
|
|
98
139
|
} else {
|
|
99
140
|
iterateFootnoteObj(notesObjResult, node.data);
|
|
141
|
+
if (node.data.extra) {
|
|
142
|
+
node.data.extra.forEach((footnoteObjItem) =>
|
|
143
|
+
// since is called in case of extra, the parent is needed
|
|
144
|
+
iterateFootnoteObj(
|
|
145
|
+
notesObjResult,
|
|
146
|
+
footnoteObjItem,
|
|
147
|
+
node.data.uid,
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
100
151
|
}
|
|
101
152
|
}
|
|
102
153
|
});
|
|
@@ -161,11 +212,11 @@ const iterateFootnoteObj = (notesObjResultTemp, node, parentUid) => {
|
|
|
161
212
|
: { ...node };
|
|
162
213
|
// the element is found, just add it's own uid to the list of refs, the parent is already known
|
|
163
214
|
} else if (notesObjResultTemp[found].refs) {
|
|
164
|
-
notesObjResultTemp[found].refs[
|
|
215
|
+
notesObjResultTemp[found].refs[uid] = true;
|
|
165
216
|
} else {
|
|
166
217
|
// element found but doesn't have refs yet, this means that it is a parent, so add it's existing uid and the current one
|
|
167
218
|
notesObjResultTemp[found].refs = {
|
|
168
|
-
[
|
|
219
|
+
[found]: true,
|
|
169
220
|
[uid]: true,
|
|
170
221
|
};
|
|
171
222
|
}
|