@lblod/ember-rdfa-editor-lblod-plugins 33.3.0 → 34.0.1

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 (31) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/addon/components/variable-plugin/codelist/edit.gts +48 -9
  3. package/addon/components/variable-plugin/codelist/{insert.ts → insert.gts} +52 -7
  4. package/addon/components/variable-plugin/codelist/nodeview.gts +49 -0
  5. package/addon/components/variable-plugin/location/edit.ts +3 -4
  6. package/addon/plugins/roadsign-regulation-plugin/actions/insert-measure.ts +25 -4
  7. package/addon/plugins/roadsign-regulation-plugin/schemas/variable.ts +1 -1
  8. package/addon/plugins/variable-plugin/actions/create-codelist-variable.ts +57 -40
  9. package/addon/plugins/variable-plugin/actions/create-legacy-codelist-variable.ts +101 -0
  10. package/addon/plugins/variable-plugin/utils/codelist-utils.ts +38 -3
  11. package/addon/plugins/variable-plugin/utils/fetch-data.ts +37 -15
  12. package/addon/plugins/variable-plugin/variables/codelist.ts +101 -175
  13. package/addon/plugins/variable-plugin/variables/legacy-codelist.ts +261 -0
  14. package/addon/utils/constants.ts +4 -0
  15. package/declarations/addon/components/variable-plugin/codelist/edit.d.ts +2 -0
  16. package/declarations/addon/components/variable-plugin/codelist/insert.d.ts +15 -9
  17. package/declarations/addon/components/variable-plugin/codelist/nodeview.d.ts +18 -0
  18. package/declarations/addon/plugins/roadsign-regulation-plugin/actions/insert-measure.d.ts +2 -1
  19. package/declarations/addon/plugins/roadsign-regulation-plugin/queries/variable.d.ts +6 -6
  20. package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/variable-instance.d.ts +25 -25
  21. package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/variable.d.ts +36 -36
  22. package/declarations/addon/plugins/variable-plugin/actions/create-codelist-variable.d.ts +20 -11
  23. package/declarations/addon/plugins/variable-plugin/actions/create-legacy-codelist-variable.d.ts +28 -0
  24. package/declarations/addon/plugins/variable-plugin/utils/codelist-utils.d.ts +7 -0
  25. package/declarations/addon/plugins/variable-plugin/utils/fetch-data.d.ts +3 -2
  26. package/declarations/addon/plugins/variable-plugin/variables/codelist.d.ts +3 -1
  27. package/declarations/addon/plugins/variable-plugin/variables/legacy-codelist.d.ts +2 -0
  28. package/declarations/addon/utils/constants.d.ts +1 -0
  29. package/docs/plugins/variable.md +1 -0
  30. package/package.json +1 -1
  31. package/addon/components/variable-plugin/codelist/insert.hbs +0 -31
@@ -1,8 +1,9 @@
1
1
  // This file contains helpers for both the codelist and location variable types
2
2
 
3
- import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
4
3
  import { CodeListOption } from './fetch-data';
5
4
  import { PNode, ProseParser, SayController } from '@lblod/ember-rdfa-editor';
5
+ import { createCodelistOptionNode } from '../actions/create-codelist-variable';
6
+ import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
6
7
 
