@lblod/ember-rdfa-editor-lblod-plugins 8.2.2 → 8.4.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.
Files changed (63) hide show
  1. package/.woodpecker/.test.yml +5 -0
  2. package/CHANGELOG.md +31 -1
  3. package/addon/components/citation-plugin/citations/search-modal.hbs +18 -41
  4. package/addon/components/citation-plugin/citations/search-modal.ts +0 -17
  5. package/addon/components/document-title-plugin/insert-title-card.hbs +5 -0
  6. package/addon/components/document-title-plugin/insert-title-card.ts +41 -0
  7. package/addon/components/pagination/pagination-view.hbs +39 -0
  8. package/addon/components/snippet-plugin/helpers/alert-load-error.hbs +22 -0
  9. package/addon/components/snippet-plugin/helpers/alert-no-items.hbs +8 -0
  10. package/addon/components/snippet-plugin/search-modal.hbs +83 -0
  11. package/addon/components/snippet-plugin/search-modal.ts +97 -0
  12. package/addon/components/snippet-plugin/snippet-insert.hbs +17 -0
  13. package/addon/components/snippet-plugin/snippet-insert.ts +50 -0
  14. package/addon/components/snippet-plugin/snippets/snippet-list.hbs +12 -0
  15. package/addon/components/snippet-plugin/snippets/snippet-preview.hbs +27 -0
  16. package/addon/components/snippet-plugin/snippets/snippet-preview.ts +28 -0
  17. package/addon/helpers/pagination.ts +40 -0
  18. package/addon/plugins/article-structure-plugin/commands/insert-structure.ts +2 -79
  19. package/addon/plugins/citation-plugin/utils/vlaamse-codex.ts +4 -34
  20. package/addon/plugins/document-title-plugin/commands/insert-document-title.ts +45 -0
  21. package/addon/plugins/document-title-plugin/nodes/document-title.ts +36 -0
  22. package/addon/plugins/document-title-plugin/nodes/index.ts +1 -0
  23. package/addon/plugins/snippet-plugin/index.ts +27 -0
  24. package/addon/plugins/snippet-plugin/utils/fetch-data.ts +96 -0
  25. package/addon/plugins/variable-plugin/nodes.ts +15 -11
  26. package/addon/plugins/variable-plugin/utils/fetch-data.ts +6 -6
  27. package/addon/utils/_private/find-insertion-range.ts +77 -0
  28. package/addon/utils/sparql-helpers.ts +28 -6
  29. package/addon/utils/strings.ts +34 -0
  30. package/addon/utils/types.ts +3 -0
  31. package/app/components/document-title-plugin/insert-title-card.js +1 -0
  32. package/app/components/pagination/pagination-view.js +1 -0
  33. package/app/components/snippet-plugin/helpers/alert-load-error.js +1 -0
  34. package/app/components/snippet-plugin/helpers/alert-no-items.js +1 -0
  35. package/app/components/snippet-plugin/search-modal.js +1 -0
  36. package/app/components/snippet-plugin/snippet-insert.js +1 -0
  37. package/app/components/snippet-plugin/snippets/snippet-list.js +1 -0
  38. package/app/components/snippet-plugin/snippets/snippet-preview.js +1 -0
  39. package/app/helpers/pagination.js +4 -0
  40. package/app/styles/document-title-plugin.scss +9 -0
  41. package/app/styles/snippet-plugin.scss +66 -0
  42. package/components/besluit-type-plugin/toolbar-dropdown.d.ts +1 -1
  43. package/components/citation-plugin/citations/search-modal.d.ts +0 -4
  44. package/components/document-title-plugin/insert-title-card.d.ts +12 -0
  45. package/components/snippet-plugin/search-modal.d.ts +22 -0
  46. package/components/snippet-plugin/snippet-insert.d.ts +16 -0
  47. package/components/snippet-plugin/snippets/snippet-preview.d.ts +14 -0
  48. package/helpers/pagination.d.ts +25 -0
  49. package/package.json +5 -5
  50. package/plugins/document-title-plugin/commands/insert-document-title.d.ts +6 -0
  51. package/plugins/document-title-plugin/nodes/document-title.d.ts +2 -0
  52. package/plugins/document-title-plugin/nodes/index.d.ts +1 -0
  53. package/plugins/snippet-plugin/index.d.ts +16 -0
  54. package/plugins/snippet-plugin/utils/fetch-data.d.ts +18 -0
  55. package/plugins/table-of-contents-plugin/nodes/table-of-contents.d.ts +1 -1
  56. package/plugins/variable-plugin/nodes.d.ts +3 -3
  57. package/translations/en-US.yaml +28 -0
  58. package/translations/nl-BE.yaml +28 -1
  59. package/tsconfig.json +5 -13
  60. package/utils/_private/find-insertion-range.d.ts +11 -0
  61. package/utils/sparql-helpers.d.ts +11 -4
  62. package/utils/strings.d.ts +2 -0
  63. package/utils/types.d.ts +2 -0
