@lblod/ember-rdfa-editor-lblod-plugins 28.0.0 → 28.1.0-dev.ed578cc3a5b1de900ca53bd1e5ebe4e950e51439

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.
Files changed (30) hide show
  1. package/.changeset/kind-cooks-cross.md +5 -0
  2. package/.changeset/lovely-carpets-grow.md +5 -0
  3. package/CHANGELOG.md +12 -0
  4. package/addon/components/besluit-type-plugin/besluit-type-form.gts +68 -0
  5. package/addon/components/besluit-type-plugin/besluit-type-select.gts +80 -0
  6. package/addon/components/besluit-type-plugin/toolbar-dropdown.gts +191 -0
  7. package/addon/components/common/documents/preview.gts +24 -6
  8. package/addon/components/common/documents/types.ts +2 -17
  9. package/addon/components/snippet-plugin/nodes/snippet.gts +1 -1
  10. package/addon/components/snippet-plugin/snippet-insert.gts +1 -1
  11. package/addon/plugins/besluit-type-plugin/utils/besluit-type-instances.ts +100 -0
  12. package/addon/plugins/besluit-type-plugin/utils/set-besluit-type.ts +57 -0
  13. package/addon/plugins/snippet-plugin/index.ts +5 -10
  14. package/addon/plugins/snippet-plugin/utils/collate-imported-resources.ts +5 -2
  15. package/app/components/besluit-type-plugin/besluit-type-form.js +1 -0
  16. package/declarations/addon/components/besluit-type-plugin/besluit-type-form.d.ts +17 -0
  17. package/declarations/addon/components/besluit-type-plugin/besluit-type-select.d.ts +15 -8
  18. package/declarations/addon/components/besluit-type-plugin/toolbar-dropdown.d.ts +8 -28
  19. package/declarations/addon/components/common/documents/preview.d.ts +2 -0
  20. package/declarations/addon/components/common/documents/types.d.ts +2 -9
  21. package/declarations/addon/plugins/besluit-type-plugin/utils/besluit-type-instances.d.ts +18 -0
  22. package/declarations/addon/plugins/besluit-type-plugin/utils/set-besluit-type.d.ts +4 -0
  23. package/declarations/addon/plugins/snippet-plugin/index.d.ts +3 -3
  24. package/package.json +1 -1
  25. package/translations/en-US.yaml +9 -7
  26. package/translations/nl-BE.yaml +12 -10
  27. package/addon/components/besluit-type-plugin/besluit-type-select.hbs +0 -32
  28. package/addon/components/besluit-type-plugin/besluit-type-select.ts +0 -29
  29. package/addon/components/besluit-type-plugin/toolbar-dropdown.hbs +0 -102
  30. package/addon/components/besluit-type-plugin/toolbar-dropdown.ts +0 -223
@@ -0,0 +1,5 @@
1
+ ---
2
+ '@lblod/ember-rdfa-editor-lblod-plugins': minor
3
+ ---
4
+
5
+ Add re-usable component for selecting a decision type
@@ -0,0 +1,5 @@
1
+ ---
2
+ '@lblod/ember-rdfa-editor-lblod-plugins': patch
3
+ ---
4
+
5
+ Fix undo behaviour when changing decision type
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @lblod/ember-rdfa-editor-lblod-plugins
2
2
 
