@lblod/ember-rdfa-editor-lblod-plugins 16.0.1 → 16.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 +18 -0
- package/README.md +9 -0
- package/addon/components/article-structure-plugin/structure-card.hbs +33 -0
- package/addon/components/article-structure-plugin/structure-card.ts +53 -0
- package/addon/plugins/article-structure-plugin/commands/index.ts +1 -0
- package/addon/plugins/article-structure-plugin/commands/recalculate-structure-numbers.ts +7 -0
- package/addon/plugins/article-structure-plugin/commands/set-structure-start-number.ts +43 -0
- package/addon/plugins/article-structure-plugin/index.ts +10 -0
- package/addon/plugins/article-structure-plugin/structures/article-paragraph.ts +23 -18
- package/addon/plugins/article-structure-plugin/structures/article.ts +19 -19
- package/addon/plugins/article-structure-plugin/structures/chapter.ts +3 -7
- package/addon/plugins/article-structure-plugin/structures/section.ts +3 -7
- package/addon/plugins/article-structure-plugin/structures/structure-header.ts +22 -15
- package/addon/plugins/article-structure-plugin/structures/subsection.ts +3 -7
- package/addon/plugins/article-structure-plugin/structures/title.ts +3 -7
- package/addon/plugins/article-structure-plugin/utils/romanize.ts +85 -0
- package/addon/plugins/article-structure-plugin/utils/structure.ts +133 -51
- package/addon/plugins/standard-template-plugin/utils/nodes.ts +31 -23
- package/addon/plugins/template-comments-plugin/node.ts +4 -3
- package/addon/utils/translation.ts +35 -0
- package/app/styles/citaten-plugin.scss +0 -2
- package/app/styles/confidentiality-plugin.scss +0 -2
- package/app/styles/template-comments-plugin.scss +3 -2
- package/components/article-structure-plugin/structure-card.d.ts +7 -0
- package/package.json +1 -1
- package/plugins/article-structure-plugin/commands/index.d.ts +1 -0
- package/plugins/article-structure-plugin/commands/set-structure-start-number.d.ts +4 -0
- package/plugins/article-structure-plugin/index.d.ts +13 -0
- package/plugins/article-structure-plugin/utils/romanize.d.ts +5 -0
- package/plugins/article-structure-plugin/utils/structure.d.ts +16 -3
- package/translations/en-US.yaml +4 -0
- package/translations/nl-BE.yaml +4 -0
- package/utils/translation.d.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @lblod/ember-rdfa-editor-lblod-plugins
|
|
2
2
|
|
|
3
|
+
## 16.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#377](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/377) [`c383236`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/c38323626745e55671bcbc2afc01d91b17911dd3) Thanks [@elpoelma](https://github.com/elpoelma)! - - Addition of the `say-template-comment` class to the static version of template comments.
|
|
8
|
+
|
|
9
|
+
- Addition of some extra styles to the `say-template-comment` class.
|
|
10
|
+
|
|
11
|
+
- [#378](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/378) [`7b53e51`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/7b53e514aac79286267da1f7f32b7179fea3fb7d) Thanks [@elpoelma](https://github.com/elpoelma)! - Add helper function to help with locale selection and add translation note to readme
|
|
12
|
+
|
|
13
|
+
- [#376](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/376) [`301b4b3`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/301b4b3a9288ce53f7be4117e95526bf73be1534) Thanks [@dkozickis](https://github.com/dkozickis)! - GN-4650: Allows to set a "start number" for a structure.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#377](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/377) [`c383236`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/c38323626745e55671bcbc2afc01d91b17911dd3) Thanks [@elpoelma](https://github.com/elpoelma)! - Remove `@import "ember-appuniversum"` statements from plugin sass modules in order to prevent style overrding.
|
|
18
|
+
|
|
19
|
+
- [`4ddf16c`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/4ddf16c91959d77fda1cd7b033f7ca18d2857b70) Thanks [@elpoelma](https://github.com/elpoelma)! - Fix template-comment padding
|
|
20
|
+
|
|
3
21
|
## 16.0.1
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -859,6 +859,15 @@ To use `@lblod/ember-rdfa-editor-lblod-plugins` with Embroider some extra Webpac
|
|
|
859
859
|
|
|
860
860
|
If you already provide some Webpack configuration, you can deep merge that with the config object we provide.
|
|
861
861
|
|
|
862
|
+
## Translation
|
|
863
|
+
|
|
864
|
+
Translations are provided for UI elements using ember-intl.
|
|
865
|
+
Currently the only languages supported are English (en-US) and Dutch (nl-BE).
|
|
866
|
+
Other languages can be added by copying the contents of the file `translations/en-us.yaml` into the relevant language file in your `translations` folder and translating all of the strings.
|
|
867
|
+
|
|
868
|
+
A helper function is provided to assist with finding a reasonable fallback locale, for example providing `en-US` translations if `en` is requested.
|
|
869
|
+
See [the test app](tests/dummy/app/routes/application.ts) for example of it's usage.
|
|
870
|
+
|
|
862
871
|
## Contributing
|
|
863
872
|
|
|
864
873
|
See the [Contributing](CONTRIBUTING.md) guide for details.
|
|
@@ -79,6 +79,39 @@
|
|
|
79
79
|
|
|
80
80
|
</AuButtonGroup>
|
|
81
81
|
</Item>
|
|
82
|
+
<Item class="au-u-padding-left-small">
|
|
83
|
+
<AuFormRow>
|
|
84
|
+
{{#let (unique-id) as |id|}}
|
|
85
|
+
<AuLabel for={{id}}>
|
|
86
|
+
{{t 'article-structure-plugin.start-number.start-number'}}
|
|
87
|
+
</AuLabel>
|
|
88
|
+
<AuInput
|
|
89
|
+
id={{id}}
|
|
90
|
+
value={{this.startNumberInputValue}}
|
|
91
|
+
{{on "change" this.onStartNumberChange}}
|
|
92
|
+
placeholder={{t 'article-structure-plugin.start-number.start-number'}}
|
|
93
|
+
type="number"
|
|
94
|
+
min="1"
|
|
95
|
+
/>
|
|
96
|
+
{{/let}}
|
|
97
|
+
</AuFormRow>
|
|
98
|
+
<AuButton
|
|
99
|
+
@iconAlignment="left"
|
|
100
|
+
class="au-u-margin-top-tiny"
|
|
101
|
+
{{on 'click' this.setStructureStartNumber}}
|
|
102
|
+
>
|
|
103
|
+
{{t 'article-structure-plugin.start-number.set'}}
|
|
104
|
+
</AuButton>
|
|
105
|
+
<AuButton
|
|
106
|
+
@iconAlignment="left"
|
|
107
|
+
@skin="secondary"
|
|
108
|
+
@disabled={{not this.structureStartNumber}}
|
|
109
|
+
class="au-u-margin-top-tiny"
|
|
110
|
+
{{on 'click' this.resetStructureStartNumber}}
|
|
111
|
+
>
|
|
112
|
+
{{t 'article-structure-plugin.start-number.reset'}}
|
|
113
|
+
</AuButton>
|
|
114
|
+
</Item>
|
|
82
115
|
</AuList>
|
|
83
116
|
</c.content>
|
|
84
117
|
</AuCard>
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
moveSelectedStructure,
|
|
6
6
|
removeStructure,
|
|
7
7
|
unwrapStructure,
|
|
8
|
+
setStructureStartNumber,
|
|
8
9
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/commands';
|
|
9
10
|
import { ArticleStructurePluginOptions } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin';
|
|
10
11
|
import { findAncestorOfType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
|
|
@@ -20,6 +21,7 @@ type Args = {
|
|
|
20
21
|
export default class EditorPluginsStructureCardComponent extends Component<Args> {
|
|
21
22
|
@service declare intl: IntlService;
|
|
22
23
|
@tracked removeStructureContent = false;
|
|
24
|
+
@tracked startNumber: number | null = null;
|
|
23
25
|
|
|
24
26
|
get controller() {
|
|
25
27
|
return this.args.controller;
|
|
@@ -34,6 +36,57 @@ export default class EditorPluginsStructureCardComponent extends Component<Args>
|
|
|
34
36
|
this.controller.focus();
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
@action
|
|
40
|
+
setStructureStartNumber() {
|
|
41
|
+
if (this.startNumber) {
|
|
42
|
+
this.controller.doCommand(
|
|
43
|
+
setStructureStartNumber(this.structureTypes, this.startNumber),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
this.startNumber = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@action
|
|
51
|
+
resetStructureStartNumber() {
|
|
52
|
+
this.controller.doCommand(
|
|
53
|
+
setStructureStartNumber(this.structureTypes, null),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
this.startNumber = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get structureNumber() {
|
|
60
|
+
if (this.structure && this.currentStructureType) {
|
|
61
|
+
return this.currentStructureType.getNumber({
|
|
62
|
+
pos: this.structure.pos,
|
|
63
|
+
transaction: this.controller.mainEditorState.tr,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get structureStartNumber() {
|
|
71
|
+
if (this.structure && this.currentStructureType) {
|
|
72
|
+
return this.currentStructureType.getStartNumber({
|
|
73
|
+
pos: this.structure.pos,
|
|
74
|
+
transaction: this.controller.mainEditorState.tr,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get startNumberInputValue() {
|
|
82
|
+
return this.startNumber ?? this.structureNumber ?? '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
onStartNumberChange = (event: InputEvent) => {
|
|
86
|
+
const target = event.target as HTMLInputElement;
|
|
87
|
+
this.startNumber = parseInt(target.value);
|
|
88
|
+
};
|
|
89
|
+
|
|
37
90
|
@action
|
|
38
91
|
removeStructure(withContent: boolean) {
|
|
39
92
|
if (this.structure && this.currentStructureType) {
|
|
@@ -4,3 +4,4 @@ export { default as recalculateStructureNumbers } from './recalculate-structure-
|
|
|
4
4
|
export { default as removeStructure } from './remove-structure';
|
|
5
5
|
export { default as unwrapStructure } from './unwrap-structure';
|
|
6
6
|
export { default as wrapStructureContent } from './wrap-structure-content';
|
|
7
|
+
export { default as setStructureStartNumber } from './set-structure-start-number';
|
|
@@ -17,6 +17,13 @@ export default function recalculateStructureNumbers(
|
|
|
17
17
|
indices[i] = 1;
|
|
18
18
|
contexts[i] = parent;
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
const startNumber = spec.getStartNumber({ pos, transaction });
|
|
22
|
+
|
|
23
|
+
if (startNumber) {
|
|
24
|
+
indices[i] = startNumber;
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
spec.updateNumber({ number: indices[i], pos, transaction });
|
|
21
28
|
indices[i] += 1;
|
|
22
29
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from '@lblod/ember-rdfa-editor';
|
|
2
|
+
|
|
3
|
+
import { findAncestorOfType } from '../utils/structure';
|
|
4
|
+
import type { ArticleStructurePluginOptions } from '..';
|
|
5
|
+
import recalculateStructureNumbers from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/commands/recalculate-structure-numbers';
|
|
6
|
+
import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
|
|
7
|
+
|
|
8
|
+
const setStructureStartNumber = (
|
|
9
|
+
options: ArticleStructurePluginOptions,
|
|
10
|
+
startNumber: number | null,
|
|
11
|
+
): Command => {
|
|
12
|
+
return (state, dispatch) => {
|
|
13
|
+
const { selection, schema } = state;
|
|
14
|
+
|
|
15
|
+
const structureSpecs = options.map((type) => schema.nodes[type.name]);
|
|
16
|
+
const currentStructure = findAncestorOfType(selection, ...structureSpecs);
|
|
17
|
+
|
|
18
|
+
if (!currentStructure || currentStructure.pos === -1) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const currentStructureSpec = unwrap(
|
|
23
|
+
options.find((spec) => spec.name === currentStructure.node.type.name),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (dispatch) {
|
|
27
|
+
const transaction = state.tr;
|
|
28
|
+
|
|
29
|
+
currentStructureSpec.setStartNumber({
|
|
30
|
+
number: startNumber,
|
|
31
|
+
pos: currentStructure.pos,
|
|
32
|
+
transaction,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
recalculateStructureNumbers(transaction, ...options);
|
|
36
|
+
|
|
37
|
+
dispatch(transaction);
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default setStructureStartNumber;
|
|
@@ -38,6 +38,16 @@ export type StructureSpec = {
|
|
|
38
38
|
pos: number;
|
|
39
39
|
transaction: Transaction;
|
|
40
40
|
}) => Transaction;
|
|
41
|
+
getNumber: (args: { pos: number; transaction: Transaction }) => number | null;
|
|
42
|
+
setStartNumber: (args: {
|
|
43
|
+
number: number | null;
|
|
44
|
+
pos: number;
|
|
45
|
+
transaction: Transaction;
|
|
46
|
+
}) => Transaction;
|
|
47
|
+
getStartNumber: (args: {
|
|
48
|
+
pos: number;
|
|
49
|
+
transaction: Transaction;
|
|
50
|
+
}) => number | null;
|
|
41
51
|
content?: (args: { pos: number; state: EditorState }) => Fragment;
|
|
42
52
|
continuous: boolean;
|
|
43
53
|
limitTo?: string;
|
|
@@ -4,10 +4,15 @@ import { v4 as uuid } from 'uuid';
|
|
|
4
4
|
import {
|
|
5
5
|
ELI,
|
|
6
6
|
SAY,
|
|
7
|
-
XSD,
|
|
8
7
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
9
8
|
import { hasRDFaAttribute } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
|
|
10
9
|
import { getTranslationFunction } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/translation';
|
|
10
|
+
import {
|
|
11
|
+
getNumberAttributeFromElement,
|
|
12
|
+
getNumberAttributesFromNode,
|
|
13
|
+
getNumberDocSpecFromNode,
|
|
14
|
+
getNumberUtils,
|
|
15
|
+
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
|
|
11
16
|
|
|
12
17
|
const PLACEHOLDERS = {
|
|
13
18
|
body: 'article-structure-plugin.placeholder.paragraph.body',
|
|
@@ -27,13 +32,12 @@ export const articleParagraphSpec: StructureSpec = {
|
|
|
27
32
|
continuous: false,
|
|
28
33
|
noUnwrap: true,
|
|
29
34
|
constructor: ({ schema, number, intl, state }) => {
|
|
30
|
-
const numberConverted = number?.toString() ?? '1';
|
|
31
35
|
const translationWithDocLang = getTranslationFunction(state);
|
|
32
36
|
const node = schema.node(
|
|
33
37
|
`article_paragraph`,
|
|
34
38
|
{
|
|
35
39
|
resource: `http://data.lblod.info/paragraphs/${uuid()}`,
|
|
36
|
-
number
|
|
40
|
+
number,
|
|
37
41
|
},
|
|
38
42
|
schema.node(
|
|
39
43
|
'paragraph',
|
|
@@ -48,10 +52,7 @@ export const articleParagraphSpec: StructureSpec = {
|
|
|
48
52
|
);
|
|
49
53
|
return { node, selectionConfig: { relativePos: 1, type: 'node' } };
|
|
50
54
|
},
|
|
51
|
-
|
|
52
|
-
const numberConverted = number.toString();
|
|
53
|
-
return transaction.setNodeAttribute(pos, 'number', numberConverted);
|
|
54
|
-
},
|
|
55
|
+
...getNumberUtils(),
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
const contentSelector = `span[property~='${SAY('body').prefixed}'],
|
|
@@ -71,7 +72,13 @@ export const article_paragraph: NodeSpec = {
|
|
|
71
72
|
},
|
|
72
73
|
resource: {},
|
|
73
74
|
number: {
|
|
74
|
-
default:
|
|
75
|
+
default: 1,
|
|
76
|
+
},
|
|
77
|
+
numberDisplayStyle: {
|
|
78
|
+
default: 'decimal', // decimal, roman
|
|
79
|
+
},
|
|
80
|
+
startNumber: {
|
|
81
|
+
default: null,
|
|
75
82
|
},
|
|
76
83
|
},
|
|
77
84
|
toDOM(node) {
|
|
@@ -81,17 +88,10 @@ export const article_paragraph: NodeSpec = {
|
|
|
81
88
|
property: node.attrs.property as string,
|
|
82
89
|
typeof: node.attrs.typeof as string,
|
|
83
90
|
resource: node.attrs.resource as string,
|
|
91
|
+
...getNumberAttributesFromNode(node),
|
|
84
92
|
},
|
|
85
93
|
['span', { contenteditable: false }, '§'],
|
|
86
|
-
|
|
87
|
-
'span',
|
|
88
|
-
{
|
|
89
|
-
property: ELI('number').prefixed,
|
|
90
|
-
datatype: XSD('integer').prefixed,
|
|
91
|
-
contenteditable: false,
|
|
92
|
-
},
|
|
93
|
-
node.attrs.number,
|
|
94
|
-
],
|
|
94
|
+
getNumberDocSpecFromNode(node),
|
|
95
95
|
['span', { contenteditable: false }, '. '],
|
|
96
96
|
['span', { property: SAY('body').prefixed }, 0],
|
|
97
97
|
];
|
|
@@ -110,9 +110,14 @@ export const article_paragraph: NodeSpec = {
|
|
|
110
110
|
element.querySelector(contentSelector) &&
|
|
111
111
|
numberSpan
|
|
112
112
|
) {
|
|
113
|
+
const numberAttributes = getNumberAttributeFromElement(
|
|
114
|
+
element,
|
|
115
|
+
numberSpan,
|
|
116
|
+
);
|
|
117
|
+
|
|
113
118
|
return {
|
|
114
119
|
resource: element.getAttribute('resource'),
|
|
115
|
-
|
|
120
|
+
...numberAttributes,
|
|
116
121
|
};
|
|
117
122
|
}
|
|
118
123
|
return false;
|
|
@@ -3,14 +3,15 @@ import { StructureSpec } from '..';
|
|
|
3
3
|
import {
|
|
4
4
|
constructStructureBodyNodeSpec,
|
|
5
5
|
constructStructureNodeSpec,
|
|
6
|
+
getNumberDocSpecFromNode,
|
|
7
|
+
getNumberAttributesFromNode,
|
|
8
|
+
getNumberUtils,
|
|
6
9
|
getStructureHeaderAttrs,
|
|
7
10
|
} from '../utils/structure';
|
|
8
11
|
import { v4 as uuid } from 'uuid';
|
|
9
12
|
import {
|
|
10
|
-
ELI,
|
|
11
13
|
EXT,
|
|
12
14
|
SAY,
|
|
13
|
-
XSD,
|
|
14
15
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
15
16
|
import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
|
|
16
17
|
import { getTranslationFunction } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/translation';
|
|
@@ -32,7 +33,6 @@ export const articleSpec: StructureSpec = {
|
|
|
32
33
|
},
|
|
33
34
|
continuous: true,
|
|
34
35
|
constructor: ({ schema, number, content, intl, state }) => {
|
|
35
|
-
const numberConverted = number?.toString() ?? '1';
|
|
36
36
|
const translationWithDocLang = getTranslationFunction(state);
|
|
37
37
|
const node = schema.node(
|
|
38
38
|
`article`,
|
|
@@ -40,7 +40,7 @@ export const articleSpec: StructureSpec = {
|
|
|
40
40
|
[
|
|
41
41
|
schema.node(
|
|
42
42
|
'article_header',
|
|
43
|
-
{ level: 4, number:
|
|
43
|
+
{ level: 4, number: number ?? 1 },
|
|
44
44
|
schema.node('placeholder', {
|
|
45
45
|
placeholderText: translationWithDocLang(
|
|
46
46
|
PLACEHOLDERS.title,
|
|
@@ -76,10 +76,7 @@ export const articleSpec: StructureSpec = {
|
|
|
76
76
|
selectionConfig,
|
|
77
77
|
};
|
|
78
78
|
},
|
|
79
|
-
|
|
80
|
-
const numberConverted = number.toString();
|
|
81
|
-
return transaction.setNodeAttribute(pos + 1, 'number', numberConverted);
|
|
82
|
-
},
|
|
79
|
+
...getNumberUtils(1),
|
|
83
80
|
content: ({ pos, state }) => {
|
|
84
81
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
85
82
|
return node.child(1).content;
|
|
@@ -98,7 +95,13 @@ export const article_header: NodeSpec = {
|
|
|
98
95
|
defining: true,
|
|
99
96
|
attrs: {
|
|
100
97
|
number: {
|
|
101
|
-
default:
|
|
98
|
+
default: 1,
|
|
99
|
+
},
|
|
100
|
+
numberDisplayStyle: {
|
|
101
|
+
default: 'decimal', // decimal, roman
|
|
102
|
+
},
|
|
103
|
+
startNumber: {
|
|
104
|
+
default: null,
|
|
102
105
|
},
|
|
103
106
|
property: {
|
|
104
107
|
default: SAY('heading').prefixed,
|
|
@@ -112,17 +115,12 @@ export const article_header: NodeSpec = {
|
|
|
112
115
|
toDOM(node) {
|
|
113
116
|
return [
|
|
114
117
|
'div',
|
|
115
|
-
{
|
|
118
|
+
{
|
|
119
|
+
property: node.attrs.property as string,
|
|
120
|
+
...getNumberAttributesFromNode(node),
|
|
121
|
+
},
|
|
116
122
|
'Artikel ',
|
|
117
|
-
|
|
118
|
-
'span',
|
|
119
|
-
{
|
|
120
|
-
property: ELI('number').prefixed,
|
|
121
|
-
datatype: XSD('string').prefixed,
|
|
122
|
-
contenteditable: false,
|
|
123
|
-
},
|
|
124
|
-
node.attrs.number,
|
|
125
|
-
],
|
|
123
|
+
getNumberDocSpecFromNode(node),
|
|
126
124
|
['span', { contenteditable: false }, ': '],
|
|
127
125
|
[
|
|
128
126
|
'span',
|
|
@@ -138,9 +136,11 @@ export const article_header: NodeSpec = {
|
|
|
138
136
|
tag: 'div',
|
|
139
137
|
getAttrs(element: HTMLElement) {
|
|
140
138
|
const headerAttrs = getStructureHeaderAttrs(element);
|
|
139
|
+
|
|
141
140
|
if (headerAttrs) {
|
|
142
141
|
return headerAttrs;
|
|
143
142
|
}
|
|
143
|
+
|
|
144
144
|
return false;
|
|
145
145
|
},
|
|
146
146
|
contentElement: `span[property~='${EXT('title').prefixed}'],
|
|
@@ -2,7 +2,7 @@ import { StructureSpec } from '..';
|
|
|
2
2
|
import {
|
|
3
3
|
constructStructureBodyNodeSpec,
|
|
4
4
|
constructStructureNodeSpec,
|
|
5
|
-
|
|
5
|
+
getNumberUtils,
|
|
6
6
|
} from '../utils/structure';
|
|
7
7
|
import { v4 as uuid } from 'uuid';
|
|
8
8
|
import { SAY } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
@@ -26,7 +26,6 @@ export const chapterSpec: StructureSpec = {
|
|
|
26
26
|
removeWithContent: 'article-structure-plugin.remove-with-content.chapter',
|
|
27
27
|
},
|
|
28
28
|
constructor: ({ schema, number, content, intl, state }) => {
|
|
29
|
-
const numberConverted = romanize(number ?? 1);
|
|
30
29
|
const translationWithDocLang = getTranslationFunction(state);
|
|
31
30
|
const node = schema.node(
|
|
32
31
|
`chapter`,
|
|
@@ -34,7 +33,7 @@ export const chapterSpec: StructureSpec = {
|
|
|
34
33
|
[
|
|
35
34
|
schema.node(
|
|
36
35
|
'structure_header',
|
|
37
|
-
{ level: 4, number:
|
|
36
|
+
{ level: 4, number: number ?? 1, numberDisplayStyle: 'roman' },
|
|
38
37
|
schema.node('placeholder', {
|
|
39
38
|
placeholderText: translationWithDocLang(
|
|
40
39
|
PLACEHOLDERS.title,
|
|
@@ -70,10 +69,7 @@ export const chapterSpec: StructureSpec = {
|
|
|
70
69
|
selectionConfig,
|
|
71
70
|
};
|
|
72
71
|
},
|
|
73
|
-
|
|
74
|
-
const numberConverted = romanize(number);
|
|
75
|
-
return transaction.setNodeAttribute(pos + 1, 'number', numberConverted);
|
|
76
|
-
},
|
|
72
|
+
...getNumberUtils(1),
|
|
77
73
|
content: ({ pos, state }) => {
|
|
78
74
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
79
75
|
return node.child(1).content;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
constructStructureBodyNodeSpec,
|
|
3
3
|
constructStructureNodeSpec,
|
|
4
|
-
|
|
4
|
+
getNumberUtils,
|
|
5
5
|
} from '../utils/structure';
|
|
6
6
|
import { v4 as uuid } from 'uuid';
|
|
7
7
|
import { StructureSpec } from '..';
|
|
@@ -26,7 +26,6 @@ export const sectionSpec: StructureSpec = {
|
|
|
26
26
|
removeWithContent: 'article-structure-plugin.remove-with-content.section',
|
|
27
27
|
},
|
|
28
28
|
constructor: ({ schema, number, content, intl, state }) => {
|
|
29
|
-
const numberConverted = romanize(number || 1);
|
|
30
29
|
const translationWithDocLang = getTranslationFunction(state);
|
|
31
30
|
const node = schema.node(
|
|
32
31
|
`section`,
|
|
@@ -34,7 +33,7 @@ export const sectionSpec: StructureSpec = {
|
|
|
34
33
|
[
|
|
35
34
|
schema.node(
|
|
36
35
|
'structure_header',
|
|
37
|
-
{ level: 5, number:
|
|
36
|
+
{ level: 5, number: number ?? 1, numberDisplayStyle: 'roman' },
|
|
38
37
|
schema.node('placeholder', {
|
|
39
38
|
placeholderText: translationWithDocLang(
|
|
40
39
|
PLACEHOLDERS.title,
|
|
@@ -70,10 +69,7 @@ export const sectionSpec: StructureSpec = {
|
|
|
70
69
|
selectionConfig,
|
|
71
70
|
};
|
|
72
71
|
},
|
|
73
|
-
|
|
74
|
-
const numberConverted = romanize(number);
|
|
75
|
-
return transaction.setNodeAttribute(pos + 1, 'number', numberConverted);
|
|
76
|
-
},
|
|
72
|
+
...getNumberUtils(1),
|
|
77
73
|
content: ({ pos, state }) => {
|
|
78
74
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
79
75
|
return node.child(1).content;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { NodeSpec, PNode } from '@lblod/ember-rdfa-editor';
|
|
2
2
|
import {
|
|
3
|
-
ELI,
|
|
4
3
|
EXT,
|
|
5
4
|
SAY,
|
|
6
|
-
XSD,
|
|
7
5
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
8
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getNumberDocSpecFromNode,
|
|
8
|
+
getNumberAttributesFromNode,
|
|
9
|
+
getStructureHeaderAttrs,
|
|
10
|
+
} from '../utils/structure';
|
|
9
11
|
|
|
10
12
|
const TAG_TO_LEVEL = new Map([
|
|
11
13
|
['h1', 1],
|
|
@@ -28,7 +30,13 @@ export const structure_header: NodeSpec = {
|
|
|
28
30
|
default: SAY('heading').prefixed,
|
|
29
31
|
},
|
|
30
32
|
number: {
|
|
31
|
-
default:
|
|
33
|
+
default: 1,
|
|
34
|
+
},
|
|
35
|
+
numberDisplayStyle: {
|
|
36
|
+
default: 'decimal', // decimal, roman
|
|
37
|
+
},
|
|
38
|
+
startNumber: {
|
|
39
|
+
default: null,
|
|
32
40
|
},
|
|
33
41
|
level: {
|
|
34
42
|
default: 1,
|
|
@@ -41,16 +49,11 @@ export const structure_header: NodeSpec = {
|
|
|
41
49
|
toDOM(node) {
|
|
42
50
|
return [
|
|
43
51
|
`h${node.attrs.level as number}`,
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
datatype: XSD('string').prefixed,
|
|
50
|
-
contenteditable: false,
|
|
51
|
-
},
|
|
52
|
-
node.attrs.number,
|
|
53
|
-
],
|
|
52
|
+
{
|
|
53
|
+
property: node.attrs.property as string,
|
|
54
|
+
...getNumberAttributesFromNode(node),
|
|
55
|
+
},
|
|
56
|
+
getNumberDocSpecFromNode(node),
|
|
54
57
|
['span', { contenteditable: false }, '. '],
|
|
55
58
|
[
|
|
56
59
|
'span',
|
|
@@ -67,8 +70,12 @@ export const structure_header: NodeSpec = {
|
|
|
67
70
|
getAttrs(element: HTMLElement) {
|
|
68
71
|
const level = TAG_TO_LEVEL.get(element.tagName.toLowerCase()) ?? 6;
|
|
69
72
|
const headerAttrs = getStructureHeaderAttrs(element);
|
|
73
|
+
|
|
70
74
|
if (headerAttrs) {
|
|
71
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
level,
|
|
77
|
+
...headerAttrs,
|
|
78
|
+
};
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
return false;
|
|
@@ -2,7 +2,7 @@ import { StructureSpec } from '..';
|
|
|
2
2
|
import {
|
|
3
3
|
constructStructureBodyNodeSpec,
|
|
4
4
|
constructStructureNodeSpec,
|
|
5
|
-
|
|
5
|
+
getNumberUtils,
|
|
6
6
|
} from '../utils/structure';
|
|
7
7
|
import { v4 as uuid } from 'uuid';
|
|
8
8
|
import { SAY } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
@@ -28,7 +28,6 @@ export const subsectionSpec: StructureSpec = {
|
|
|
28
28
|
'article-structure-plugin.remove-with-content.subsection',
|
|
29
29
|
},
|
|
30
30
|
constructor: ({ schema, number, intl, content, state }) => {
|
|
31
|
-
const numberConverted = romanize(number ?? 1);
|
|
32
31
|
const translationWithDocLang = getTranslationFunction(state);
|
|
33
32
|
const node = schema.node(
|
|
34
33
|
`subsection`,
|
|
@@ -36,7 +35,7 @@ export const subsectionSpec: StructureSpec = {
|
|
|
36
35
|
[
|
|
37
36
|
schema.node(
|
|
38
37
|
'structure_header',
|
|
39
|
-
{ level: 6, number:
|
|
38
|
+
{ level: 6, number: number ?? 1, numberDisplayStyle: 'roman' },
|
|
40
39
|
schema.node('placeholder', {
|
|
41
40
|
placeholderText: translationWithDocLang(
|
|
42
41
|
PLACEHOLDERS.title,
|
|
@@ -72,10 +71,7 @@ export const subsectionSpec: StructureSpec = {
|
|
|
72
71
|
selectionConfig,
|
|
73
72
|
};
|
|
74
73
|
},
|
|
75
|
-
|
|
76
|
-
const numberConverted = romanize(number);
|
|
77
|
-
return transaction.setNodeAttribute(pos + 1, 'number', numberConverted);
|
|
78
|
-
},
|
|
74
|
+
...getNumberUtils(1),
|
|
79
75
|
content: ({ pos, state }) => {
|
|
80
76
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
81
77
|
return node.child(1).content;
|
|
@@ -2,7 +2,7 @@ import { StructureSpec } from '..';
|
|
|
2
2
|
import {
|
|
3
3
|
constructStructureBodyNodeSpec,
|
|
4
4
|
constructStructureNodeSpec,
|
|
5
|
-
|
|
5
|
+
getNumberUtils,
|
|
6
6
|
} from '../utils/structure';
|
|
7
7
|
import { v4 as uuid } from 'uuid';
|
|
8
8
|
import { SAY } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
@@ -26,7 +26,6 @@ export const titleSpec: StructureSpec = {
|
|
|
26
26
|
removeWithContent: 'article-structure-plugin.remove-with-content.title',
|
|
27
27
|
},
|
|
28
28
|
constructor: ({ schema, number, content, intl, state }) => {
|
|
29
|
-
const numberConverted = romanize(number ?? 1);
|
|
30
29
|
const translationWithDocLang = getTranslationFunction(state);
|
|
31
30
|
const node = schema.node(
|
|
32
31
|
`title`,
|
|
@@ -34,7 +33,7 @@ export const titleSpec: StructureSpec = {
|
|
|
34
33
|
[
|
|
35
34
|
schema.node(
|
|
36
35
|
'structure_header',
|
|
37
|
-
{ level: 3, number:
|
|
36
|
+
{ level: 3, number: number ?? 1, numberDisplayStyle: 'roman' },
|
|
38
37
|
schema.node('placeholder', {
|
|
39
38
|
placeholderText: translationWithDocLang(
|
|
40
39
|
PLACEHOLDERS.heading,
|
|
@@ -70,10 +69,7 @@ export const titleSpec: StructureSpec = {
|
|
|
70
69
|
selectionConfig,
|
|
71
70
|
};
|
|
72
71
|
},
|
|
73
|
-
|
|
74
|
-
const numberConverted = romanize(number);
|
|
75
|
-
return transaction.setNodeAttribute(pos + 1, 'number', numberConverted);
|
|
76
|
-
},
|
|
72
|
+
...getNumberUtils(1),
|
|
77
73
|
content: ({ pos, state }) => {
|
|
78
74
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
79
75
|
return node.child(1).content;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function romanize(num: number) {
|
|
2
|
+
if (isNaN(num)) throw new Error('Provided number is NaN');
|
|
3
|
+
const digits = String(+num).split('');
|
|
4
|
+
const key = [
|
|
5
|
+
'',
|
|
6
|
+
'C',
|
|
7
|
+
'CC',
|
|
8
|
+
'CCC',
|
|
9
|
+
'CD',
|
|
10
|
+
'D',
|
|
11
|
+
'DC',
|
|
12
|
+
'DCC',
|
|
13
|
+
'DCCC',
|
|
14
|
+
'CM',
|
|
15
|
+
'',
|
|
16
|
+
'X',
|
|
17
|
+
'XX',
|
|
18
|
+
'XXX',
|
|
19
|
+
'XL',
|
|
20
|
+
'L',
|
|
21
|
+
'LX',
|
|
22
|
+
'LXX',
|
|
23
|
+
'LXXX',
|
|
24
|
+
'XC',
|
|
25
|
+
'',
|
|
26
|
+
'I',
|
|
27
|
+
'II',
|
|
28
|
+
'III',
|
|
29
|
+
'IV',
|
|
30
|
+
'V',
|
|
31
|
+
'VI',
|
|
32
|
+
'VII',
|
|
33
|
+
'VIII',
|
|
34
|
+
'IX',
|
|
35
|
+
];
|
|
36
|
+
let roman = '';
|
|
37
|
+
let i = 3;
|
|
38
|
+
while (i--) {
|
|
39
|
+
const digit = digits.pop();
|
|
40
|
+
if (digit) {
|
|
41
|
+
roman = (key[Number(digit) + i * 10] || '') + roman;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Array(+digits.join('') + 1).join('M') + roman;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const subs: Record<string, string> = {
|
|
48
|
+
V: 'I',
|
|
49
|
+
X: 'I',
|
|
50
|
+
L: 'X',
|
|
51
|
+
C: 'X',
|
|
52
|
+
D: 'C',
|
|
53
|
+
M: 'C',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const lookup: Record<string, number> = {
|
|
57
|
+
I: 1,
|
|
58
|
+
V: 5,
|
|
59
|
+
X: 10,
|
|
60
|
+
L: 50,
|
|
61
|
+
C: 100,
|
|
62
|
+
D: 500,
|
|
63
|
+
M: 1000,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @link https://gist.github.com/briansunter/ec7af91065d79a2f790fcd76a2a08a84
|
|
68
|
+
*/
|
|
69
|
+
export function romanToInt(romanString: string) {
|
|
70
|
+
let total = 0;
|
|
71
|
+
|
|
72
|
+
for (let x = 0; x < romanString.length; x++) {
|
|
73
|
+
const fst = romanString[x];
|
|
74
|
+
const snd = romanString[x + 1];
|
|
75
|
+
if (fst === subs[snd]) {
|
|
76
|
+
total = total + lookup[snd] - lookup[fst];
|
|
77
|
+
x++;
|
|
78
|
+
} else if (!snd) {
|
|
79
|
+
total = total + lookup[fst];
|
|
80
|
+
} else {
|
|
81
|
+
total = total + lookup[fst];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return total;
|
|
85
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DOMOutputSpec,
|
|
2
3
|
NodeSpec,
|
|
3
4
|
NodeType,
|
|
4
5
|
PNode,
|
|
@@ -10,11 +11,18 @@ import {
|
|
|
10
11
|
ELI,
|
|
11
12
|
RDF,
|
|
12
13
|
SAY,
|
|
14
|
+
XSD,
|
|
13
15
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
14
16
|
import {
|
|
15
17
|
hasRDFaAttribute,
|
|
16
18
|
Resource,
|
|
17
19
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
|
|
20
|
+
import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
|
|
21
|
+
import { StructureSpec } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin';
|
|
22
|
+
import {
|
|
23
|
+
romanize,
|
|
24
|
+
romanToInt,
|
|
25
|
+
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/romanize';
|
|
18
26
|
|
|
19
27
|
export function constructStructureNodeSpec(config: {
|
|
20
28
|
type: Resource;
|
|
@@ -120,63 +128,59 @@ export function findAncestorOfType(selection: Selection, ...types: NodeType[]) {
|
|
|
120
128
|
return;
|
|
121
129
|
}
|
|
122
130
|
|
|
123
|
-
export function
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
export function getNumberAttributeFromElement(
|
|
132
|
+
containerElement: Element,
|
|
133
|
+
numberElement: Element,
|
|
134
|
+
): {
|
|
135
|
+
number: number;
|
|
136
|
+
numberDisplayStyle: string;
|
|
137
|
+
startNumber: number | null;
|
|
138
|
+
} {
|
|
139
|
+
// Storing the number in the content attribute was not introduced straight away,
|
|
140
|
+
// so we need to check for both the content attribute and the textContent.
|
|
141
|
+
const contentAttribute = numberElement.getAttribute('content');
|
|
142
|
+
|
|
143
|
+
// If the content attribute is present, we can assume it is the correct number.
|
|
144
|
+
if (contentAttribute) {
|
|
129
145
|
return {
|
|
130
|
-
number:
|
|
146
|
+
number: parseInt(contentAttribute, 10),
|
|
147
|
+
...getNodeNumberAttrsFromElement(containerElement),
|
|
131
148
|
};
|
|
132
149
|
}
|
|
133
|
-
|
|
150
|
+
|
|
151
|
+
const textContentNumber = numberElement.textContent;
|
|
152
|
+
|
|
153
|
+
if (!textContentNumber) {
|
|
154
|
+
return { number: 1, ...getNodeNumberAttrsFromElement(containerElement) };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// If the textContent is a number, we can assume it is the correct number.
|
|
158
|
+
if (/^[0-9]+$/.exec(textContentNumber)) {
|
|
159
|
+
return {
|
|
160
|
+
number: parseInt(textContentNumber, 10),
|
|
161
|
+
...getNodeNumberAttrsFromElement(containerElement),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Otherwise, we assume it is a roman number.
|
|
166
|
+
return {
|
|
167
|
+
number: romanToInt(textContentNumber),
|
|
168
|
+
...getNodeNumberAttrsFromElement(containerElement),
|
|
169
|
+
numberDisplayStyle: 'roman',
|
|
170
|
+
};
|
|
134
171
|
}
|
|
135
172
|
|
|
136
|
-
export function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
'CD',
|
|
145
|
-
'D',
|
|
146
|
-
'DC',
|
|
147
|
-
'DCC',
|
|
148
|
-
'DCCC',
|
|
149
|
-
'CM',
|
|
150
|
-
'',
|
|
151
|
-
'X',
|
|
152
|
-
'XX',
|
|
153
|
-
'XXX',
|
|
154
|
-
'XL',
|
|
155
|
-
'L',
|
|
156
|
-
'LX',
|
|
157
|
-
'LXX',
|
|
158
|
-
'LXXX',
|
|
159
|
-
'XC',
|
|
160
|
-
'',
|
|
161
|
-
'I',
|
|
162
|
-
'II',
|
|
163
|
-
'III',
|
|
164
|
-
'IV',
|
|
165
|
-
'V',
|
|
166
|
-
'VI',
|
|
167
|
-
'VII',
|
|
168
|
-
'VIII',
|
|
169
|
-
'IX',
|
|
170
|
-
];
|
|
171
|
-
let roman = '';
|
|
172
|
-
let i = 3;
|
|
173
|
-
while (i--) {
|
|
174
|
-
const digit = digits.pop();
|
|
175
|
-
if (digit) {
|
|
176
|
-
roman = (key[Number(digit) + i * 10] || '') + roman;
|
|
177
|
-
}
|
|
173
|
+
export function getStructureHeaderAttrs(element: HTMLElement) {
|
|
174
|
+
const numberElement = element.querySelector(
|
|
175
|
+
`[property~="${ELI('number').prefixed}"],
|
|
176
|
+
[property~="${ELI('number').full}"]`,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
if (hasRDFaAttribute(element, 'property', SAY('heading')) && numberElement) {
|
|
180
|
+
return getNumberAttributeFromElement(element, numberElement);
|
|
178
181
|
}
|
|
179
|
-
|
|
182
|
+
|
|
183
|
+
return false;
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
export function containsOnlyPlaceholder(schema: Schema, node: PNode) {
|
|
@@ -186,3 +190,81 @@ export function containsOnlyPlaceholder(schema: Schema, node: PNode) {
|
|
|
186
190
|
node.firstChild.firstChild?.type === schema.nodes['placeholder']
|
|
187
191
|
);
|
|
188
192
|
}
|
|
193
|
+
|
|
194
|
+
export const getNumberAttributesFromNode = (node: PNode) => ({
|
|
195
|
+
['data-start-number']: node.attrs.startNumber
|
|
196
|
+
? `${node.attrs.startNumber}`
|
|
197
|
+
: null,
|
|
198
|
+
['data-number-display-style']: node.attrs.numberDisplayStyle as string,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
export const getNumberDocSpecFromNode = (node: PNode): DOMOutputSpec => [
|
|
202
|
+
'span',
|
|
203
|
+
{
|
|
204
|
+
property: ELI('number').prefixed,
|
|
205
|
+
datatype: XSD('integer').prefixed,
|
|
206
|
+
content: node.attrs.number as string,
|
|
207
|
+
contenteditable: false,
|
|
208
|
+
},
|
|
209
|
+
node.attrs.numberDisplayStyle === 'roman'
|
|
210
|
+
? romanize(node.attrs.number ?? '1')
|
|
211
|
+
: `${node.attrs.number ?? '1'}`,
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
const getNodeNumberAttrsFromElement = (element: Element) => {
|
|
215
|
+
const startNumber = element.getAttribute('data-start-number');
|
|
216
|
+
const numberDisplayStyle = element.getAttribute('data-number-display-style');
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
numberDisplayStyle: numberDisplayStyle ?? 'decimal',
|
|
220
|
+
startNumber: startNumber ? parseInt(startNumber, 10) : null,
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export const getNumberUtils = (
|
|
225
|
+
// Offset for the position of the node where the starting number is stored.
|
|
226
|
+
// For structures with `structure_header` it will usually be +1,
|
|
227
|
+
// for `articleParagraph` it is 0.
|
|
228
|
+
offset = 0,
|
|
229
|
+
): Pick<
|
|
230
|
+
StructureSpec,
|
|
231
|
+
'setStartNumber' | 'getStartNumber' | 'getNumber' | 'updateNumber'
|
|
232
|
+
> => ({
|
|
233
|
+
updateNumber: ({ number, pos, transaction }) => {
|
|
234
|
+
return transaction.setNodeAttribute(pos + offset, 'number', number);
|
|
235
|
+
},
|
|
236
|
+
getNumber: ({ pos, transaction }) => {
|
|
237
|
+
const node = unwrap(transaction.doc.nodeAt(pos + offset));
|
|
238
|
+
const number = node.attrs.number as string | number | undefined | null;
|
|
239
|
+
|
|
240
|
+
if (typeof number === 'string' && number.length > 0) {
|
|
241
|
+
return parseInt(number, 10);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (typeof number === 'number') {
|
|
245
|
+
return number;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return null;
|
|
249
|
+
},
|
|
250
|
+
getStartNumber: ({ pos, transaction }) => {
|
|
251
|
+
const node = unwrap(transaction.doc.nodeAt(pos + offset));
|
|
252
|
+
const startNumber = node.attrs.startNumber as
|
|
253
|
+
| string
|
|
254
|
+
| number
|
|
255
|
+
| undefined
|
|
256
|
+
| null;
|
|
257
|
+
|
|
258
|
+
if (typeof startNumber === 'string' && startNumber.length > 0) {
|
|
259
|
+
return parseInt(startNumber, 10);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (typeof startNumber === 'number') {
|
|
263
|
+
return startNumber;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return null;
|
|
267
|
+
},
|
|
268
|
+
setStartNumber: ({ number, pos, transaction }) =>
|
|
269
|
+
transaction.setNodeAttribute(pos + offset, 'startNumber', number),
|
|
270
|
+
});
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getRdfaAttrs,
|
|
3
|
-
NodeSpec,
|
|
4
|
-
rdfaAttrs,
|
|
5
|
-
Transaction,
|
|
6
|
-
} from '@lblod/ember-rdfa-editor';
|
|
1
|
+
import { getRdfaAttrs, NodeSpec, rdfaAttrs } from '@lblod/ember-rdfa-editor';
|
|
7
2
|
import {
|
|
8
3
|
BESLUIT,
|
|
9
4
|
ELI,
|
|
10
5
|
PROV,
|
|
11
6
|
SKOS,
|
|
12
|
-
XSD,
|
|
13
7
|
} from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
|
|
14
8
|
import { hasRDFaAttribute } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
|
|
15
9
|
import { StructureSpec } from '../../article-structure-plugin';
|
|
16
10
|
import { v4 as uuid } from 'uuid';
|
|
17
11
|
import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
|
|
18
12
|
import { getTranslationFunction } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/translation';
|
|
13
|
+
import {
|
|
14
|
+
getNumberAttributeFromElement,
|
|
15
|
+
getNumberAttributesFromNode,
|
|
16
|
+
getNumberDocSpecFromNode,
|
|
17
|
+
getNumberUtils,
|
|
18
|
+
} from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
|
|
19
19
|
|
|
20
20
|
export const besluit_title: NodeSpec = {
|
|
21
21
|
content: 'paragraph+',
|
|
@@ -183,7 +183,6 @@ export const besluitArticleStructure: StructureSpec = {
|
|
|
183
183
|
limitTo: 'besluit',
|
|
184
184
|
constructor: ({ schema, number, content, intl, state }) => {
|
|
185
185
|
const translationWithDocLang = getTranslationFunction(state);
|
|
186
|
-
const numberConverted = number?.toString() ?? '1';
|
|
187
186
|
const node = schema.node(
|
|
188
187
|
`besluit_article`,
|
|
189
188
|
{
|
|
@@ -191,7 +190,7 @@ export const besluitArticleStructure: StructureSpec = {
|
|
|
191
190
|
},
|
|
192
191
|
[
|
|
193
192
|
schema.node('besluit_article_header', {
|
|
194
|
-
number:
|
|
193
|
+
number: number ?? 1,
|
|
195
194
|
}),
|
|
196
195
|
schema.node(
|
|
197
196
|
`besluit_article_content`,
|
|
@@ -223,10 +222,7 @@ export const besluitArticleStructure: StructureSpec = {
|
|
|
223
222
|
selectionConfig,
|
|
224
223
|
};
|
|
225
224
|
},
|
|
226
|
-
|
|
227
|
-
transaction.setNodeAttribute(pos + 1, 'number', number.toString());
|
|
228
|
-
return transaction;
|
|
229
|
-
},
|
|
225
|
+
...getNumberUtils(1),
|
|
230
226
|
content: ({ pos, state }) => {
|
|
231
227
|
const node = unwrap(state.doc.nodeAt(pos));
|
|
232
228
|
return unwrap(node.lastChild).content;
|
|
@@ -240,7 +236,13 @@ export const besluit_article_header: NodeSpec = {
|
|
|
240
236
|
attrs: {
|
|
241
237
|
...rdfaAttrs,
|
|
242
238
|
number: {
|
|
243
|
-
default:
|
|
239
|
+
default: 1,
|
|
240
|
+
},
|
|
241
|
+
numberDisplayStyle: {
|
|
242
|
+
default: 'decimal', // decimal, roman
|
|
243
|
+
},
|
|
244
|
+
startNumber: {
|
|
245
|
+
default: null,
|
|
244
246
|
},
|
|
245
247
|
},
|
|
246
248
|
toDOM(node) {
|
|
@@ -249,29 +251,35 @@ export const besluit_article_header: NodeSpec = {
|
|
|
249
251
|
delete toplevelAttrs.datatype;
|
|
250
252
|
return [
|
|
251
253
|
'div',
|
|
252
|
-
{
|
|
254
|
+
{
|
|
255
|
+
...toplevelAttrs,
|
|
256
|
+
contenteditable: false,
|
|
257
|
+
...getNumberAttributesFromNode(node),
|
|
258
|
+
},
|
|
253
259
|
'Artikel ',
|
|
254
|
-
|
|
255
|
-
'span',
|
|
256
|
-
{ property: ELI('number').prefixed, datatype: XSD('string').prefixed },
|
|
257
|
-
node.attrs.number,
|
|
258
|
-
],
|
|
260
|
+
getNumberDocSpecFromNode(node),
|
|
259
261
|
];
|
|
260
262
|
},
|
|
261
263
|
parseDOM: [
|
|
262
264
|
{
|
|
263
265
|
tag: 'p,div',
|
|
264
266
|
getAttrs(element: HTMLElement) {
|
|
265
|
-
const
|
|
267
|
+
const numberElement = element.querySelector(
|
|
266
268
|
`span[property~='${ELI('number').prefixed}'],
|
|
267
269
|
span[property~='${ELI('number').full}']`,
|
|
268
270
|
);
|
|
269
|
-
|
|
271
|
+
|
|
272
|
+
const numberAttributes =
|
|
273
|
+
numberElement &&
|
|
274
|
+
getNumberAttributeFromElement(element, numberElement);
|
|
275
|
+
|
|
276
|
+
if (numberAttributes) {
|
|
270
277
|
return {
|
|
271
278
|
...getRdfaAttrs(element),
|
|
272
|
-
|
|
279
|
+
...numberAttributes,
|
|
273
280
|
};
|
|
274
281
|
}
|
|
282
|
+
|
|
275
283
|
return false;
|
|
276
284
|
},
|
|
277
285
|
},
|
|
@@ -24,16 +24,17 @@ export const emberNodeConfig: () => EmberNodeConfig = () => {
|
|
|
24
24
|
serialize(_, state) {
|
|
25
25
|
const t = getTranslationFunction(state);
|
|
26
26
|
const heading = t(
|
|
27
|
-
'template-comments-plugin.
|
|
28
|
-
'
|
|
27
|
+
'template-comments-plugin.long-title',
|
|
28
|
+
'Toelichtings- of voorbeeldbepaling',
|
|
29
29
|
);
|
|
30
30
|
|
|
31
31
|
return [
|
|
32
32
|
'div',
|
|
33
33
|
{
|
|
34
34
|
typeof: EXT('TemplateComment').prefixed,
|
|
35
|
+
class: 'say-template-comment',
|
|
35
36
|
},
|
|
36
|
-
['
|
|
37
|
+
['p', {}, ['strong', {}, heading]],
|
|
37
38
|
['div', { property: EXT('content').prefixed }, 0],
|
|
38
39
|
];
|
|
39
40
|
},
|
|
@@ -21,3 +21,38 @@ export const getTranslationFunction = (state?: EditorState) => {
|
|
|
21
21
|
return intl.t(key, { ...options, htmlSafe: false, locale });
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper function to help pick supported locales for ember-intl.
|
|
27
|
+
* Returns exact matches first, then language matches, then the default.
|
|
28
|
+
**/
|
|
29
|
+
export function decentLocaleMatch(
|
|
30
|
+
userLocales: string[] | readonly string[],
|
|
31
|
+
supportedLocales: string[],
|
|
32
|
+
defaultLocale: string,
|
|
33
|
+
) {
|
|
34
|
+
// Ember-intl lowercases locales so we can make comparisons easier by doing the same
|
|
35
|
+
const userLocs = userLocales.map((locale) => locale.toLowerCase());
|
|
36
|
+
const supportedLocs = supportedLocales.map((locale) => locale.toLowerCase());
|
|
37
|
+
|
|
38
|
+
// First find exact matches. Use a set to avoid duplicates while preserving insert order.
|
|
39
|
+
const matches = new Set(
|
|
40
|
+
userLocs.filter((locale) => supportedLocs.includes(locale)),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Then look for locales that just match based on language,
|
|
44
|
+
// e.g. match en or en-US if looking for en-GB
|
|
45
|
+
const languageMap: Record<string, string[] | undefined> = {};
|
|
46
|
+
supportedLocs.forEach((locale) => {
|
|
47
|
+
const lang = locale.split('-')[0];
|
|
48
|
+
languageMap[lang] = [...(languageMap[lang] || []), locale];
|
|
49
|
+
});
|
|
50
|
+
userLocs.forEach((locale) => {
|
|
51
|
+
const looseMatches = languageMap[locale.split('-')[0]] ?? [];
|
|
52
|
+
looseMatches.forEach((match) => matches.add(match));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Add the default so we always have something
|
|
56
|
+
matches.add(defaultLocale.toLowerCase());
|
|
57
|
+
return [...matches];
|
|
58
|
+
}
|
|
@@ -9,8 +9,15 @@ type Args = {
|
|
|
9
9
|
export default class EditorPluginsStructureCardComponent extends Component<Args> {
|
|
10
10
|
intl: IntlService;
|
|
11
11
|
removeStructureContent: boolean;
|
|
12
|
+
startNumber: number | null;
|
|
12
13
|
get controller(): SayController;
|
|
13
14
|
moveStructure(direction: 'up' | 'down'): void;
|
|
15
|
+
setStructureStartNumber(): void;
|
|
16
|
+
resetStructureStartNumber(): void;
|
|
17
|
+
get structureNumber(): number | null | undefined;
|
|
18
|
+
get structureStartNumber(): number | null | undefined;
|
|
19
|
+
get startNumberInputValue(): number | "";
|
|
20
|
+
onStartNumberChange: (event: InputEvent) => void;
|
|
14
21
|
removeStructure(withContent: boolean): void;
|
|
15
22
|
setRemoveStructureContent(value: boolean): void;
|
|
16
23
|
get structureTypes(): ArticleStructurePluginOptions;
|
package/package.json
CHANGED
|
@@ -4,3 +4,4 @@ export { default as recalculateStructureNumbers } from './recalculate-structure-
|
|
|
4
4
|
export { default as removeStructure } from './remove-structure';
|
|
5
5
|
export { default as unwrapStructure } from './unwrap-structure';
|
|
6
6
|
export { default as wrapStructureContent } from './wrap-structure-content';
|
|
7
|
+
export { default as setStructureStartNumber } from './set-structure-start-number';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Command } from '@lblod/ember-rdfa-editor';
|
|
2
|
+
import type { ArticleStructurePluginOptions } from '..';
|
|
3
|
+
declare const setStructureStartNumber: (options: ArticleStructurePluginOptions, startNumber: number | null) => Command;
|
|
4
|
+
export default setStructureStartNumber;
|
|
@@ -30,6 +30,19 @@ export type StructureSpec = {
|
|
|
30
30
|
pos: number;
|
|
31
31
|
transaction: Transaction;
|
|
32
32
|
}) => Transaction;
|
|
33
|
+
getNumber: (args: {
|
|
34
|
+
pos: number;
|
|
35
|
+
transaction: Transaction;
|
|
36
|
+
}) => number | null;
|
|
37
|
+
setStartNumber: (args: {
|
|
38
|
+
number: number | null;
|
|
39
|
+
pos: number;
|
|
40
|
+
transaction: Transaction;
|
|
41
|
+
}) => Transaction;
|
|
42
|
+
getStartNumber: (args: {
|
|
43
|
+
pos: number;
|
|
44
|
+
transaction: Transaction;
|
|
45
|
+
}) => number | null;
|
|
33
46
|
content?: (args: {
|
|
34
47
|
pos: number;
|
|
35
48
|
state: EditorState;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { NodeSpec, NodeType, PNode, Schema, Selection } from '@lblod/ember-rdfa-editor';
|
|
1
|
+
import { DOMOutputSpec, NodeSpec, NodeType, PNode, Schema, Selection } from '@lblod/ember-rdfa-editor';
|
|
2
2
|
import { Resource } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
|
|
3
|
+
import { StructureSpec } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin';
|
|
3
4
|
export declare function constructStructureNodeSpec(config: {
|
|
4
5
|
type: Resource;
|
|
5
6
|
content: string;
|
|
@@ -16,8 +17,20 @@ export declare function findAncestorOfType(selection: Selection, ...types: NodeT
|
|
|
16
17
|
depth: number;
|
|
17
18
|
node: PNode;
|
|
18
19
|
} | undefined;
|
|
20
|
+
export declare function getNumberAttributeFromElement(containerElement: Element, numberElement: Element): {
|
|
21
|
+
number: number;
|
|
22
|
+
numberDisplayStyle: string;
|
|
23
|
+
startNumber: number | null;
|
|
24
|
+
};
|
|
19
25
|
export declare function getStructureHeaderAttrs(element: HTMLElement): false | {
|
|
20
|
-
number:
|
|
26
|
+
number: number;
|
|
27
|
+
numberDisplayStyle: string;
|
|
28
|
+
startNumber: number | null;
|
|
21
29
|
};
|
|
22
|
-
export declare function romanize(num: number): string;
|
|
23
30
|
export declare function containsOnlyPlaceholder(schema: Schema, node: PNode): boolean;
|
|
31
|
+
export declare const getNumberAttributesFromNode: (node: PNode) => {
|
|
32
|
+
"data-start-number": string | null;
|
|
33
|
+
"data-number-display-style": string;
|
|
34
|
+
};
|
|
35
|
+
export declare const getNumberDocSpecFromNode: (node: PNode) => DOMOutputSpec;
|
|
36
|
+
export declare const getNumberUtils: (offset?: number) => Pick<StructureSpec, 'setStartNumber' | 'getStartNumber' | 'getNumber' | 'updateNumber'>;
|
package/translations/en-US.yaml
CHANGED
|
@@ -22,6 +22,10 @@ article-structure-plugin:
|
|
|
22
22
|
chapter: Move chapter down
|
|
23
23
|
section: Move section down
|
|
24
24
|
subsection: Move subsection down
|
|
25
|
+
start-number:
|
|
26
|
+
start-number: Start number
|
|
27
|
+
set: Set start number
|
|
28
|
+
reset: Reset
|
|
25
29
|
title:
|
|
26
30
|
structure-card: Structure Card
|
|
27
31
|
remove:
|
package/translations/nl-BE.yaml
CHANGED
|
@@ -22,6 +22,10 @@ article-structure-plugin:
|
|
|
22
22
|
section: Afdeling naar beneden verplaatsen
|
|
23
23
|
subsection: Onderafdeling naar beneden verplaatsen
|
|
24
24
|
default: Structuur naar beneden verplaatsen
|
|
25
|
+
start-number:
|
|
26
|
+
start-number: Startnummer
|
|
27
|
+
set: Startnummer instellen
|
|
28
|
+
reset: Resetten
|
|
25
29
|
title:
|
|
26
30
|
structure-card: Structuur card
|
|
27
31
|
remove:
|
package/utils/translation.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { EditorState } from '@lblod/ember-rdfa-editor';
|
|
2
2
|
import { type TOptions } from 'ember-intl/services/intl';
|
|
3
3
|
export declare const getTranslationFunction: (state?: EditorState) => (key: string, fallback: string, options?: TOptions) => string;
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to help pick supported locales for ember-intl.
|
|
6
|
+
* Returns exact matches first, then language matches, then the default.
|
|
7
|
+
**/
|
|
8
|
+
export declare function decentLocaleMatch(userLocales: string[] | readonly string[], supportedLocales: string[], defaultLocale: string): string[];
|