@@ -2,19 +2,13 @@ import {
2
2
  Command,
3
3
  Fragment,
4
4
  NodeSelection,
5
- NodeType,
6
- PNode,
7
- Schema,
8
- Selection,
9
5
  TextSelection,
10
6
  } from '@lblod/ember-rdfa-editor';
11
7
  import recalculateStructureNumbers from './recalculate-structure-numbers';
12
8
  import { StructureSpec } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin';
13
9
  import wrapStructureContent from './wrap-structure-content';
14
10
  import IntlService from 'ember-intl/services/intl';
15
- import { findNodes } from '@lblod/ember-rdfa-editor/utils/position-utils';
16
- import { containsOnlyPlaceholder } from '../utils/structure';
17
- import { findParentNodeOfType } from '@curvenote/prosemirror-utils';
11
+ import { findInsertionRange } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/_private/find-insertion-range';
18
12
 
19
13
  const insertStructure = (
20
14
  structureSpec: StructureSpec,
@@ -28,7 +22,7 @@ const insertStructure = (
28
22
  }
29
23
  const insertionRange = findInsertionRange({
30
24
  doc,
31
- selection,
25
+ $from: selection.$from,
32
26
  nodeType: schema.nodes[structureSpec.name],
33
27
  schema,
34
28
  limitTo: structureSpec.limitTo,
@@ -65,75 +59,4 @@ const insertStructure = (
65
59
  };
66
60
  };
67
61
 
68
- function findInsertionRange(args: {
69
- doc: PNode;
70
- selection: Selection;
71
- nodeType: NodeType;
72
- schema: Schema;
73
- limitTo?: string;
74
- }) {
75
- const { doc, selection, nodeType, schema, limitTo } = args;
76
- const { $from } = selection;
77
- for (let currentDepth = $from.depth; currentDepth >= 0; currentDepth--) {
78
- const currentAncestor = $from.node(currentDepth);
79
- const index = $from.index(currentDepth);
80
- if (currentAncestor.canReplaceWith(index, index, nodeType)) {
81
- if (containsOnlyPlaceholder(schema, currentAncestor)) {
82
- return { from: $from.start(currentDepth), to: $from.end(currentDepth) };
83
- } else {
84
- const insertPos = $from.after(currentDepth + 1);
85
- return { from: insertPos, to: insertPos };
86
- }
87
- }
88
- }
89
- const limitContainer = limitTo
90
- ? findParentNodeOfType(schema.nodes[limitTo])(selection)
91
- : null;
92
-
93
- const limitContainerRange = limitContainer
94
- ? {
95
- from: limitContainer.pos,
96
- to: limitContainer.pos + limitContainer.node.nodeSize,
97
- }
98
- : { from: 0, to: doc.nodeSize };
99
- const filterFunction = ({ from, to }: { from: number; to: number }) => {
100
- if (from >= limitContainerRange.from && to <= limitContainerRange.to) {
101
- const node = doc.nodeAt(from);
102
- if (node) {
103
- if (node.canReplaceWith(node.childCount, node.childCount, nodeType)) {
104
- return true;
105
- }
106
- }
107
- }
108
- return false;
109
- };
110
- const nextContainerRange =
111
- findNodes({
112
- doc,
113
- start: selection.from,
114
- visitParentUpwards: true,
115
- reverse: false,
116
- filter: filterFunction,
117
- }).next().value ??
118
- findNodes({
119
- doc,
120
- start: selection.from,
121
- visitParentUpwards: true,
122
- reverse: true,
123
- filter: filterFunction,
124
- }).next().value;
125
- if (nextContainerRange) {
126
- const { from, to } = nextContainerRange;
127
- const containerNode = doc.nodeAt(from);
128
- if (containerNode) {
129
- if (containsOnlyPlaceholder(schema, containerNode)) {
130
- return { from: from + 1, to: to - 1 };
131
- } else {
132
- return { from: to - 1, to: to - 1 };
133
- }
134
- }
135
- }
136
- return null;
137
- }
138
-
139
62
  export default insertStructure;
@@ -1,9 +1,12 @@
1
1
  import { LEGISLATION_TYPE_CONCEPTS } from './legislation-types';
2
- import { warn } from '@ember/debug';
3
2
  import {
4
3
  Option,
5
4
  optionMapOr,
6
5
  } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
6
+ import {
7
+ dateValue,
8
+ escapeValue,
9
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
7
10
 
8
11
  interface DecisionArgs {
9
12
  uri: string;
@@ -470,39 +473,6 @@ function cleanCaches() {
470
473
  fetchArticlesMemory.clear();
471
474
  }
472
475
 
473
- function escapeValue(value?: string) {
474
- if (value) {
475
- const shadowDomElement = document.createElement('textarea');
476
- shadowDomElement.innerHTML = value;
477
- return shadowDomElement.textContent;
478
- } else {
479
- return null;
480
- }
481
- }
482
-
483
- function dateValue(value?: string): string | null {
484
- if (value) {
485
- try {
486
- return new Intl.DateTimeFormat('nl-BE').format(
487
- new Date(Date.parse(value))
488
- );
489
- } catch (e) {
490
- let message: string;
491
- if (e instanceof Error) {
492
- message = e.message;
493
- } else {
494
- message = e as string;
495
- }
496
- warn(`Error parsing date ${value}: ${message}`, {
497
- id: 'date-parsing-error',
498
- });
499
- return null;
500
- }
501
- } else {
502
- return null;
503
- }
504
- }
505
-
506
476
  async function executeCountQuery({
507
477
  query,
508
478
  config,
@@ -0,0 +1,45 @@
1
+ import { Command } from '@lblod/ember-rdfa-editor';
2
+ import { findInsertionRange } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/_private/find-insertion-range';
3
+ import { v4 as uuid } from 'uuid';
4
+
5
+ interface InsertDocumentTitleArgs {
6
+ placeholder: string;
7
+ }
8
+ export default function insertDocumentTitle({
9
+ placeholder,
10
+ }: InsertDocumentTitleArgs): Command {
11
+ return function (state, dispatch) {
12
+ const { schema } = state;
13
+ const insertionRange = findInsertionRange({
14
+ doc: state.doc,
15
+ $from: state.doc.resolve(0),
16
+ nodeType: schema.nodes.document_title,
17
+ schema,
18
+ });
19
+ if (!insertionRange) {
20
+ return false;
21
+ }
22
+
23
+ if (dispatch) {
24
+ const tr = state.tr;
25
+ tr.replaceWith(
26
+ insertionRange.from,
27
+ insertionRange.to,
28
+ schema.node(
29
+ 'document_title',
30
+ { __rdfaId: uuid() },
31
+ schema.node(
32
+ 'paragraph',
33
+ null,
34
+ schema.node('placeholder', {
35
+ placeholderText: placeholder,
36
+ })
37
+ )
38
+ )
39
+ );
40
+ dispatch(tr);
41
+ }
42
+
43
+ return true;
44
+ };
45
+ }
@@ -0,0 +1,36 @@
1
+ import { NodeSpec, getRdfaAttrs, rdfaAttrs } from '@lblod/ember-rdfa-editor';
2
+
3
+ import { ELI } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
4
+
5
+ import { hasRDFaAttribute } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
6
+
7
+ export const document_title: NodeSpec = {
8
+ content: 'paragraph{1}',
9
+ inline: false,
10
+ defining: true,
11
+ canSplit: false,
12
+ group: '',
13
+ attrs: {
14
+ ...rdfaAttrs,
15
+ property: {
16
+ default: 'eli:title',
17
+ },
18
+ datatype: {
19
+ default: 'xsd:string',
20
+ },
21
+ },
22
+ toDOM(node) {
23
+ return ['h4', node.attrs, 0];
24
+ },
25
+ parseDOM: [
26
+ {
27
+ tag: 'h1,h2,h3,h4,h5',
28
+ getAttrs(element: HTMLElement) {
29
+ if (hasRDFaAttribute(element, 'property', ELI('title'))) {
30
+ return getRdfaAttrs(element);
31
+ }
32
+ return false;
33
+ },
34
+ },
35
+ ],
36
+ };
@@ -0,0 +1 @@
1
+ export { document_title } from './document-title';
@@ -0,0 +1,27 @@
1
+ import { htmlSafe } from '@ember/template';
2
+
3
+ import { optionMapOr } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
4
+ import { dateValue } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
5
+ import { SafeString } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/types';
6
+
7
+ export type SnippetPluginConfig = {
8
+ endpoint: string;
9
+ };
10
+
11
+ interface SnippetArgs {
12
+ title: string | null;
13
+ createdOn: string | null;
14
+ content: string | null;
15
+ }
16
+
17
+ export class Snippet {
18
+ content: SafeString | null;
19
+ createdOn: string | null;
20
+ title: string | null;
21
+
22
+ constructor({ title, createdOn, content }: SnippetArgs) {
23
+ this.content = optionMapOr(null, htmlSafe, content);
24
+ this.createdOn = dateValue(createdOn ?? undefined);
25
+ this.title = title;
26
+ }
27
+ }
@@ -0,0 +1,96 @@
1
+ import {
2
+ executeCountQuery,
3
+ executeQuery,
4
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/sparql-helpers';
5
+ import { Snippet } from '../index';
6
+
7
+ type Filter = { name?: string };
8
+ type Pagination = { pageNumber: number; pageSize: number };
9
+
10
+ const buildCountQuery = ({ name }: Filter) => {
11
+ return `
12
+ PREFIX dct: <http://purl.org/dc/terms/>
13
+ PREFIX pav: <http://purl.org/pav/>
14
+ PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
15
+
16
+ SELECT (COUNT(?snippetDocument) AS ?count)
17
+ WHERE {
18
+ ?snippetList a ext:SnippetList ;
19
+ ext:hasSnippet/pav:hasCurrentVersion ?snippetDocument .
20
+ ?snippetDocument dct:title ?title ;
21
+ ext:editorDocumentContent ?content ;
22
+ pav:createdOn ?createdOn .
23
+ ${name ? `FILTER (CONTAINS(LCASE(?title), "${name}"))` : ''}
24
+ }
25
+ `;
26
+ };
27
+
28
+ const buildFetchQuery = ({
29
+ filter: { name },
30
+ pagination: { pageSize, pageNumber },
31
+ }: {
32
+ filter: Filter;
33
+ pagination: Pagination;
34
+ }) => {
35
+ return `
36
+ PREFIX dct: <http://purl.org/dc/terms/>
37
+ PREFIX pav: <http://purl.org/pav/>
38
+ PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
39
+
40
+ SELECT DISTINCT ?title ?content ?createdOn
41
+ WHERE {
42
+ ?snippetList a ext:SnippetList ;
43
+ ext:hasSnippet/pav:hasCurrentVersion ?snippetDocument .
44
+ ?snippetDocument dct:title ?title ;
45
+ ext:editorDocumentContent ?content ;
46
+ pav:createdOn ?createdOn .
47
+ ${name ? `FILTER (CONTAINS(LCASE(?title), "${name}"))` : ''}
48
+ }
49
+ ORDER BY DESC(?createdOn) LIMIT ${pageSize} OFFSET ${
50
+ pageNumber * pageSize
51
+ }
52
+ `;
53
+ };
54
+
55
+ export const fetchSnippets = async ({
56
+ endpoint,
57
+ abortSignal,
58
+ filter,
59
+ pagination,
60
+ }: {
61
+ endpoint: string;
62
+ abortSignal: AbortSignal;
63
+ filter: Filter;
64
+ pagination: Pagination;
65
+ }) => {
66
+ const totalCount = await executeCountQuery({
67
+ endpoint,
68
+ query: buildCountQuery(filter),
69
+ abortSignal,
70
+ });
71
+
72
+ if (totalCount === 0) {
73
+ return { totalCount, results: [] };
74
+ }
75
+
76
+ const queryResult = await executeQuery<{
77
+ title: { value: string };
78
+ createdOn: { value: string };
79
+ content: { value: string };
80
+ }>({
81
+ endpoint,
82
+ query: buildFetchQuery({ filter, pagination }),
83
+ abortSignal,
84
+ });
85
+
86
+ const results = queryResult.results.bindings.map(
87
+ (binding) =>
88
+ new Snippet({
89
+ title: binding.title?.value,
90
+ createdOn: binding.createdOn?.value,
91
+ content: binding.content?.value,
92
+ })
93
+ );
94
+
95
+ return { totalCount, results };
96
+ };
@@ -73,20 +73,19 @@ export const contentToDom = ({
73
73
  type,
74
74
  node,
75
75
  }: {
76
- content: string;
76
+ content: string | null;
77
77
  type: string;
78
78
  node: PNode;
79
79
  }) => {
80
80
  if (type === 'number') {
81
- if (
82
- node.attrs[WRITTEN_NUMBER_PNODE_KEY] ||
83
- Number.isNaN(Number(content)) ||
84
- content === null ||
85
- content === ''
86
- ) {
87
- return n2words(Number(content), { lang: 'nl' });
81
+ if (!Number.isNaN(Number(content)) && content !== null && content !== '') {
82
+ if (node.attrs[WRITTEN_NUMBER_PNODE_KEY]) {
83
+ return n2words(Number(content), { lang: 'nl' });
84
+ } else {
85
+ return content;
86
+ }
88
87
  } else {
89
- return content;
88
+ return 'Voeg getal in';
90
89
  }
91
90
  } else {
92
91
  return content;
@@ -137,7 +136,10 @@ export const parseAttributes = (node: HTMLElement): false | Attrs => {
137
136
  return false;
138
137
  };
139
138
 
140
- export const attributesToDOM = (node: PNode, content = null): DOMOutputSpec => {
139
+ export const attributesToDOM = (
140
+ node: PNode,
141
+ content?: string | null
142
+ ): DOMOutputSpec => {
141
143
  const {
142
144
  mappingResource,
143
145
  codelistResource,
@@ -192,7 +194,9 @@ export const attributesToDOM = (node: PNode, content = null): DOMOutputSpec => {
192
194
  content: content ? content : '',
193
195
  ...(!!datatype && { datatype: datatype as string }),
194
196
  },
195
- content ? contentToDom({ content, type: type as string, node }) : 0,
197
+ content !== undefined
198
+ ? contentToDom({ content, type: type as string, node })
199
+ : 0,
196
200
  ],
197
201
  ];
198
202
  };
@@ -43,10 +43,10 @@ export async function fetchCodeListOptions(
43
43
  endpoint: string,
44
44
  codelistUri: string
45
45
  ): Promise<CodeListOptions> {
46
- const codelistsOptionsQueryResult = await executeQuery(
46
+ const codelistsOptionsQueryResult = await executeQuery({
47
47
  endpoint,
48
- generateCodeListOptionsQuery(codelistUri)
49
- );
48
+ query: generateCodeListOptionsQuery(codelistUri),
49
+ });
50
50
  const options = parseCodelistOptions(codelistsOptionsQueryResult);
51
51
  return {
52
52
  type:
@@ -95,10 +95,10 @@ export async function fetchCodeListsByPublisher(
95
95
  endpoint: string,
96
96
  publisher: string
97
97
  ): Promise<CodeList[]> {
98
- const codelistsOptionsQueryResult = await executeQuery(
98
+ const codelistsOptionsQueryResult = await executeQuery({
99
99
  endpoint,
100
- generateCodeListsByPublisherQuery(publisher)
101
- );
100
+ query: generateCodeListsByPublisherQuery(publisher),
101
+ });
102
102
  const bindings = codelistsOptionsQueryResult.results.bindings;
103
103
  return bindings.map((binding) => ({
104
104
  uri: binding['uri']?.value,
@@ -0,0 +1,77 @@
1
+ import { findParentNodeClosestToPos } from '@curvenote/prosemirror-utils';
2
+ import { NodeType, PNode, ResolvedPos, Schema } from '@lblod/ember-rdfa-editor';
3
+ import { containsOnlyPlaceholder } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
4
+ import { findNodes } from '@lblod/ember-rdfa-editor/utils/position-utils';
5
+
6
+ export function findInsertionRange(args: {
7
+ doc: PNode;
8
+ $from: ResolvedPos;
9
+ nodeType: NodeType;
10
+ schema: Schema;
11
+ limitTo?: string;
12
+ }) {
13
+ const { doc, $from, nodeType, schema, limitTo } = args;
14
+ for (let currentDepth = $from.depth; currentDepth >= 0; currentDepth--) {
15
+ const currentAncestor = $from.node(currentDepth);
16
+ const index = $from.index(currentDepth);
17
+ if (currentAncestor.canReplaceWith(index, index, nodeType)) {
18
+ if (containsOnlyPlaceholder(schema, currentAncestor)) {
19
+ return { from: $from.start(currentDepth), to: $from.end(currentDepth) };
20
+ } else {
21
+ const insertPos = $from.after(currentDepth + 1);
22
+ return { from: insertPos, to: insertPos };
23
+ }
24
+ }
25
+ }
26
+ const limitContainer = limitTo
27
+ ? findParentNodeClosestToPos(
28
+ $from,
29
+ (node) => node.type === schema.nodes[limitTo]
30
+ )
31
+ : null;
32
+
33
+ const limitContainerRange = limitContainer
34
+ ? {
35
+ from: limitContainer.pos,
36
+ to: limitContainer.pos + limitContainer.node.nodeSize,
37
+ }
38
+ : { from: 0, to: doc.nodeSize };
39
+ const filterFunction = ({ from, to }: { from: number; to: number }) => {
40
+ if (from >= limitContainerRange.from && to <= limitContainerRange.to) {
41
+ const node = doc.nodeAt(from);
42
+ if (node) {
43
+ if (node.canReplaceWith(node.childCount, node.childCount, nodeType)) {
44
+ return true;
45
+ }
46
+ }
47
+ }
48
+ return false;
49
+ };
50
+ const nextContainerRange =
51
+ findNodes({
52
+ doc,
53
+ start: $from.pos,
54
+ visitParentUpwards: true,
55
+ reverse: false,
56
+ filter: filterFunction,
57
+ }).next().value ??
58
+ findNodes({
59
+ doc,
60
+ start: $from.pos,
61
+ visitParentUpwards: true,
62
+ reverse: true,
63
+ filter: filterFunction,
64
+ }).next().value;
65
+ if (nextContainerRange) {
66
+ const { from, to } = nextContainerRange;
67
+ const containerNode = doc.nodeAt(from);
68
+ if (containerNode) {
69
+ if (containsOnlyPlaceholder(schema, containerNode)) {
70
+ return { from: from + 1, to: to - 1 };
71
+ } else {
72
+ return { from: to - 1, to: to - 1 };
73
+ }
74
+ }
75
+ }
76
+ return null;
77
+ }
@@ -1,13 +1,25 @@
1
1
  import * as RDF from '@rdfjs/types';
2
+ import { optionMapOr } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
2
3
 
3
- export type QueryResult = {
4
+ export interface QueryResult<Binding = Record<string, RDF.Term>> {
4
5
  results: {
5
- bindings: Record<string, RDF.Term>[];
6
+ bindings: Binding[];
6
7
  };
7
- };
8
+ }
9
+
10
+ interface QueryConfig {
11
+ query: string;
12
+ endpoint: string;
13
+ abortSignal?: AbortSignal;
14
+ }
8
15
 
9
- export async function executeQuery(endpoint: string, query: string) {
16
+ export async function executeQuery<Binding = Record<string, RDF.Term>>({
17
+ query,
18
+ endpoint,
19
+ abortSignal,
20
+ }: QueryConfig) {
10
21
  const encodedQuery = encodeURIComponent(query.trim());
22
+
11
23
  const response = await fetch(endpoint, {
12
24
  method: 'POST',
13
25
  mode: 'cors',
@@ -16,12 +28,22 @@ export async function executeQuery(endpoint: string, query: string) {
16
28
  'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
17
29
  },
18
30
  body: `query=${encodedQuery}`,
31
+ signal: abortSignal,
19
32
  });
33
+
20
34
  if (response.ok) {
21
- return response.json() as unknown as QueryResult;
35
+ return response.json() as Promise<QueryResult<Binding>>;
22
36
  } else {
23
37
  throw new Error(
24
- `Request to MOW backend was unsuccessful: [${response.status}] ${response.statusText}`
38
+ `Request to ${endpoint} was unsuccessful: [${response.status}] ${response.statusText}`
25
39
  );
26
40
  }
27
41
  }
42
+
43
+ export async function executeCountQuery(queryConfig: QueryConfig) {
44
+ const response = await executeQuery<{ count: { value: string } }>(
45
+ queryConfig
46
+ );
47
+
48
+ return optionMapOr(0, parseInt, response.results.bindings[0]?.count.value);
49
+ }
@@ -0,0 +1,34 @@
1
+ import { warn } from '@ember/debug';
2
+
3
+ export function escapeValue(value?: string) {
4
+ if (value) {
5
+ const shadowDomElement = document.createElement('textarea');
6
+ shadowDomElement.innerHTML = value;
7
+ return shadowDomElement.textContent;
8
+ } else {
9
+ return null;
10
+ }
11
+ }
12
+
13
+ export function dateValue(value?: string): string | null {
14
+ if (value) {
15
+ try {
16
+ return new Intl.DateTimeFormat('nl-BE').format(
17
+ new Date(Date.parse(value))
18
+ );
19
+ } catch (e) {
20
+ let message: string;
21
+ if (e instanceof Error) {
22
+ message = e.message;
23
+ } else {
24
+ message = e as string;
25
+ }
26
+ warn(`Error parsing date ${value}: ${message}`, {
27
+ id: 'date-parsing-error',
28
+ });
29
+ return null;
30
+ }
31
+ } else {
32
+ return null;
33
+ }
34
+ }
@@ -0,0 +1,3 @@
1
+ import { htmlSafe } from '@ember/template';
2
+
3
+ export type SafeString = ReturnType<typeof htmlSafe>;
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/document-title-plugin/insert-title-card';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/pagination/pagination-view';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/helpers/alert-load-error';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/helpers/alert-no-items';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/search-modal';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/snippet-insert';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/snippets/snippet-list';
@@ -0,0 +1 @@
1
+ export { default } from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/snippets/snippet-preview';
@@ -0,0 +1,4 @@
1
+ export {
2
+ default,
3
+ pagination,
4
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/helpers/pagination';
@@ -0,0 +1,9 @@
1
+ [property='eli:title']:before {
2
+ content: 'Document-titel' !important;
3
+ }
4
+
5
+ [lang='en-US'] {
6
+ [property='eli:title']:before {
7
+ content: 'Document title' !important;
8
+ }
9
+ }