7
8
  /**
8
9
  *
@@ -27,12 +28,46 @@ export function updateCodelistVariable(
27
28
  },
28
29
  selectedOption: CodeListOption | CodeListOption[],
29
30
  controller: SayController,
31
+ ) {
32
+ const selectedOptions = Array.isArray(selectedOption)
33
+ ? selectedOption
34
+ : [selectedOption];
35
+ const variableInstance = selectedCodelist.node.attrs['variableInstance'] as
36
+ | string
37
+ | undefined;
38
+ const codelistOptionNodes = selectedOptions.map((option) =>
39
+ createCodelistOptionNode({
40
+ schema: controller.schema,
41
+ text: option.label,
42
+ subject: option.uri,
43
+ variableInstance,
44
+ }),
45
+ );
46
+ const range = {
47
+ from: selectedCodelist.pos + 1,
48
+ to: selectedCodelist.pos + selectedCodelist.node.nodeSize - 1,
49
+ };
50
+ controller.withTransaction((tr) => {
51
+ return tr.replaceWith(range.from, range.to, codelistOptionNodes);
52
+ });
53
+ }
54
+
55
+ /**
56
+ * @deprecated use `updateCodelistVariable` instead
57
+ */
58
+ export function updateCodelistVariableLegacy(
59
+ selectedCodelist: {
60
+ node: PNode;
61
+ pos: number;
62
+ },
63
+ selectedOption: CodeListOption | CodeListOption[],
64
+ controller: SayController,
30
65
  ) {
31
66
  let htmlToInsert: string;
32
67
  if (Array.isArray(selectedOption)) {
33
- htmlToInsert = selectedOption.map((option) => option.value).join(', ');
68
+ htmlToInsert = selectedOption.map((option) => option.label).join(', ');
34
69
  } else {
35
- htmlToInsert = unwrap(selectedOption.value);
70
+ htmlToInsert = unwrap(selectedOption.label);
36
71
  }
37
72
  htmlToInsert = wrapVariableInHighlight(htmlToInsert);
38
73
  const domParser = new DOMParser();
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  executeQuery,
3
3
  QueryResult,
4
+ sparqlEscapeUri,
4
5
  } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/sparql-helpers';
5
6
 