3
+ ## 28.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#549](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/549) [`ab33ef7`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/ab33ef7e9ef6d237457db61d217f5286362ed74d) Thanks [@piemonkey](https://github.com/piemonkey)! - Change preview list to asynchronously load previews
8
+
9
+ ### Patch Changes
10
+
11
+ - [#551](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/551) [`f88d903`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/f88d903697e4f689a09cf2d364bf8c5b81bbbb19) Thanks [@lagartoverde](https://github.com/lagartoverde)! - Change number variable modal to clarify the upper number is also included in the range
12
+
13
+ - [#552](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/552) [`4cf94fd`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/4cf94fd78616a141265f09e8b403923e8018cd05) Thanks [@lagartoverde](https://github.com/lagartoverde)! - Rename "citeeropschrift" to "citaat"
14
+
3
15
  ## 28.0.0
4
16
 
5
17
  ### Major Changes
@@ -0,0 +1,68 @@
1
+ import Component from '@glimmer/component';
2
+ import { type BesluitType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/fetchBesluitTypes';
3
+ import BesluitTypeSelect from '@lblod/ember-rdfa-editor-lblod-plugins/components/besluit-type-plugin/besluit-type-select';
4
+ import { type BesluitTypeInstance } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/besluit-type-instances';
5
+
6
+ interface Sig {
7
+ Args: {
8
+ types: BesluitType[];
9
+ selectedType?: BesluitTypeInstance;
10
+ setType: (selected: BesluitTypeInstance) => void;
11
+ };
12
+ Element: HTMLDivElement;
13
+ }
14
+
15
+ export default class BesluitTypePluginBesluitTypeSelectComponent extends Component<Sig> {
16
+ updateParentType = (selected: BesluitType) => {
17
+ this.args.setType({ parent: selected });
18
+ };
19
+
20
+ updateSubType = (selected: BesluitType) => {
21
+ if (this.args.selectedType) {
22
+ this.args.setType({
23
+ parent: this.args.selectedType.parent,
24
+ subType: selected,
25
+ });
26
+ }
27
+ };
28
+
29
+ updateSubSubType = (selected: BesluitType) => {
30
+ if (this.args.selectedType) {
31
+ this.args.setType({
32
+ parent: this.args.selectedType.parent,
33
+ subType: this.args.selectedType.subType,
34
+ subSubType: selected,
35
+ });
36
+ }
37
+ };
38
+
39
+ <template>
40
+ <div ...attributes>
41
+ <BesluitTypeSelect
42
+ @fieldNameTranslation='besluit-type-plugin.dt'
43
+ @besluitTypes={{@types}}
44
+ @onchange={{this.updateParentType}}
45
+ @selected={{@selectedType.parent}}
46
+ @showWarningWhenEmpty={{false}}
47
+ />
48
+ {{#if @selectedType.parent.subTypes.length}}
49
+ <BesluitTypeSelect
50
+ @fieldNameTranslation='besluit-type-plugin.sub-type'
51
+ @besluitTypes={{@selectedType.parent.subTypes}}
52
+ @onchange={{this.updateSubType}}
53
+ @selected={{@selectedType.subType}}
54
+ @showWarningWhenEmpty={{true}}
55
+ />
56
+ {{/if}}
57
+ {{#if @selectedType.subType.subTypes.length}}
58
+ <BesluitTypeSelect
59
+ @fieldNameTranslation='besluit-type-plugin.sub-type'
60
+ @besluitTypes={{@selectedType.subType.subTypes}}
61
+ @onchange={{this.updateSubSubType}}
62
+ @selected={{@selectedType.subSubType}}
63
+ @showWarningWhenEmpty={{true}}
64
+ />
65
+ {{/if}}
66
+ </div>
67
+ </template>
68
+ }
@@ -0,0 +1,80 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import t from 'ember-intl/helpers/t';
4
+ import PowerSelect from 'ember-power-select/components/power-select';
5
+ import { v4 as uuidv4 } from 'uuid';
6
+ import AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
7
+ import AuLabel from '@appuniversum/ember-appuniversum/components/au-label';
8
+ import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/icons/alert-triangle';
9
+ import { type BesluitType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/fetchBesluitTypes';
10
+
11
+ interface Sig {
12
+ Args: {
13
+ fieldNameTranslation: string;
14
+ besluitTypes: BesluitType[];
15
+ selected?: BesluitType;
16
+ showWarningWhenEmpty: boolean;
17
+ onchange: (selected: BesluitType) => void;
18
+ };
19
+ Element: HTMLDivElement;
20
+ }
21
+
22
+ export default class BesluitTypePluginBesluitTypeSelectComponent extends Component<Sig> {
23
+ @tracked besluitTypes;
24
+
25
+ constructor(parent: unknown, args: Sig['Args']) {
26
+ super(parent, args);
27
+ this.besluitTypes = this.args.besluitTypes.sort((a, b) =>
28
+ a.label > b.label ? 1 : -1,
29
+ );
30
+ }
31
+
32
+ get showWarning() {
33
+ return this.args.showWarningWhenEmpty && !this.args.selected;
34
+ }
35
+
36
+ search = (term: string) => {
37
+ const lowerTerm = term.toLowerCase();
38
+ return this.args.besluitTypes.filter((besluitType) =>
39
+ besluitType.label.toLowerCase().includes(lowerTerm),
40
+ );
41
+ };
42
+
43
+ <template>
44
+ <div ...attributes>
45
+ {{#let (uuidv4) as |id|}}
46
+ <AuLabel for={{id}}>
47
+ {{t @fieldNameTranslation}}
48
+ </AuLabel>
49
+ <PowerSelect
50
+ id={{id}}
51
+ @renderInPlace={{true}}
52
+ @searchEnabled={{true}}
53
+ @searchMessage={{t 'besluit-type-plugin.search-message'}}
54
+ @noMatchesMessage={{t 'besluit-type-plugin.no-matches-message'}}
55
+ @search={{this.search}}
56
+ @options={{this.besluitTypes}}
57
+ @selected={{@selected}}
58
+ @onChange={{@onchange}}
59
+ as |besluitType|
60
+ >
61
+ {{besluitType.label}}
62
+ </PowerSelect>
63
+ {{/let}}
64
+ <p class='au-u-muted au-u-margin-tiny au-u-margin-bottom-small'>
65
+ {{@selected.definition}}
66
+ </p>
67
+ {{#if this.showWarning}}
68
+ <AuAlert
69
+ @icon={{AlertTriangleIcon}}
70
+ @title={{t 'besluit-type-plugin.alert-title'}}
71
+ @skin='warning'
72
+ @size='small'
73
+ class='au-u-margin-bottom-none au-u-margin-top-small'
74
+ >
75
+ <p>{{t 'besluit-type-plugin.alert-body'}}</p>
76
+ </AuAlert>
77
+ {{/if}}
78
+ </div>
79
+ </template>
80
+ }
@@ -0,0 +1,191 @@
1
+ import { tracked } from '@glimmer/tracking';
2
+ import Component from '@glimmer/component';
3
+ import { on } from '@ember/modifier';
4
+ // eslint-disable-next-line ember/no-at-ember-render-modifiers
5
+ import didUpdate from '@ember/render-modifiers/modifiers/did-update';
6
+ import { trackedFunction } from 'reactiveweb/function';
7
+ import t from 'ember-intl/helpers/t';
8
+ import AuPill from '@appuniversum/ember-appuniversum/components/au-pill';
9
+ import AuModal from '@appuniversum/ember-appuniversum/components/au-modal';
10
+ import AuLinkExternal from '@appuniversum/ember-appuniversum/components/au-link-external';
11
+ import AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
12
+ import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/icons/alert-triangle';
13
+ import { CrossIcon } from '@appuniversum/ember-appuniversum/components/icons/cross';
14
+ import { MailIcon } from '@appuniversum/ember-appuniversum/components/icons/mail';
15
+ import { CircleXIcon } from '@appuniversum/ember-appuniversum/components/icons/circle-x';
16
+ import { SayController } from '@lblod/ember-rdfa-editor';
17
+ import fetchBesluitTypes from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/fetchBesluitTypes';
18
+ import { BesluitTypePluginOptions } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin';
19
+ import { getCurrentBesluitRange } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
20
+ import {
21
+ BesluitTypeInstance,
22
+ checkBesluitTypeInstance,
23
+ mostSpecificBesluitType,
24
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/besluit-type-instances';
25
+ import BesluitTypeForm from '@lblod/ember-rdfa-editor-lblod-plugins/components/besluit-type-plugin/besluit-type-form';
26
+ import { setBesluitType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/set-besluit-type';
27
+
28
+ type Args = {
29
+ controller: SayController;
30
+ options: BesluitTypePluginOptions;
31
+ };
32
+
33
+ export default class EditorPluginsToolbarDropdownComponent extends Component<Args> {
34
+ @tracked selectedTypeInstance?: BesluitTypeInstance;
35
+ @tracked cardExpanded = false;
36
+
37
+ get controller() {
38
+ return this.args.controller;
39
+ }
40
+
41
+ types = trackedFunction(this, async () => {
42
+ const types = await fetchBesluitTypes(
43
+ this.args.options.classificatieUri,
44
+ this.args.options.endpoint,
45
+ );
46
+ return types;
47
+ });
48
+
49
+ get currentBesluitRange() {
50
+ return getCurrentBesluitRange(this.controller);
51
+ }
52
+
53
+ get showCard() {
54
+ return !!this.currentBesluitRange;
55
+ }
56
+
57
+ get selectedType() {
58
+ return (
59
+ this.selectedTypeInstance &&
60
+ mostSpecificBesluitType(this.selectedTypeInstance)
61
+ );
62
+ }
63
+
64
+ toggleCard = () => {
65
+ this.cardExpanded = !this.cardExpanded;
66
+ };
67
+
68
+ setType = (type: BesluitTypeInstance) => {
69
+ this.selectedTypeInstance = type;
70
+ this.insertIfValid();
71
+ };
72
+
73
+ updateBesluitTypes = () => {
74
+ if (!this.types.isFinished || !this.currentBesluitRange) {
75
+ return;
76
+ }
77
+ if (!this.types.value) {
78
+ console.warn('Request for besluit types failed');
79
+ return;
80
+ }
81
+ const typeInstance = checkBesluitTypeInstance(
82
+ this.controller.mainEditorState,
83
+ this.types.value,
84
+ );
85
+ if (typeInstance) {
86
+ this.selectedTypeInstance = typeInstance;
87
+ this.cardExpanded = false;
88
+ } else {
89
+ this.cardExpanded = true;
90
+ }
91
+ };
92
+
93
+ insertIfValid() {
94
+ this.controller.doCommand((state, dispatch) => {
95
+ if (!this.selectedTypeInstance || !dispatch) {
96
+ return false;
97
+ }
98
+ const { result, transaction } = setBesluitType(
99
+ state,
100
+ this.selectedTypeInstance,
101
+ );
102
+ if (result.every((ok) => ok)) {
103
+ dispatch(transaction);
104
+ return true;
105
+ }
106
+ return false;
107
+ });
108
+ }
109
+
110
+ <template>
111
+ <div
112
+ {{didUpdate this.updateBesluitTypes @controller.mainEditorState}}
113
+ {{didUpdate this.updateBesluitTypes this.types.value}}
114
+ >
115
+ {{#if this.showCard}}
116
+ {{#if this.types.isError}}
117
+ <AuPill
118
+ @skin='error'
119
+ @icon={{CircleXIcon}}
120
+ @iconAlignment='left'
121
+ class='au-c-pill--link besluit-toolbar-pill'
122
+ {{on 'click' this.toggleCard}}
123
+ title={{t 'besluit-type-plugin.insert-dt'}}
124
+ >
125
+ {{t 'besluit-type-plugin.error-short'}}
126
+ </AuPill>
127
+ {{else}}
128
+ {{#if this.selectedType.label}}
129
+ <AuPill
130
+ @skin='link'
131
+ {{on 'click' this.toggleCard}}
132
+ title={{t 'besluit-type-plugin.insert-dt'}}
133
+ >
134
+ {{t 'besluit-type-plugin.dt'}}:
135
+ {{this.selectedType.label}}
136
+ </AuPill>
137
+ {{else}}
138
+ <AuPill
139
+ @icon={{AlertTriangleIcon}}
140
+ @iconAlignment='left'
141
+ @skin='link'
142
+ {{on 'click' this.toggleCard}}
143
+ title={{t 'besluit-type-plugin.insert-dt'}}
144
+ >
145
+ {{t 'besluit-type-plugin.insert-dt'}}
146
+ </AuPill>
147
+ {{/if}}
148
+ {{/if}}
149
+ {{/if}}
150
+ {{#if this.cardExpanded}}
151
+ <AuModal
152
+ @title={{t 'besluit-type-plugin.insert-dt'}}
153
+ @closeModal={{this.toggleCard}}
154
+ @modalOpen={{true}}
155
+ class='au-c-modal--overflow'
156
+ as |Modal|
157
+ >
158
+ <Modal.Body>
159
+ {{#if this.types.isError}}
160
+ <AuAlert
161
+ @title={{t 'besluit-type-plugin.error-title'}}
162
+ @skin='error'
163
+ @icon={{CrossIcon}}
164
+ >
165
+ <p>
166
+ {{t 'besluit-type-plugin.error-first-body'}}
167
+ {{! template-lint-disable no-bare-strings }}
168
+ <AuLinkExternal
169
+ href='mailto:gelinktnotuleren@vlaanderen.be'
170
+ @icon={{MailIcon}}
171
+ @iconAlignment='left'
172
+ >
173
+ GelinktNotuleren@vlaanderen.be
174
+ </AuLinkExternal>
175
+ {{! template-lint-enable no-bare-strings }}
176
+ {{t 'besluit-type-plugin.error-rest-body'}}
177
+ </p>
178
+ </AuAlert>
179
+ {{else if this.types.value}}
180
+ <BesluitTypeForm
181
+ @types={{this.types.value}}
182
+ @selectedType={{this.selectedTypeInstance}}
183
+ @setType={{this.setType}}
184
+ />
185
+ {{/if}}
186
+ </Modal.Body>
187
+ </AuModal>
188
+ {{/if}}
189
+ </div>
190
+ </template>
191
+ }
@@ -1,4 +1,5 @@
1
1
  import AuButton from '@appuniversum/ember-appuniversum/components/au-button';
2
+ import AuLoader from '@appuniversum/ember-appuniversum/components/au-loader';
2
3
  import AuIcon from '@appuniversum/ember-appuniversum/components/au-icon';
3
4
  import { NavDownIcon } from '@appuniversum/ember-appuniversum/components/icons/nav-down';
4
5
  import { NavUpIcon } from '@appuniversum/ember-appuniversum/components/icons/nav-up';
@@ -7,6 +8,8 @@ import { on } from '@ember/modifier';
7
8
  import { action } from '@ember/object';
8
9
  import Component from '@glimmer/component';
9
10
  import { tracked } from '@glimmer/tracking';
11
+ import { htmlSafe } from '@ember/template';
12
+ import { task } from 'ember-concurrency';
10
13
  import t from 'ember-intl/helpers/t';
11
14
  import { SayController } from '@lblod/ember-rdfa-editor';
12
15
  import { PreviewableDocument } from './types';
@@ -35,6 +38,9 @@ export default class DocumentPreview<
35
38
 
36
39
  @action
37
40
  togglePreview() {
41
+ if (!this.isExpanded && this.contentTask.isIdle && !this.contentTask.last) {
42
+ this.contentTask.perform();
43
+ }
38
44
  this.isExpanded = !this.isExpanded;
39
45
  }
40
46
 
@@ -46,6 +52,14 @@ export default class DocumentPreview<
46
52
  this.args.toggleFavourite?.(this.args.doc);
47
53
  };
48
54
 
55
+ contentTask = task(async () => {
56
+ const content = await this.args.doc.content;
57
+ return content && htmlSafe(content);
58
+ });
59
+ get content() {
60
+ return this.contentTask.last?.value;
61
+ }
62
+
49
63
  <template>
50
64
  <div
51
65
  class='snippet-preview {{if this.isExpanded "snippet-preview--expanded"}}'
@@ -54,7 +68,7 @@ export default class DocumentPreview<
54
68
  <div class='snippet-preview__header'>
55
69
  <div
56
70
  role='button'
57
- title={{t 'snippet-plugin.modal.preview-button.title'}}
71
+ title={{t 'common.preview-list.preview-button.title'}}
58
72
  {{on 'click' this.togglePreview}}
59
73
  {{! template-lint-disable require-presentational-children}}
60
74
  >
@@ -86,12 +100,12 @@ export default class DocumentPreview<
86
100
  </div>
87
101
  <div
88
102
  role='button'
89
- title={{t 'snippet-plugin.modal.select-button.title'}}
103
+ title={{t 'common.preview-list.select-button.title'}}
90
104
  {{on 'click' this.onInsert}}
91
105
  {{! template-lint-disable require-presentational-children}}
92
106
  >
93
107
  <AuButton class='snippet-preview__insert-button' @skin='naked'>
94
- {{t 'snippet-plugin.modal.select-button.label'}}
108
+ {{t 'common.preview-list.select-button.label'}}
95
109
  </AuButton>
96
110
  </div>
97
111
 
@@ -100,10 +114,14 @@ export default class DocumentPreview<
100
114
  <div
101
115
  class='say-editor say-content rdfa-annotations rdfa-annotations-highlight rdfa-annotations-hover snippet-preview__content'
102
116
  >
103
- {{#if @doc.content}}
104
- {{@doc.content}}
117
+ {{#if this.content}}
118
+ {{this.content}}
119
+ {{else if this.contentTask.isRunning}}
120
+ <AuLoader @hideMessage={{true}}>
121
+ {{t 'common.search.loading'}}
122
+ </AuLoader>
105
123
  {{else}}
106
- <p class='au-u-italic'>{{t 'snippet-plugin.modal.no-content'}}</p>
124
+ <p class='au-u-italic'>{{t 'common.preview-list.no-content'}}</p>
107
125
  {{/if}}
108
126
  </div>
109
127
  {{/if}}
@@ -1,19 +1,4 @@
1
- import { htmlSafe } from '@ember/template';
2
-
3
- import { optionMapOr } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
4
- import { SafeString } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/types';
5
-
6
- interface PreviewableDocumentArgs {
1
+ export interface PreviewableDocument {
7
2
  title: string | null;
8
- content: string | null;
9
- }
10
-
11
- export class PreviewableDocument {
12
- content: SafeString | null;
13
- title: string | null;
14
-
15
- constructor({ title, content }: PreviewableDocumentArgs) {
16
- this.content = optionMapOr(null, htmlSafe, content);
17
- this.title = title;
18
- }
3
+ content: string | Promise<string | null> | null;
19
4
  }
@@ -197,7 +197,7 @@ export default class SnippetNode extends Component<Signature> {
197
197
  }
198
198
  this.controller.doCommand(
199
199
  insertSnippet({
200
- content: snippet.content?.toHTML() ?? '',
200
+ content: snippet.content ?? '',
201
201
  title: snippet.title ?? '',
202
202
  listProperties: {
203
203
  placeholderId: this.node.attrs.placeholderId,
@@ -64,7 +64,7 @@ export default class SnippetInsertComponent extends Component<Sig> {
64
64
  if (this.args.listProperties) {
65
65
  this.controller.doCommand(
66
66
  insertSnippet({
67
- content: snippet.content?.toHTML() ?? '',
67
+ content: snippet.content ?? '',
68
68
  title: snippet.title ?? '',
69
69
  listProperties: this.args.listProperties,
70
70
  allowMultipleSnippets: this.args.allowMultipleSnippets,
@@ -0,0 +1,100 @@
1
+ import { type EditorState } from '@lblod/ember-rdfa-editor';
2
+ import { getOutgoingTripleList } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
3
+ import { getCurrentBesluitRange } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
4
+ import { RDF } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
5
+ import { type BesluitType } from './fetchBesluitTypes';
6
+ import { type NamedNodeTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
7
+
8
+ export interface BesluitTypeInstance {
9
+ parent: BesluitType;
10
+ subType?: BesluitType;
11
+ subSubType?: BesluitType;
12
+ }
13
+
14
+ export function extractBesluitTypeUris(editorState: EditorState): string[] {
15
+ const besluitRange = getCurrentBesluitRange(editorState);
16
+ if (!besluitRange) {
17
+ return [];
18
+ }
19
+ return getOutgoingTripleList(besluitRange.node.attrs, RDF('type'))
20
+ .filter(
21
+ (type) =>
22
+ type.object.termType === 'NamedNode' &&
23
+ type.object.value.includes(
24
+ 'https://data.vlaanderen.be/id/concept/BesluitType/',
25
+ ),
26
+ )
27
+ .map((type: NamedNodeTriple) => type?.object.value);
28
+ }
29
+
30
+ /**
31
+ * Finds a decision type in the document and checks that it represents a valid decision type
32
+ * according to the list of types passed in.
33
+ */
34
+ export function checkBesluitTypeInstance(
35
+ editorState: EditorState,
36
+ types: BesluitType[],
37
+ ): BesluitTypeInstance | false {
38
+ const besluitTypes = extractBesluitTypeUris(editorState);
39
+
40
+ if (besluitTypes.length === 0) {
41
+ return false;
42
+ } else if (besluitTypes.length !== 1) {
43
+ console.warn(
44
+ "More than one decision type found for document, we don't support this and will just take the first one",
45
+ besluitTypes,
46
+ );
47
+ }
48
+ const typeHierarchy = findBesluitTypeHierarchy(types, besluitTypes[0]);
49
+
50
+ return (
51
+ !!typeHierarchy && {
52
+ parent: typeHierarchy[0],
53
+ subType: typeHierarchy[1],
54
+ subSubType: typeHierarchy[2],
55
+ }
56
+ );
57
+ }
58
+
59
+ function findBesluitTypeHierarchy(
60
+ types: BesluitType[],
61
+ uri: string,
62
+ ): BesluitType[] | undefined {
63
+ for (const type of types) {
64
+ if (type.uri === uri) {
65
+ return [type];
66
+ } else if (type.subTypes?.length) {
67
+ const subTypes = findBesluitTypeHierarchy(type.subTypes, uri);
68
+ if (subTypes) {
69
+ return [type, ...subTypes];
70
+ }
71
+ }
72
+ }
73
+ return;
74
+ }
75
+
76
+ /**
77
+ * Checks that the passed type instance has all of the necessary sub-types selected (and no more)
78
+ */
79
+ export function isValidTypeChoice({
80
+ parent,
81
+ subType,
82
+ subSubType,
83
+ }: BesluitTypeInstance) {
84
+ if (!parent.subTypes || parent.subTypes.length === 0) {
85
+ return !subType && !subSubType;
86
+ }
87
+ if (!subType) {
88
+ return false;
89
+ }
90
+ if (!subType.subTypes || subType.subTypes.length === 0) {
91
+ return !subSubType;
92
+ }
93
+ return !!subSubType;
94
+ }
95
+
96
+ export function mostSpecificBesluitType(
97
+ typeInstance: BesluitTypeInstance,
98
+ ): BesluitType {
99
+ return typeInstance.subSubType ?? typeInstance.subType ?? typeInstance.parent;
100
+ }
@@ -0,0 +1,57 @@
1
+ import { type EditorState } from '@lblod/ember-rdfa-editor';
2
+ import {
3
+ transactionCombinator,
4
+ type TransactionCombinatorResult,
5
+ } from '@lblod/ember-rdfa-editor/utils/transaction-utils';
6
+ import {
7
+ addPropertyToNode,
8
+ removePropertyFromNode,
9
+ } from '@lblod/ember-rdfa-editor/utils/rdfa-utils';
10
+ import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
11
+ import { getCurrentBesluitURI } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
12
+ import {
13
+ extractBesluitTypeUris,
14
+ isValidTypeChoice,
15
+ mostSpecificBesluitType,
16
+ type BesluitTypeInstance,
17
+ } from './besluit-type-instances';
18
+ import { RDF } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
19
+
20
+ export function setBesluitType(
21
+ initialState: EditorState,
22
+ typeInstance: BesluitTypeInstance,
23
+ ): TransactionCombinatorResult<boolean> {
24
+ const transaction = initialState.tr;
25
+
26
+ const resource = getCurrentBesluitURI(initialState);
27
+ if (!resource || !isValidTypeChoice(typeInstance)) {
28
+ return {
29
+ result: [false],
30
+ initialState,
31
+ transaction,
32
+ transactions: [transaction],
33
+ };
34
+ }
35
+ const existingTypeUris = extractBesluitTypeUris(initialState);
36
+ const monads = existingTypeUris.map((existingUri) => {
37
+ return removePropertyFromNode({
38
+ resource,
39
+ property: {
40
+ predicate: RDF('type').full,
41
+ object: sayDataFactory.namedNode(existingUri),
42
+ },
43
+ });
44
+ });
45
+ monads.push(
46
+ addPropertyToNode({
47
+ resource,
48
+ property: {
49
+ predicate: RDF('type').full,
50
+ object: sayDataFactory.namedNode(
51
+ mostSpecificBesluitType(typeInstance).uri,
52
+ ),
53
+ },
54
+ }),
55
+ );
56
+ return transactionCombinator<boolean>(initialState)(monads);
57
+ }
@@ -1,11 +1,6 @@
1
- import { htmlSafe } from '@ember/template';
2
-
3
- import {
4
- type Option,
5
- optionMapOr,
6
- } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
1
+ import { PreviewableDocument } from '@lblod/ember-rdfa-editor-lblod-plugins/components/common/documents/types';
2
+ import { type Option } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
7
3
  import { dateValue } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
8
- import { SafeString } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/types';
9
4
 
10
5
  export const DEFAULT_CONTENT_STRING = 'block+';
11
6
 
@@ -21,13 +16,13 @@ interface SnippetArgs {
21
16
  content: string | null;
22
17
  }
23
18
 
24
- export class Snippet {
25
- content: SafeString | null;
19
+ export class Snippet implements PreviewableDocument {
20
+ content: string | null;
26
21
  createdOn: string | null;
27
22
  title: string | null;
28
23
 
29
24
  constructor({ title, createdOn, content }: SnippetArgs) {
30
- this.content = optionMapOr(null, htmlSafe, content);
25
+ this.content = content;
31
26
  this.createdOn = dateValue(createdOn ?? undefined);
32
27
  this.title = title;
33
28
  }