@lblod/ember-rdfa-editor-lblod-plugins 24.3.1 → 24.3.2-dev.2ac9ceabc39305020bc2d6bbf37755c2dcb383ac

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 (46) hide show
  1. package/.changeset/four-eagles-live.md +5 -0
  2. package/.changeset/gentle-berries-exist.md +5 -0
  3. package/.changeset/hungry-trees-perform.md +5 -0
  4. package/.changeset/tough-pugs-shave.md +5 -0
  5. package/CHANGELOG.md +6 -0
  6. package/addon/components/snippet-plugin/nodes/placeholder.gts +42 -23
  7. package/addon/components/snippet-plugin/nodes/snippet.gts +103 -39
  8. package/addon/components/snippet-plugin/search-modal.hbs +4 -1
  9. package/addon/components/snippet-plugin/search-modal.ts +8 -4
  10. package/addon/components/snippet-plugin/snippet-insert-placeholder.gts +4 -4
  11. package/addon/components/snippet-plugin/snippet-insert-rdfa.gts +14 -22
  12. package/addon/components/snippet-plugin/snippet-insert.gts +17 -19
  13. package/addon/components/snippet-plugin/snippet-list/snippet-list-modal.hbs +1 -1
  14. package/addon/components/snippet-plugin/snippet-list/snippet-list-modal.ts +7 -9
  15. package/addon/components/snippet-plugin/snippet-list/snippet-list-view.hbs +1 -1
  16. package/addon/components/snippet-plugin/snippet-list/snippet-list-view.ts +5 -9
  17. package/addon/components/snippet-plugin/snippet-list-select.gts +2 -2
  18. package/addon/plugins/snippet-plugin/commands/insert-snippet.ts +5 -8
  19. package/addon/plugins/snippet-plugin/commands/update-snippet-placeholder.ts +2 -2
  20. package/addon/plugins/snippet-plugin/index.ts +9 -7
  21. package/addon/plugins/snippet-plugin/nodes/snippet-placeholder.ts +71 -23
  22. package/addon/plugins/snippet-plugin/nodes/snippet.ts +53 -20
  23. package/addon/plugins/snippet-plugin/utils/fetch-data.ts +8 -8
  24. package/addon/plugins/snippet-plugin/utils/rdfa-predicate.ts +20 -3
  25. package/addon/utils/has-descendant.ts +19 -0
  26. package/app/styles/snippet-plugin.scss +59 -23
  27. package/declarations/addon/components/snippet-plugin/nodes/placeholder.d.ts +7 -2
  28. package/declarations/addon/components/snippet-plugin/nodes/snippet.d.ts +4 -1
  29. package/declarations/addon/components/snippet-plugin/search-modal.d.ts +3 -1
  30. package/declarations/addon/components/snippet-plugin/snippet-insert-rdfa.d.ts +2 -6
  31. package/declarations/addon/components/snippet-plugin/snippet-insert.d.ts +3 -7
  32. package/declarations/addon/components/snippet-plugin/snippet-list/snippet-list-modal.d.ts +3 -3
  33. package/declarations/addon/components/snippet-plugin/snippet-list/snippet-list-view.d.ts +2 -2
  34. package/declarations/addon/components/snippet-plugin/snippet-list-select.d.ts +1 -1
  35. package/declarations/addon/plugins/snippet-plugin/commands/insert-snippet.d.ts +3 -4
  36. package/declarations/addon/plugins/snippet-plugin/index.d.ts +7 -2
  37. package/declarations/addon/plugins/snippet-plugin/nodes/snippet-placeholder.d.ts +13 -4
  38. package/declarations/addon/plugins/snippet-plugin/nodes/snippet.d.ts +4 -5
  39. package/declarations/addon/plugins/snippet-plugin/utils/fetch-data.d.ts +1 -1
  40. package/declarations/addon/plugins/snippet-plugin/utils/rdfa-predicate.d.ts +9 -2
  41. package/declarations/addon/utils/has-descendant.d.ts +2 -0
  42. package/package.json +2 -1
  43. package/pnpm-lock.yaml +11 -1
  44. package/translations/en-US.yaml +2 -2
  45. package/translations/nl-BE.yaml +2 -2
  46. package/types/lblod/template-uuid-instantiator.d.ts +3 -0