6
7
  export type CodeListOptions = {
@@ -9,30 +10,27 @@ export type CodeListOptions = {
9
10
  };
10
11
 
11
12
  export type CodeListOption = {
12
- value?: string;
13
- label?: string;
13
+ uri: string;
14
+ label: string;
14
15
  };
15
16
 
16
17
  function generateCodeListOptionsQuery(codelistUri: string): string {
17
- const codeListOptionsQuery = `
18
+ const codeListOptionsQuery = /* sparql */ `
18
19
  PREFIX lblodMobiliteit: <http://data.lblod.info/vocabularies/mobiliteit/>
19
20
  PREFIX dct: <http://purl.org/dc/terms/>
20
21
  PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
21
22
  PREFIX schema: <http://schema.org/>
22
23
  PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
23
- SELECT DISTINCT * WHERE {
24
+ SELECT DISTINCT ?codelistOption ?label ?type ?position WHERE {
24
25
  <${codelistUri}> a lblodMobiliteit:Codelist.
25
- ?codelistOptions skos:inScheme <${codelistUri}>.
26
- ?codelistOptions skos:prefLabel ?value.
26
+ ?codelistOption skos:inScheme <${codelistUri}>.
27
+ ?codelistOption skos:prefLabel ?label.
27
28
  OPTIONAL {
28
- ?codelistOptions schema:position ?position .
29
+ ?codelistOption schema:position ?position .
29
30
  }
30
31
  OPTIONAL {
31
32
  <${codelistUri}> dct:type ?type.
32
33
  }
33
- OPTIONAL {
34
- ?codelistOptions ext:summary ?label.
35
- }
36
34
  }
37
35
  ORDER BY (!BOUND(?position)) ASC(?position)
38
36
  `;
@@ -57,11 +55,35 @@ export async function fetchCodeListOptions(
57
55
  };
58
56
  }
59
57
 
58
+ export async function fetchCodelistOption(
59
+ endpoint: string,
60
+ codelistOptionUri: string,
61
+ ): Promise<Required<CodeListOption> | undefined> {
62
+ const response = await executeQuery({
63
+ endpoint,
64
+ query: /* sparql */ `
65
+ PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
66
+ SELECT DISTINCT ?label WHERE {
67
+ ${sparqlEscapeUri(codelistOptionUri)}
68
+ skos:prefLabel ?label.
69
+ }
70
+ `,
71
+ });
72
+ const bindings = response.results.bindings;
73
+ if (!bindings.length) {
74
+ return;
75
+ }
76
+ return {
77
+ uri: codelistOptionUri,
78
+ label: bindings[0]['label'].value,
79
+ };
80
+ }
81
+
60
82
  function parseCodelistOptions(queryResult: QueryResult): CodeListOption[] {
61
83
  const bindings = queryResult.results.bindings;
62
84
  return bindings.map((binding) => ({
63
- value: binding['value']?.value,
64
- label: binding['label'] ? binding['label'].value : binding['value']?.value,
85
+ uri: binding['codelistOption'].value,
86
+ label: binding['label'].value,
65
87
  }));
66
88
  }
67
89
 
@@ -76,7 +98,7 @@ function generateCodeListsByPublisherQuery(publisher?: string): string {
76
98
  PREFIX dct: <http://purl.org/dc/terms/>
77
99
  PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
78
100
  PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
79
- SELECT DISTINCT * WHERE {
101
+ SELECT DISTINCT * WHERE {
80
102
  ?uri a lblodMobilitiet:Codelist;
81
103
  skos:prefLabel ?label.
82
104
  ${
@@ -101,7 +123,7 @@ export async function fetchCodeListsByPublisher(
101
123
  });
102
124
  const bindings = codelistsOptionsQueryResult.results.bindings;
103
125
  return bindings.map((binding) => ({
104
- uri: binding['uri']?.value,
105
- label: binding['label']?.value,
126
+ uri: binding['uri'].value,
127
+ label: binding['label'].value,
106
128
  }));
107
129
  }
@@ -1,16 +1,3 @@
1
- import {
2
- getOutgoingTriple,
3
- hasOutgoingNamedNodeTriple,
4
- hasRDFaAttribute,
5
- } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
6
- import {
7
- DCT,
8
- EXT,
9
- MOBILITEIT,
10
- RDF,
11
- VARIABLES,
12
- XSD,
13
- } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
14
1
  import {
15
2
  createEmberNodeSpec,
16
3
  createEmberNodeView,
@@ -18,215 +5,133 @@ import {
18
5
  } from '@lblod/ember-rdfa-editor/utils/ember-node';
19
6
  import {
20
7
  DOMOutputSpec,
8
+ Fragment,
21
9
  PNode,
10
+ Schema,
11
+ TagParseRule,
22
12
  getRdfaAttrs,
23
13
  rdfaAttrSpec,
24
14
  } from '@lblod/ember-rdfa-editor';
25
- import {
26
- hasRdfaVariableType,
27
- isVariable,
28
- parseLabel,
29
- parseVariableInstance,
30
- parseVariableSource,
31
- parseVariableType,
32
- } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/variable-attribute-parsers';
33
- import VariableNodeViewComponent from '@lblod/ember-rdfa-editor-lblod-plugins/components/variable-plugin/variable/nodeview';
34
15
  import type { ComponentLike } from '@glint/template';
35
- import { renderRdfaAware } from '@lblod/ember-rdfa-editor/core/schema';
16
+ import {
17
+ getRdfaContentElement,
18
+ RdfaAttrs,
19
+ renderRdfaAware,
20
+ } from '@lblod/ember-rdfa-editor/core/schema';
36
21
  import { recreateVariableUris } from '../utils/recreate-variable-uris';
37
- import { generateVariableInstanceUri } from '../utils/variable-helpers';
38
- import { createCodelistVariableAttrs } from '../actions/create-codelist-variable';
39
22
  import getClassnamesFromNode from '@lblod/ember-rdfa-editor/utils/get-classnames-from-node';
23
+ import SayNodeSpec from '@lblod/ember-rdfa-editor/core/say-node-spec';
24
+ import CodelistNodeviewComponent from '@lblod/ember-rdfa-editor-lblod-plugins/components/variable-plugin/codelist/nodeview';
25
+ import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
40
26
 
41
- const CONTENT_SELECTOR = '[data-content-container="true"]';
42
-
43
- const CONTENT_SELECTOR_LEGACY = `span[property~='${EXT('content').prefixed}'],
44
- span[property~='${EXT('content').full}']`;
45
27
  const rdfaAware = true;
46
28
 
47
- const parseDOM = [
29
+ const parseDOM: TagParseRule[] = [
48
30
  {
49
31
  tag: 'span',
50
32
  getAttrs: (node: HTMLElement) => {
51
- const attrs = getRdfaAttrs(node, { rdfaAware });
33
+ const attrs = getRdfaAttrs(node, { rdfaAware }) as RdfaAttrs;
52
34
  if (!attrs) {
53
35
  return false;
54
36
  }
55
37
  if (
56
38
  node.dataset.sayVariable &&
57
39
  node.dataset.sayVariableType === 'codelist' &&
58
- node.querySelector(CONTENT_SELECTOR)
40
+ node.dataset.sayNodeVersion === '2'
59
41
  ) {
60
42
  const label = node.dataset.label;
61
43
  const source = node.dataset.source;
62
44
  const codelist = node.dataset.codelist;
45
+ const variable = node.dataset.variable;
46
+ const variableInstance = node.dataset.variableInstance;
63
47
  const selectionStyle = node.dataset.selectionStyle;
64
- return { ...attrs, label, source, codelist, selectionStyle };
65
- }
66
- return false;
67
- },
68
- contentElement: CONTENT_SELECTOR,
69
- },
70
- ];
71
-
72
- const parseDOMLegacy = [
73
- {
74
- tag: 'span',
75
- getAttrs: (node: HTMLElement) => {
76
- const attrs = getRdfaAttrs(node, { rdfaAware });
77
- if (!attrs || attrs.rdfaNodeType !== 'resource') {
78
- return false;
79
- }
80
-
81
- if (
82
- hasOutgoingNamedNodeTriple(
83
- attrs,
84
- RDF('type'),
85
- VARIABLES('VariableInstance'),
86
- ) &&
87
- node.querySelector(CONTENT_SELECTOR) &&
88
- hasRdfaVariableType(attrs, 'codelist')
89
- ) {
90
- const variableInstanceUri = attrs.subject;
91
- const variableUri = getOutgoingTriple(attrs, VARIABLES('instanceOf'))
92
- ?.object.value;
93
- if (!variableInstanceUri || !variableUri) {
94
- return false;
95
- }
96
-
97
- const codelistUri = getOutgoingTriple(attrs, MOBILITEIT('codelijst'))
98
- ?.object.value;
99
- const sourceUri = getOutgoingTriple(attrs, DCT('source'))?.object.value;
100
- const selectionStyle = node.dataset.selectionStyle;
101
- const label = getOutgoingTriple(attrs, DCT('title'))?.object.value;
102
-
103
- return createCodelistVariableAttrs({
104
- variable: variableUri,
105
- variableInstance: variableInstanceUri,
48
+ return {
49
+ ...attrs,
106
50
  label,
107
- // These attrs are required but it's possible for older documents to get into a broken
108
- // state. We mark these as unknown so we can push the user to fix this as we can't do it.
109
- source: sourceUri,
110
- codelist: codelistUri,
51
+ source,
52
+ codelist,
111
53
  selectionStyle,
112
- });
54
+ variable,
55
+ variableInstance,
56
+ };
113
57
  }
114
58
  return false;
115
59
  },
116
- contentElement: CONTENT_SELECTOR,
117
- },
118
- {
119
- tag: 'span',
120
- getAttrs(node: HTMLElement) {
121
- const attrs = getRdfaAttrs(node, { rdfaAware });
122
- if (!attrs || attrs.rdfaNodeType !== 'resource') {
123
- return false;
60
+ getContent: (node: HTMLElement, schema: Schema) => {
61
+ const contentContainer = getRdfaContentElement(node);
62
+ if (!contentContainer) {
63
+ return Fragment.fromArray([]);
124
64
  }
125
-
126
- if (
127
- hasOutgoingNamedNodeTriple(attrs, RDF('type'), EXT('Mapping')) &&
128
- node.querySelector(CONTENT_SELECTOR) &&
129
- hasRdfaVariableType(attrs, 'codelist')
130
- ) {
131
- const variableUri = attrs.subject;
132
- const variableInstanceUri =
133
- getOutgoingTriple(attrs, EXT('instance'))?.object.value ??
134
- generateVariableInstanceUri();
135
-
136
- const codelistUri = getOutgoingTriple(attrs, EXT('codelist'))?.object
137
- .value;
138
- const sourceUri = getOutgoingTriple(attrs, DCT('source'))?.object.value;
139
- const selectionStyle = node.dataset.selectionStyle;
140
- const label = getOutgoingTriple(attrs, EXT('label'))?.object.value;
141
- return createCodelistVariableAttrs({
142
- variable: variableUri,
143
- variableInstance: variableInstanceUri,
144
- label,
145
- source: sourceUri,
146
- codelist: codelistUri,
147
- selectionStyle,
148
- });
65
+ // We only retrieve the `children` here, as it skips the textnodes,
66
+ // we only want the nodes corresponding to `codelist_option` nodes.
67
+ const children = [...contentContainer.children].filter(
68
+ (child: HTMLElement) => child.dataset.sayType === 'codelist_option',
69
+ );
70
+ if (!children.length) {
71
+ return Fragment.empty;
149
72
  }
150
- return false;
151
- },
152
- contentElement: CONTENT_SELECTOR,
153
- },
154
- {
155
- tag: 'span',
156
- getAttrs: (node: HTMLElement) => {
157
- if (
158
- isVariable(node) &&
159
- node.querySelector(CONTENT_SELECTOR_LEGACY) &&
160
- parseVariableType(node) === 'codelist'
161
- ) {
162
- const variableUri = node.getAttribute('resource');
163
- if (!variableUri) {
164
- return false;
165
- }
166
- const variableInstanceUri =
167
- parseVariableInstance(node) ?? generateVariableInstanceUri();
168
73
 
169
- const source = parseVariableSource(node) ?? undefined;
170
- const selectionStyle = node.dataset.selectionStyle;
171
- const codelistSpan = Array.from(node.children).find((el) =>
172
- hasRDFaAttribute(el, 'property', EXT('codelist')),
74
+ const contentNodes = children.map((child: HTMLElement) => {
75
+ const attrs = getRdfaAttrs(child, { rdfaAware }) as RdfaAttrs;
76
+ return schema.nodes.codelist_option.create(
77
+ attrs,
78
+ schema.text(child.textContent ?? ''),
173
79
  );
174
- const codelistUri =
175
- codelistSpan?.getAttribute('resource') ??
176
- codelistSpan?.getAttribute('content') ??
177
- undefined;
178
- const label = parseLabel(node) ?? undefined;
179
-
180
- return createCodelistVariableAttrs({
181
- variable: variableUri,
182
- variableInstance: variableInstanceUri,
183
- label,
184
- source,
185
- codelist: codelistUri,
186
- selectionStyle,
187
- });
188
- }
189
-
190
- return false;
80
+ });
81
+ return Fragment.fromArray(contentNodes);
191
82
  },
192
- contentElement: CONTENT_SELECTOR_LEGACY,
193
83
  },
194
84
  ];
195
85
 
196
86
  const toDOM = (node: PNode): DOMOutputSpec => {
197
- const { selectionStyle, label, codelist, source } = node.attrs;
198
- const onlyContentType =
199
- node.content.size === 1 && node.content.firstChild?.type;
200
- const className =
201
- onlyContentType &&
202
- onlyContentType === onlyContentType.schema.nodes['placeholder']
203
- ? ' say-variable'
204
- : '';
205
-
87
+ const {
88
+ label = 'codelist',
89
+ codelist,
90
+ source,
91
+ humanReadableContent,
92
+ selectionStyle,
93
+ variable,
94
+ variableInstance,
95
+ } = node.attrs;
96
+ const className = humanReadableContent ? '' : ' say-variable';
97
+ const codelist_option_nodes = node.content.content;
98
+ const contentArray = [];
99
+ for (let i = 0; i < codelist_option_nodes.length; i++) {
100
+ const codelist_option_node = codelist_option_nodes[i];
101
+ contentArray.push(
102
+ unwrap(codelist_option_node.type.spec.toDOM)(codelist_option_node),
103
+ );
104
+ if (i !== codelist_option_nodes.length - 1) {
105
+ contentArray.push(', ');
106
+ }
107
+ }
206
108
  return renderRdfaAware({
207
109
  renderable: node,
110
+ tag: 'span',
208
111
  attrs: {
209
112
  class: `${getClassnamesFromNode(node)}${className}`,
210
113
  'data-say-variable': 'true',
211
114
  'data-say-variable-type': 'codelist',
212
- 'data-selection-style': selectionStyle as string,
115
+ 'data-say-node-version': '2',
213
116
  'data-label': label as string | null,
214
117
  'data-codelist': codelist as string,
215
118
  'data-source': source as string,
119
+ 'data-selection-style': selectionStyle as string,
120
+ 'data-variable': variable as string,
121
+ 'data-variable-instance': variableInstance as string,
216
122
  },
217
- tag: 'span',
218
- content: 0,
123
+ contentArray: contentArray.length ? contentArray : [label],
219
124
  });
220
125
  };
221
126
 
222
127
  const emberNodeConfig: EmberNodeConfig = {
223
128
  name: 'codelist',
224
- component: VariableNodeViewComponent as unknown as ComponentLike,
129
+ component: CodelistNodeviewComponent as unknown as ComponentLike,
225
130
  inline: true,
226
131
  group: 'inline variable',
227
- content: 'inline*',
132
+ content: 'codelist_option*',
228
133
  atom: true,
229
- editable: true,
134
+ editable: false,
230
135
  recreateUriFunction: recreateVariableUris,
231
136
  draggable: false,
232
137
  needsFFKludge: true,
@@ -236,23 +141,44 @@ const emberNodeConfig: EmberNodeConfig = {
236
141
  label: {
237
142
  default: null,
238
143
  },
239
- codelist: {
240
- default: 'UNKNOWN',
241
- },
242
- source: {
243
- default: 'UNKNOWN',
244
- },
245
144
  selectionStyle: {
246
145
  default: null,
247
146
  },
248
- datatype: {
249
- default: XSD('string').namedNode,
147
+ codelist: {},
148
+ source: {},
149
+ variable: {
150
+ default: null,
151
+ },
152
+ variableInstance: {
153
+ default: null,
250
154
  },
251
155
  },
252
156
  classNames: ['say-codelist-variable'],
253
157
  toDOM,
254
- parseDOM: [...parseDOM, ...parseDOMLegacy],
158
+ parseDOM,
255
159
  };
256
160
 
257
161
  export const codelist = createEmberNodeSpec(emberNodeConfig);
258
162
  export const codelistView = createEmberNodeView(emberNodeConfig);
163
+
164
+ export const codelist_option: SayNodeSpec = {
165
+ inline: true,
166
+ atom: true,
167
+ content: 'text*',
168
+ selectable: false,
169
+ editable: false,
170
+ draggable: false,
171
+ attrs: {
172
+ ...rdfaAttrSpec({ rdfaAware }),
173
+ },
174
+ toDOM: (node) => {
175
+ return renderRdfaAware({
176
+ renderable: node,
177
+ attrs: {
178
+ 'data-say-type': 'codelist_option',
179
+ },
180
+ tag: 'span',
181
+ content: node.textContent,
182
+ });
183
+ },
184
+ };