@@ -4,25 +4,22 @@ import { SnippetList } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snip
4
4
 
5
5
  interface Args {
6
6
  snippetLists: SnippetList[];
7
- assignedSnippetListsIds: string[];
7
+ snippetListIds: string[];
8
8
  listNameFilter: string | null;
9
9
  isLoading: boolean;
10
- onChange: (assignedSnippetListsIds: string[]) => void;
10
+ onChange: (snippetListIds: string[]) => void;
11
11
  }
12
12
 
13
13
  export default class SnippetListViewComponent extends Component<Args> {
14
14
  @action
15
15
  onChange(snippetId: string, isSelected: boolean) {
16
16
  if (isSelected) {
17
- const newSnippetListIds = [
18
- ...this.args.assignedSnippetListsIds,
19
- snippetId,
20
- ];
17
+ const newSnippetListIds = [...this.args.snippetListIds, snippetId];
21
18
 
22
19
  return this.args.onChange(newSnippetListIds);
23
20
  }
24
21
 
25
- const newSnippetListIds = this.args.assignedSnippetListsIds.filter(
22
+ const newSnippetListIds = this.args.snippetListIds.filter(
26
23
  (id) => id !== snippetId,
27
24
  );
28
25
 
@@ -49,8 +46,7 @@ export default class SnippetListViewComponent extends Component<Args> {
49
46
  return;
50
47
  }
51
48
 
52
- const isSelected =
53
- this.args.assignedSnippetListsIds.includes(snippetListId);
49
+ const isSelected = this.args.snippetListIds.includes(snippetListId);
54
50
 
55
51
  this.onChange(snippetListId, !isSelected);
56
52
  }
@@ -53,7 +53,7 @@ export default class SnippetListSelect extends Component<Signature> {
53
53
  return getSnippetListIdsProperties(this.args.node.value);
54
54
  }
55
55
 
56
- get assignedSnippetListsIds(): string[] {
56
+ get snippetListIds(): string[] {
57
57
  return getAssignedSnippetListsIdsFromProperties(
58
58
  this.snippetListIdsProperties,
59
59
  );
@@ -99,7 +99,7 @@ export default class SnippetListSelect extends Component<Signature> {
99
99
 
100
100
  <SnippetListModal
101
101
  @config={{@config}}
102
- @assignedSnippetListsIds={{this.assignedSnippetListsIds}}
102
+ @snippetListIds={{this.snippetListIds}}
103
103
  @onSaveSnippetLists={{this.onSaveSnippetLists}}
104
104
  @allowMultipleSnippets={{this.allowMultipleSnippets}}
105
105
  @open={{this.showModal}}
@@ -3,7 +3,7 @@ import { transactionCombinator } from '@lblod/ember-rdfa-editor/utils/transactio
3
3
  import { addPropertyToNode } from '@lblod/ember-rdfa-editor/utils/rdfa-utils';
4
4
  import { recalculateNumbers } from '../../structure-plugin/recalculate-structure-numbers';
5
5
  import { createSnippet } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/nodes/snippet';
6
- import { type ImportedResourceMap } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
6
+ import { type SnippetListProperties } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
7
7
  import {
8
8
  isSome,
9
9
  unwrap,
@@ -12,8 +12,7 @@ import {
12
12
  export interface InsertSnippetCommandArgs {
13
13
  content: string;
14
14
  title: string;
15
- assignedSnippetListsIds: string[];
16
- importedResources?: ImportedResourceMap;
15
+ listProperties: SnippetListProperties;
17
16
  range?: { start: number; end: number };
18
17
  allowMultipleSnippets?: boolean;
19
18
  }
@@ -21,8 +20,7 @@ export interface InsertSnippetCommandArgs {
21
20
  const insertSnippet = ({
22
21
  content,
23
22
  title,
24
- assignedSnippetListsIds,
25
- importedResources,
23
+ listProperties,
26
24
  range,
27
25
  allowMultipleSnippets,
28
26
  }: InsertSnippetCommandArgs): Command => {
@@ -44,13 +42,12 @@ const insertSnippet = ({
44
42
  schema: state.schema,
45
43
  content,
46
44
  title,
47
- snippetListIds: assignedSnippetListsIds,
48
- importedResources,
45
+ listProperties,
49
46
  allowMultipleSnippets,
50
47
  });
51
48
 
52
49
  const addImportedResourceProperties = Object.values(
53
- importedResources ?? {},
50
+ listProperties.importedResources ?? {},
54
51
  )
55
52
  .map((linked) => {
56
53
  const newProperties =
@@ -2,7 +2,7 @@ import { Command } from '@lblod/ember-rdfa-editor';
2
2
  import { addProperty, removeProperty } from '@lblod/ember-rdfa-editor/commands';
3
3
  import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
4
4
  import { SNIPPET_LIST_RDFA_PREDICATE } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
5
- import { getSnippetUriFromId } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
5
+ import { getSnippetUriFromId } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
6
6
  import { type OutgoingTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
7
7
  import { type ResolvedPNode } from '@lblod/ember-rdfa-editor/utils/_private/types';
8
8
  import {
@@ -59,7 +59,7 @@ export const updateSnippetPlaceholder = ({
59
59
  });
60
60
  transaction = transaction.setNodeAttribute(
61
61
  node.pos,
62
- 'listNames',
62
+ 'snippetListNames',
63
63
  newSnippetLists.map((list) => list.label),
64
64
  );
65
65
  transaction = transaction.setNodeAttribute(
@@ -6,12 +6,14 @@ import {
6
6
  } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
7
7
  import { dateValue } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
8
8
  import { SafeString } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/types';
9
+ import { getSnippetIdFromUri } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
9
10
 
10
11
  export const DEFAULT_CONTENT_STRING = 'block+';
11
12
 
12
13
  export type SnippetPluginConfig = {
13
14
  endpoint: string;
14
15
  allowedContent?: string;
16
+ hidePlaceholderInsertButton?: boolean;
15
17
  };
16
18
 
17
19
  interface SnippetArgs {
@@ -34,6 +36,13 @@ export class Snippet {
34
36
 
35
37
  export type ImportedResourceMap = Record<string, Option<string>>;
36
38
 
39
+ export type SnippetListProperties = {
40
+ placeholderId: string;
41
+ listIds: string[];
42
+ names: string[];
43
+ importedResources: ImportedResourceMap;
44
+ };
45
+
37
46
  export type SnippetListArgs = {
38
47
  id: string;
39
48
  label: string;
@@ -41,13 +50,6 @@ export type SnippetListArgs = {
41
50
  importedResources: string[];
42
51
  };
43
52
 
44
- const snippetListBase = 'http://lblod.data.gift/snippet-lists/';
45
-
46
- export const getSnippetUriFromId = (id: string) => `${snippetListBase}${id}`;
47
-
48
- export const getSnippetIdFromUri = (uri: string) =>
49
- uri.replace(snippetListBase, '');
50
-
51
53
  export class SnippetList {
52
54
  id: string;
53
55
  label: string;
@@ -11,7 +11,7 @@ import {
11
11
  createEmberNodeView,
12
12
  type EmberNodeConfig,
13
13
  } from '@lblod/ember-rdfa-editor/utils/ember-node';
14
- import SnippetPlaceholderComponent from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/nodes/placeholder';
14
+ import SnippetComponent from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/nodes/snippet';
15
15
  import {
16
16
  EXT,
17
17
  RDF,
@@ -20,11 +20,13 @@ import { hasOutgoingNamedNodeTriple } from '@lblod/ember-rdfa-editor-lblod-plugi
20
20
  import { getTranslationFunction } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/translation';
21
21
  import { jsonParse } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
22
22
  import {
23
- getSnippetUriFromId,
23
+ type SnippetListProperties,
24
24
  type ImportedResourceMap,
25
25
  type SnippetList,
26
+ type SnippetPluginConfig,
26
27
  } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
27
- import { SNIPPET_LIST_RDFA_PREDICATE } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
28
+ import { tripleForSnippetListId } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
29
+ import { OutgoingTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
28
30
 
29
31
  export function importedResourcesFromSnippetLists(
30
32
  lists: SnippetList[],
@@ -38,32 +40,61 @@ export function importedResourcesFromSnippetLists(
38
40
  );
39
41
  }
40
42
 
41
- export function createSnippetPlaceholder(
42
- lists: SnippetList[],
43
- schema: Schema,
44
- allowMultipleSnippets?: boolean,
45
- ) {
43
+ type CreateSnippetPlaceholderArgs = {
44
+ schema: Schema;
45
+ allowMultipleSnippets?: boolean;
46
+ } & (
47
+ | {
48
+ listProperties: SnippetListProperties;
49
+ }
50
+ | {
51
+ lists: SnippetList[];
52
+ }
53
+ );
54
+
55
+ export function createSnippetPlaceholder({
56
+ schema,
57
+ allowMultipleSnippets,
58
+ ...args
59
+ }: CreateSnippetPlaceholderArgs) {
60
+ let additionalProperties: OutgoingTriple[];
61
+ let listProps: Omit<SnippetListProperties, 'listIds'>;
62
+ if ('lists' in args) {
63
+ listProps = {
64
+ // This is a completely new placeholder, so new id
65
+ placeholderId: uuidv4(),
66
+ names: args.lists.map((list) => list.label),
67
+ importedResources: importedResourcesFromSnippetLists(args.lists),
68
+ };
69
+ additionalProperties = args.lists.map((list) =>
70
+ tripleForSnippetListId(list.id),
71
+ );
72
+ } else {
73
+ // Replacing the last snippet, so keep the id
74
+ listProps = args.listProperties;
75
+ additionalProperties = args.listProperties.listIds.map(
76
+ tripleForSnippetListId,
77
+ );
78
+ }
46
79
  const mappingResource = `http://example.net/lblod-snippet-placeholder/${uuidv4()}`;
47
80
  return schema.nodes.snippet_placeholder.create({
48
81
  rdfaNodeType: 'resource',
49
- listNames: lists.map((list) => list.label),
82
+ placeholderId: listProps.placeholderId,
83
+ snippetListNames: listProps.names,
50
84
  subject: mappingResource,
51
85
  properties: [
52
86
  {
53
87
  predicate: RDF('type').full,
54
88
  object: sayDataFactory.namedNode(EXT('SnippetPlaceholder').full),
55
89
  },
56
- ...lists.map((list) => ({
57
- predicate: SNIPPET_LIST_RDFA_PREDICATE.full,
58
- object: sayDataFactory.namedNode(getSnippetUriFromId(list.id)),
59
- })),
90
+ ...additionalProperties,
60
91
  ],
61
- importedResources: importedResourcesFromSnippetLists(lists),
92
+ importedResources: listProps.importedResources,
62
93
  allowMultipleSnippets,
63
94
  });
64
95
  }
65
96
 
66
- const emberNodeConfig: EmberNodeConfig = {
97
+ const emberNodeConfig = (config: SnippetPluginConfig): EmberNodeConfig => ({
67
98
  name: 'snippet_placeholder',
68
99
  inline: false,
69
100
  group: 'block',
@@ -73,20 +104,24 @@ const emberNodeConfig: EmberNodeConfig = {
73
104
  attrs: {
74
105
  ...rdfaAttrSpec({ rdfaAware: true }),
75
106
  typeof: { default: EXT('SnippetPlaceholder') },
76
- listNames: { default: [] },
107
+ placeholderId: { default: '' },
108
+ snippetListNames: { default: [] },
77
109
  importedResources: { default: {} },
78
110
  allowMultipleSnippets: { default: false },
111
+ config: {
112
+ default: config,
113
+ },
79
114
  },
80
- component: SnippetPlaceholderComponent,
115
+ component: SnippetComponent,
81
116
  serialize(node, editorState) {
82
117
  const t = getTranslationFunction(editorState);
118
+ const listNames = node.attrs.snippetListNames as string[];
83
119
  return renderRdfaAware({
84
120
  renderable: node,
85
121
  tag: 'div',
86
122
  attrs: {
87
- ...node.attrs,
88
123
  class: 'say-snippet-placeholder-node',
89
- 'data-list-names': (node.attrs.listNames as string[]).join(','),
124
+ 'data-list-names': listNames && JSON.stringify(listNames),
90
125
  'data-imported-resources': JSON.stringify(node.attrs.importedResources),
91
126
  'data-allow-multiple-snippets': node.attrs.allowMultipleSnippets,
92
127
  },
@@ -112,9 +147,20 @@ const emberNodeConfig: EmberNodeConfig = {
112
147
  EXT('SnippetPlaceholder'),
113
148
  )
114
149
  ) {
150
+ let snippetListNames = jsonParse(
151
+ node.getAttribute('data-list-names'),
152
+ );
153
+ if (!snippetListNames) {
154
+ // We might have an older version which is comma separated
155
+ snippetListNames = node.getAttribute('data-list-names')?.split(',');
156
+ }
115
157
  return {
116
158
  ...rdfaAttrs,
117
- listNames: node.getAttribute('data-list-names')?.split(','),
159
+ // Generate a placeholderId any time we deserialise, this way we don't need to handle
160
+ // generating new ids whenever we re-use parts of a document (e.g. copy-paste or
161
+ // placeholders inside snippets)
162
+ placeholderId: uuidv4(),
163
+ snippetListNames,
118
164
  importedResources: jsonParse(
119
165
  node.getAttribute('data-imported-resources'),
120
166
  ),
@@ -126,7 +172,9 @@ const emberNodeConfig: EmberNodeConfig = {
126
172
  },
127
173
  },
128
174
  ],
129
- };
175
+ });
130
176
 
131
- export const snippetPlaceholder = createEmberNodeSpec(emberNodeConfig);
132
- export const snippetPlaceholderView = createEmberNodeView(emberNodeConfig);
177
+ export const snippetPlaceholder = (config: SnippetPluginConfig) =>
178
+ createEmberNodeSpec(emberNodeConfig(config));
179
+ export const snippetPlaceholderView = (config: SnippetPluginConfig) =>
180
+ createEmberNodeView(emberNodeConfig(config));
@@ -1,4 +1,5 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
+ import templateUuidInstantiator from '@lblod/template-uuid-instantiator';
2
3
  import {
3
4
  type Attrs,
4
5
  getRdfaAttrs,
@@ -31,9 +32,10 @@ import { hasOutgoingNamedNodeTriple } from '@lblod/ember-rdfa-editor-lblod-plugi
31
32
  import { jsonParse } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/strings';
32
33
  import {
33
34
  DEFAULT_CONTENT_STRING,
34
- type ImportedResourceMap,
35
+ SnippetListProperties,
35
36
  type SnippetPluginConfig,
36
37
  } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
38
+ import { tripleForSnippetListId } from '../utils/rdfa-predicate';
37
39
 
38
40
  function outgoingFromBacklink(
39
41
  backlink: IncomingTriple,
@@ -57,13 +59,19 @@ function outgoingFromBacklink(
57
59
  }
58
60
  }
59
61
 
62
+ const defaultProperties = [
63
+ {
64
+ predicate: RDF('type').full,
65
+ object: sayDataFactory.namedNode(EXT('Snippet').full),
66
+ },
67
+ ];
68
+
60
69
  interface CreateSnippetArgs {
61
70
  schema: Schema;
71
+ allowMultipleSnippets?: boolean;
62
72
  content: string;
63
73
  title: string;
64
- snippetListIds: string[];
65
- importedResources?: ImportedResourceMap;
66
- allowMultipleSnippets?: boolean;
74
+ listProperties: SnippetListProperties;
67
75
  }
68
76
 
69
77
  /**
@@ -76,9 +84,13 @@ export function createSnippet({
76
84
  schema,
77
85
  content,
78
86
  title,
79
- snippetListIds,
80
- importedResources,
81
87
  allowMultipleSnippets,
88
+ listProperties: {
89
+ listIds,
90
+ names: snippetListNames,
91
+ importedResources,
92
+ placeholderId,
93
+ },
82
94
  }: CreateSnippetArgs): [PNode, Map<string, OutgoingTriple[]>] {
83
95
  // Replace instances of linked to uris with the resources that exist in the outer document.
84
96
  let replacedContent = content;
@@ -88,16 +100,24 @@ export function createSnippet({
88
100
  replacedContent = replacedContent.replaceAll(imported, linked);
89
101
  }
90
102
  }
103
+ // Instantiate URIs of the form --ref-algo-123
104
+ replacedContent = templateUuidInstantiator(replacedContent);
91
105
  // Create the new node
92
106
  const parser = ProseParser.fromSchema(schema);
93
107
  const contentAsNode = htmlToDoc(replacedContent, {
94
108
  schema,
95
109
  parser,
96
110
  });
111
+ const properties = [
112
+ ...defaultProperties,
113
+ ...listIds.map(tripleForSnippetListId),
114
+ ];
97
115
  const node = schema.node(
98
116
  'snippet',
99
117
  {
100
- assignedSnippetListsIds: snippetListIds,
118
+ placeholderId,
119
+ properties,
120
+ snippetListNames,
101
121
  title,
102
122
  subject: `http://data.lblod.info/snippets/${uuidv4()}`,
103
123
  importedResources,
@@ -142,15 +162,11 @@ const emberNodeConfig = (options: SnippetPluginConfig): EmberNodeConfig => ({
142
162
  attrs: {
143
163
  ...rdfaAttrSpec({ rdfaAware: true }),
144
164
  properties: {
145
- default: [
146
- {
147
- predicate: RDF('type').full,
148
- object: sayDataFactory.namedNode(EXT('Snippet').full),
149
- },
150
- ],
165
+ default: defaultProperties,
151
166
  },
152
167
  rdfaNodeType: { default: 'resource' },
153
- assignedSnippetListsIds: { default: [] },
168
+ placeholderId: { default: '' },
169
+ snippetListNames: { default: [] },
154
170
  importedResources: { default: {} },
155
171
  title: { default: '' },
156
172
  config: { default: options },
@@ -159,14 +175,14 @@ const emberNodeConfig = (options: SnippetPluginConfig): EmberNodeConfig => ({
159
175
  component: SnippetComponent,
160
176
  content: options.allowedContent || DEFAULT_CONTENT_STRING,
161
177
  serialize(node) {
178
+ const listNames = node.attrs.snippetListNames as string[];
162
179
  return renderRdfaAware({
163
180
  renderable: node,
164
181
  tag: 'div',
165
182
  attrs: {
166
183
  ...node.attrs,
167
- 'data-assigned-snippet-ids': (
168
- node.attrs.assignedSnippetListsIds as string[]
169
- ).join(','),
184
+ 'data-snippet-placeholder-id': node.attrs.placeholderId,
185
+ 'data-list-names': listNames && JSON.stringify(listNames),
170
186
  'data-imported-resources': JSON.stringify(node.attrs.importedResources),
171
187
  'data-snippet-title': node.attrs.title,
172
188
  'data-allow-multiple-snippets': node.attrs.allowMultipleSnippets,
@@ -181,13 +197,30 @@ const emberNodeConfig = (options: SnippetPluginConfig): EmberNodeConfig => ({
181
197
  if (typeof node === 'string') return false;
182
198
  const rdfaAttrs = getRdfaAttrs(node, { rdfaAware: true });
183
199
  if (
200
+ rdfaAttrs &&
201
+ rdfaAttrs.rdfaNodeType !== 'literal' &&
184
202
  hasOutgoingNamedNodeTriple(rdfaAttrs, RDF('type'), EXT('Snippet'))
185
203
  ) {
204
+ // For older documents without placeholder ids, treat each inserted snippet separately.
205
+ // This means that pressing 'remove snippet' will add a placeholder in it's place, which
206
+ // is not expected, but simple to remove (hitting backspace). This is better than
207
+ // risking having no ability to insert another snippet.
208
+ const placeholderId =
209
+ node.getAttribute('data-snippet-placeholder-id') || uuidv4();
210
+ const legacySnippetListIds = node
211
+ .getAttribute('data-assigned-snippet-ids')
212
+ ?.split(',');
213
+ const properties = !legacySnippetListIds
214
+ ? rdfaAttrs.properties
215
+ : [
216
+ ...rdfaAttrs.properties,
217
+ ...legacySnippetListIds.map(tripleForSnippetListId),
218
+ ];
186
219
  return {
187
220
  ...rdfaAttrs,
188
- assignedSnippetListsIds: node
189
- .getAttribute('data-assigned-snippet-ids')
190
- ?.split(','),
221
+ properties,
222
+ placeholderId,
223
+ snippetListNames: jsonParse(node.getAttribute('data-list-names')),
191
224
  importedResources: jsonParse(
192
225
  node.getAttribute('data-imported-resources'),
193
226
  ),
@@ -6,7 +6,7 @@ import {
6
6
  } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/sparql-helpers';
7
7
  import { Snippet, SnippetList, SnippetListArgs } from '../index';
8
8
 
9
- type Filter = { name?: string; assignedSnippetListIds?: string[] };
9
+ type Filter = { name?: string; snippetListIds?: string[] };
10
10
  export type OrderBy =
11
11
  | 'label'
12
12
  | 'created-on'
@@ -16,7 +16,7 @@ export type OrderBy =
16
16
  | null;
17
17
  type Pagination = { pageNumber: number; pageSize: number };
18
18
 
19
- const buildSnippetCountQuery = ({ name, assignedSnippetListIds }: Filter) => {
19
+ const buildSnippetCountQuery = ({ name, snippetListIds }: Filter) => {
20
20
  return /* sparql */ `
21
21
  PREFIX schema: <http://schema.org/>
22
22
  PREFIX dct: <http://purl.org/dc/terms/>
@@ -42,8 +42,8 @@ const buildSnippetCountQuery = ({ name, assignedSnippetListIds }: Filter) => {
42
42
  : ''
43
43
  }
44
44
  ${
45
- assignedSnippetListIds && assignedSnippetListIds.length
46
- ? `FILTER (?snippetListId IN (${assignedSnippetListIds
45
+ snippetListIds && snippetListIds.length
46
+ ? `FILTER (?snippetListId IN (${snippetListIds
47
47
  .map((from) => sparqlEscapeString(from))
48
48
  .join(', ')}))`
49
49
  : ''
@@ -69,7 +69,7 @@ const buildSnippetCountQuery = ({ name, assignedSnippetListIds }: Filter) => {
69
69
  // };
70
70
 
71
71
  const buildSnippetFetchQuery = ({
72
- filter: { name, assignedSnippetListIds },
72
+ filter: { name, snippetListIds },
73
73
  pagination: { pageSize, pageNumber },
74
74
  }: {
75
75
  filter: Filter;
@@ -106,8 +106,8 @@ const buildSnippetFetchQuery = ({
106
106
  : ''
107
107
  }
108
108
  ${
109
- assignedSnippetListIds && assignedSnippetListIds.length
110
- ? `FILTER (?snippetListId IN (${assignedSnippetListIds
109
+ snippetListIds && snippetListIds.length
110
+ ? `FILTER (?snippetListId IN (${snippetListIds
111
111
  .map((from) => sparqlEscapeString(from))
112
112
  .join(', ')}))`
113
113
  : ''
@@ -173,7 +173,7 @@ export const fetchSnippets = async ({
173
173
  filter: Filter;
174
174
  pagination: Pagination;
175
175
  }) => {
176
- if (!filter.assignedSnippetListIds?.length) {
176
+ if (!filter.snippetListIds?.length) {
177
177
  return { totalCount: 0, results: [] };
178
178
  }
179
179
 
@@ -1,11 +1,25 @@
1
- import { PNode } from '@lblod/ember-rdfa-editor';
2
- import { OutgoingTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
3
- import { getSnippetIdFromUri } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
1
+ import { type PNode } from '@lblod/ember-rdfa-editor';
2
+ import { type OutgoingTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
3
+ import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
4
4
  import { SAY } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
5
5
  import { getOutgoingTripleList } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
6
6
 
7
7
  export const SNIPPET_LIST_RDFA_PREDICATE = SAY('allowedSnippetList');
8
8
 
9
+ const snippetListBase = 'http://lblod.data.gift/snippet-lists/';
10
+
11
+ export const getSnippetUriFromId = (id: string) => `${snippetListBase}${id}`;
12
+
13
+ export const getSnippetIdFromUri = (uri: string) =>
14
+ uri.replace(snippetListBase, '');
15
+
16
+ export function tripleForSnippetListId(id: string) {
17
+ return {
18
+ predicate: SNIPPET_LIST_RDFA_PREDICATE.full,
19
+ object: sayDataFactory.namedNode(getSnippetUriFromId(id)),
20
+ };
21
+ }
22
+
9
23
  export const getSnippetListIdsProperties = (node: PNode) => {
10
24
  return getOutgoingTripleList(node.attrs, SNIPPET_LIST_RDFA_PREDICATE);
11
25
  };
@@ -19,3 +33,6 @@ export const getAssignedSnippetListsIdsFromProperties = (
19
33
  .map(getSnippetIdFromUri)
20
34
  .filter((id) => id !== undefined);
21
35
  };
36
+
37
+ export const getSnippetListIdsFromNode = (node: PNode) =>
38
+ getAssignedSnippetListsIdsFromProperties(getSnippetListIdsProperties(node));
@@ -0,0 +1,19 @@
1
+ import { type PNode } from '@lblod/ember-rdfa-editor';
2
+
3
+ export function hasDecendant(
4
+ nodeToDescendInto: PNode,
5
+ matchFunc: (node: PNode) => boolean,
6
+ ) {
7
+ let foundMatch = false;
8
+ nodeToDescendInto.descendants((node) => {
9
+ // Already found a match, stop descending or checking
10
+ if (foundMatch) return false;
11
+ if (matchFunc(node)) {
12
+ foundMatch = true;
13
+ return false;
14
+ }
15
+ return true;
16
+ });
17
+
18
+ return foundMatch;
19
+ }
@@ -86,29 +86,6 @@
86
86
  }
87
87
  }
88
88
 
89
- .ProseMirror-selectednode > .say-snippet-placeholder {
90
- background-color: var(--au-blue-200);
91
- }
92
-
93
- .say-snippet-placeholder-node {
94
- background-color: var(--au-orange-200);
95
- padding: 2rem;
96
-
97
- div {
98
- font-weight: var(--au-medium);
99
- }
100
- }
101
-
102
- div[typeof='besluitpublicatie:Documentonderdeel']
103
- .say-snippet-placeholder-node {
104
- background-color: var(--au-gray-300);
105
- }
106
-
107
- .rdfa-annotations
108
- [typeof]:not([typeof='foaf:Document']).say-snippet-placeholder-node {
109
- padding-bottom: 2rem;
110
- }
111
-
112
89
  .say-snippet-card {
113
90
  border: 1px solid var(--au-blue-300);
114
91
  .say-snippet-title {
@@ -164,3 +141,62 @@ div[typeof='besluitpublicatie:Documentonderdeel']
164
141
  }
165
142
  }
166
143
  }
144
+
145
+ .say-snippet-placeholder {
146
+ display: flex;
147
+ flex-direction: row;
148
+ padding: $au-unit-small $au-unit-small * 1.5;
149
+ background-color: var(--au-orange-300);
150
+ border-radius: var(--au-radius);
151
+ border: 0.1rem solid var(--au-orange-500);
152
+
153
+ .say-snippet-placeholder__icon {
154
+ background-color: var(--au-orange-500);
155
+ color: black;
156
+ height: $au-unit - 0.1rem; // compensate for visual distortion of perfect circle
157
+ width: $au-unit;
158
+ margin-right: $au-unit * 0.5;
159
+ border-radius: $au-unit-large;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ flex-shrink: 0;
164
+ }
165
+
166
+ .say-snippet-placeholder__content {
167
+ margin-top: 0;
168
+ }
169
+
170
+ .say-snippet-placeholder__title {
171
+ color: var(--au-orange-700);
172
+ font-weight: var(--au-medium);
173
+ }
174
+
175
+ .say-snippet-placeholder__button {
176
+ margin: 0;
177
+ padding: 0;
178
+ }
179
+ }
180
+
181
+ .ProseMirror-selectednode > .say-snippet-placeholder {
182
+ background-color: var(--au-blue-200);
183
+ }
184
+
185
+ .say-snippet-placeholder-node {
186
+ background-color: var(--au-orange-200);
187
+ padding: 2rem;
188
+
189
+ div {
190
+ font-weight: var(--au-medium);
191
+ }
192
+ }
193
+
194
+ div[typeof='besluitpublicatie:Documentonderdeel']
195
+ .say-snippet-placeholder-node {
196
+ background-color: var(--au-gray-300);
197
+ }
198
+
199
+ .rdfa-annotations
200
+ [typeof]:not([typeof='foaf:Document']).say-snippet-placeholder-node {
201
+ padding-bottom: 2rem;
202
+ }