@lblod/ember-rdfa-editor-lblod-plugins 19.3.1 → 20.0.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 (58) hide show
  1. package/.dockerignore +3 -0
  2. package/CHANGELOG.md +14 -0
  3. package/addon/components/besluit-topic-plugin/besluit-topic-toolbar-dropdown.ts +8 -10
  4. package/addon/components/besluit-type-plugin/toolbar-dropdown.ts +4 -20
  5. package/addon/components/decision-plugin/decision-plugin-card.gts +231 -0
  6. package/addon/components/decision-plugin/insert-article.gts +81 -0
  7. package/addon/components/hover-tooltip.gts +68 -0
  8. package/addon/components/prosemirror-editor.hbs +15 -0
  9. package/addon/components/prosemirror-editor.ts +98 -0
  10. package/addon/components/roadsign-regulation-plugin/roadsign-regulation-card.ts +16 -19
  11. package/addon/components/roadsign-regulation-plugin/roadsigns-modal.ts +23 -3
  12. package/addon/components/structure-plugin/_private/control-card.gts +192 -0
  13. package/addon/components/structure-plugin/_private/structure.gts +159 -0
  14. package/addon/plugins/besluit-topic-plugin/utils/helpers.ts +19 -10
  15. package/addon/plugins/decision-plugin/commands/insert-article-command.ts +82 -0
  16. package/addon/plugins/decision-plugin/commands/insert-article-container.ts +33 -35
  17. package/addon/plugins/decision-plugin/commands/insert-description.ts +31 -28
  18. package/addon/plugins/decision-plugin/commands/insert-motivation.ts +106 -106
  19. package/addon/plugins/decision-plugin/commands/insert-title.ts +30 -28
  20. package/addon/plugins/decision-plugin/utils/build-article-structure.ts +44 -0
  21. package/addon/plugins/roadsign-regulation-plugin/index.ts +1 -0
  22. package/addon/plugins/structure-plugin/move-structure.ts +120 -0
  23. package/addon/plugins/structure-plugin/node.ts +148 -0
  24. package/addon/plugins/structure-plugin/recalculate-structure-numbers.ts +28 -0
  25. package/addon/utils/find-insertion-pos-in-node.ts +21 -0
  26. package/addon/utils/nested-prosemirror.ts +111 -0
  27. package/app/styles/structure-plugin.scss +53 -0
  28. package/declarations/addon/components/besluit-topic-plugin/besluit-topic-toolbar-dropdown.d.ts +2 -1
  29. package/declarations/addon/components/besluit-type-plugin/toolbar-dropdown.d.ts +1 -2
  30. package/declarations/addon/components/decision-plugin/decision-plugin-card.d.ts +20 -11
  31. package/declarations/addon/components/decision-plugin/insert-article.d.ts +23 -0
  32. package/declarations/addon/components/hover-tooltip.d.ts +26 -9
  33. package/declarations/addon/components/prosemirror-editor.d.ts +23 -0
  34. package/declarations/addon/components/roadsign-regulation-plugin/roadsigns-modal.d.ts +6 -0
  35. package/declarations/addon/components/structure-plugin/_private/control-card.d.ts +22 -0
  36. package/declarations/addon/components/structure-plugin/_private/structure.d.ts +32 -0
  37. package/declarations/addon/plugins/besluit-topic-plugin/utils/helpers.d.ts +2 -2
  38. package/declarations/addon/plugins/decision-plugin/commands/insert-article-command.d.ts +8 -0
  39. package/declarations/addon/plugins/decision-plugin/commands/insert-article-container.d.ts +4 -2
  40. package/declarations/addon/plugins/decision-plugin/commands/insert-description.d.ts +3 -2
  41. package/declarations/addon/plugins/decision-plugin/commands/insert-motivation.d.ts +3 -2
  42. package/declarations/addon/plugins/decision-plugin/commands/insert-title.d.ts +3 -2
  43. package/declarations/addon/plugins/decision-plugin/utils/build-article-structure.d.ts +2 -0
  44. package/declarations/addon/plugins/roadsign-regulation-plugin/index.d.ts +1 -0
  45. package/declarations/addon/plugins/structure-plugin/move-structure.d.ts +2 -0
  46. package/declarations/addon/plugins/structure-plugin/node.d.ts +4 -0
  47. package/declarations/addon/plugins/structure-plugin/recalculate-structure-numbers.d.ts +3 -0
  48. package/declarations/addon/utils/find-insertion-pos-in-node.d.ts +3 -0
  49. package/declarations/addon/utils/nested-prosemirror.d.ts +23 -0
  50. package/package.json +10 -5
  51. package/pnpm-lock.yaml +73 -14
  52. package/translations/en-US.yaml +9 -0
  53. package/translations/nl-BE.yaml +10 -3
  54. package/types/ember-power-select/components/power-select.d.ts +3 -3
  55. package/addon/components/decision-plugin/decision-plugin-card.hbs +0 -55
  56. package/addon/components/decision-plugin/decision-plugin-card.ts +0 -71
  57. package/addon/components/hover-tooltip.hbs +0 -12
  58. package/addon/components/hover-tooltip.ts +0 -41
package/.dockerignore ADDED
@@ -0,0 +1,3 @@
1
+ node_modules
2
+ dist
3
+ .eslintcache
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @lblod/ember-rdfa-editor-lblod-plugins
2
2
 
3
+ ## 20.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#440](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/440) [`8c242fe2eda10725e2bce59a77c86e905b6878b9`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/8c242fe2eda10725e2bce59a77c86e905b6878b9) Thanks [@abeforgit](https://github.com/abeforgit)! - Convert plugins that used decision nodes to work on any nodes that have the rdf decision type
8
+
9
+ ### Minor Changes
10
+
11
+ - [#440](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/440) [`8c242fe2eda10725e2bce59a77c86e905b6878b9`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/8c242fe2eda10725e2bce59a77c86e905b6878b9) Thanks [@abeforgit](https://github.com/abeforgit)! - Add new structure node using a nodeview approach
12
+
13
+ ### Patch Changes
14
+
15
+ - [#441](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/441) [`45aad15462f89eede7cd2633ccf129189367d8db`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/45aad15462f89eede7cd2633ccf129189367d8db) Thanks [@piemonkey](https://github.com/piemonkey)! - Fix docker image builds
16
+
3
17
  ## 19.3.1
4
18
 
5
19
  ### Patch Changes
@@ -2,7 +2,6 @@ import { tracked } from '@glimmer/tracking';
2
2
  import Component from '@glimmer/component';
3
3
  import { action } from '@ember/object';
4
4
  import { SayController } from '@lblod/ember-rdfa-editor';
5
- import { findAncestorOfType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
6
5
  import { trackedFunction } from 'ember-resources/util/function';
7
6
  import { ELI } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
8
7
  import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/icons/alert-triangle';
@@ -48,6 +47,13 @@ export default class BesluitTopicToolbarDropdownComponent extends Component<Args
48
47
  get doc() {
49
48
  return this.controller.mainEditorState.doc;
50
49
  }
50
+ get decisionRange() {
51
+ return getCurrentBesluitRange(this.controller);
52
+ }
53
+
54
+ get showCard() {
55
+ return !!this.decisionRange;
56
+ }
51
57
 
52
58
  topics = trackedFunction(this, async () => {
53
59
  const result = await fetchBesluitTopics({
@@ -74,11 +80,7 @@ export default class BesluitTopicToolbarDropdownComponent extends Component<Args
74
80
  return;
75
81
  }
76
82
 
77
- const besluit = findAncestorOfType(
78
- this.controller.mainEditorState.selection,
79
- this.controller.schema.nodes['besluit'],
80
- );
81
-
83
+ const besluit = this.decisionRange;
82
84
  if (!besluit) {
83
85
  console.warn(
84
86
  `We have a besluit URI (${currentBesluitURI}), but can't find a besluit ancestor`,
@@ -114,10 +116,6 @@ export default class BesluitTopicToolbarDropdownComponent extends Component<Args
114
116
  }
115
117
  }
116
118
 
117
- get showCard() {
118
- return !!getCurrentBesluitRange(this.controller);
119
- }
120
-
121
119
  @action
122
120
  upsertBesluitTopic(selected: BesluitTopic[]) {
123
121
  this.besluitTopicsSelected = selected;
@@ -4,11 +4,9 @@ import { action } from '@ember/object';
4
4
  import { addProperty, removeProperty } from '@lblod/ember-rdfa-editor/commands';
5
5
  import { SayController } from '@lblod/ember-rdfa-editor';
6
6
  import { sayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
7
- import { ResolvedPNode } from '@lblod/ember-rdfa-editor/plugins/datastore';
8
7
  import fetchBesluitTypes, {
9
8
  BesluitType,
10
9
  } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin/utils/fetchBesluitTypes';
11
- import { findAncestorOfType } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/article-structure-plugin/utils/structure';
12
10
  import { trackedFunction } from 'ember-resources/util/function';
13
11
  import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
14
12
  import { BesluitTypePluginOptions } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-type-plugin';
@@ -18,6 +16,7 @@ import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/i
18
16
  import { CrossIcon } from '@appuniversum/ember-appuniversum/components/icons/cross';
19
17
  import { MailIcon } from '@appuniversum/ember-appuniversum/components/icons/mail';
20
18
  import { CircleXIcon } from '@appuniversum/ember-appuniversum/components/icons/circle-x';
19
+ import { getCurrentBesluitRange } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
21
20
 
22
21
  type Args = {
23
22
  controller: SayController;
@@ -65,20 +64,8 @@ export default class EditorPluginsToolbarDropdownComponent extends Component<Arg
65
64
  return types;
66
65
  });
67
66
 
68
- get currentBesluitRange(): ResolvedPNode | undefined {
69
- const selection = this.controller.mainEditorState.selection;
70
- const besluit = findAncestorOfType(
71
- selection,
72
- this.controller.schema.nodes['besluit'],
73
- );
74
- if (!besluit) {
75
- return undefined;
76
- }
77
- return {
78
- node: besluit.node,
79
- from: besluit.start - 1,
80
- to: besluit.start + besluit.node.nodeSize - 1,
81
- };
67
+ get currentBesluitRange() {
68
+ return getCurrentBesluitRange(this.controller);
82
69
  }
83
70
 
84
71
  get currentBesluitURI() {
@@ -98,10 +85,7 @@ export default class EditorPluginsToolbarDropdownComponent extends Component<Arg
98
85
  if (!this.currentBesluitURI || !this.types.value) {
99
86
  return;
100
87
  }
101
- const besluit = findAncestorOfType(
102
- this.controller.mainEditorState.selection,
103
- this.controller.schema.nodes['besluit'],
104
- );
88
+ const besluit = this.currentBesluitRange;
105
89
  if (!besluit) {
106
90
  console.warn(
107
91
  `We have a besluit URI (${this.currentBesluitURI}), but can't find a besluit ancestor`,
@@ -0,0 +1,231 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+ import {
4
+ insertMotivation,
5
+ insertArticleContainer,
6
+ insertDescription,
7
+ insertTitle,
8
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/decision-plugin/commands';
9
+ import type { PNode, SayController, Selection } from '@lblod/ember-rdfa-editor';
10
+ import { service } from '@ember/service';
11
+ import IntlService from 'ember-intl/services/intl';
12
+ import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/icons/alert-triangle';
13
+ import { findAncestors } from '@lblod/ember-rdfa-editor/utils/position-utils';
14
+ import {
15
+ getOutgoingTriple,
16
+ hasOutgoingNamedNodeTriple,
17
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/namespace';
18
+ import {
19
+ BESLUIT,
20
+ ELI,
21
+ PROV,
22
+ RDF,
23
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
24
+ import { NodeWithPos } from '@curvenote/prosemirror-utils';
25
+ import AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
26
+ import AuButton from '@appuniversum/ember-appuniversum/components/au-button';
27
+ import { on } from '@ember/modifier';
28
+ import { not } from 'ember-truth-helpers';
29
+ import t from 'ember-intl/helpers/t';
30
+ import { TemplateOnlyComponent } from '@ember/component/template-only';
31
+
32
+ interface DecisionCardOptions {
33
+ articleUriGenerator?: () => string;
34
+ }
35
+ interface Sig {
36
+ Args: {
37
+ controller: SayController;
38
+ options?: DecisionCardOptions;
39
+ };
40
+ }
41
+
42
+ export default class DecisionPluginCard extends Component<Sig> {
43
+ @service declare intl: IntlService;
44
+
45
+ get controller() {
46
+ return this.args.controller;
47
+ }
48
+ get selection(): Selection {
49
+ return this.controller.mainEditorState.selection;
50
+ }
51
+
52
+ get decisionNodeLocation(): NodeWithPos | null {
53
+ return (
54
+ findAncestors(this.selection.$from, (node: PNode) => {
55
+ return hasOutgoingNamedNodeTriple(
56
+ node.attrs,
57
+ RDF('type'),
58
+ BESLUIT('Besluit'),
59
+ );
60
+ })[0] ?? null
61
+ );
62
+ }
63
+
64
+ @action
65
+ focus() {
66
+ this.controller.focus();
67
+ }
68
+ get canInsertTitle() {
69
+ return (
70
+ this.decisionNodeLocation &&
71
+ !getOutgoingTriple(this.decisionNodeLocation.node.attrs, ELI('title'))
72
+ );
73
+ }
74
+ @action
75
+ insertTitle() {
76
+ if (this.decisionNodeLocation) {
77
+ this.controller.doCommand(
78
+ insertTitle({
79
+ placeholderText: this.intl.t(
80
+ 'besluit-plugin.placeholder.decision-title',
81
+ ),
82
+ decisionLocation: this.decisionNodeLocation,
83
+ }),
84
+ { view: this.controller.mainEditorView },
85
+ );
86
+ }
87
+ this.focus();
88
+ }
89
+ get canInsertDescription() {
90
+ return (
91
+ this.decisionNodeLocation &&
92
+ !getOutgoingTriple(
93
+ this.decisionNodeLocation.node.attrs,
94
+ ELI('description'),
95
+ )
96
+ );
97
+ }
98
+ @action
99
+ insertDescription() {
100
+ if (this.decisionNodeLocation) {
101
+ this.controller.doCommand(
102
+ insertDescription({
103
+ placeholderText: this.intl.t(
104
+ 'besluit-plugin.placeholder.decision-description',
105
+ ),
106
+ decisionLocation: this.decisionNodeLocation,
107
+ }),
108
+ {
109
+ view: this.controller.mainEditorView,
110
+ },
111
+ );
112
+ }
113
+ this.focus();
114
+ }
115
+
116
+ get canInsertMotivation() {
117
+ return (
118
+ this.decisionNodeLocation &&
119
+ !getOutgoingTriple(
120
+ this.decisionNodeLocation.node.attrs,
121
+ BESLUIT('motivering'),
122
+ )
123
+ );
124
+ }
125
+
126
+ @action
127
+ insertMotivation() {
128
+ if (this.decisionNodeLocation) {
129
+ this.controller.doCommand(
130
+ insertMotivation({
131
+ intl: this.intl,
132
+ decisionLocation: this.decisionNodeLocation,
133
+ }),
134
+ {
135
+ view: this.controller.mainEditorView,
136
+ },
137
+ );
138
+ }
139
+ this.focus();
140
+ }
141
+
142
+ get missingArticleBlock() {
143
+ return (
144
+ this.decisionNodeLocation &&
145
+ !getOutgoingTriple(this.decisionNodeLocation.node.attrs, PROV('value'))
146
+ );
147
+ }
148
+ @action
149
+ insertArticleBlock() {
150
+ if (this.decisionNodeLocation) {
151
+ this.controller.doCommand(
152
+ insertArticleContainer({
153
+ intl: this.intl,
154
+ decisionLocation: this.decisionNodeLocation,
155
+ articleUriGenerator: this.args.options?.articleUriGenerator,
156
+ }),
157
+ {
158
+ view: this.controller.mainEditorView,
159
+ },
160
+ );
161
+ }
162
+ this.focus();
163
+ }
164
+
165
+ <template>
166
+ {{#if this.canInsertTitle}}
167
+ <ValidationCard
168
+ @enabled={{this.canInsertTitle}}
169
+ @title={{t 'besluit-plugin.missing-title-warning'}}
170
+ @onClickFix={{this.insertTitle}}
171
+ >
172
+ {{t 'besluit-plugin.insert.decision-title'}}
173
+ </ValidationCard>
174
+ {{/if}}
175
+ {{#if this.canInsertDescription}}
176
+ <ValidationCard
177
+ @enabled={{this.canInsertDescription}}
178
+ @title={{t 'besluit-plugin.missing-description-warning'}}
179
+ @onClickFix={{this.insertDescription}}
180
+ >
181
+ {{t 'besluit-plugin.insert.description'}}
182
+ </ValidationCard>
183
+ {{/if}}
184
+ {{#if this.canInsertMotivation}}
185
+ <ValidationCard
186
+ @enabled={{this.canInsertMotivation}}
187
+ @title={{t 'besluit-plugin.missing-motivation-warning'}}
188
+ @onClickFix={{this.insertMotivation}}
189
+ >
190
+ {{t 'besluit-plugin.insert.motivation'}}
191
+ </ValidationCard>
192
+ {{/if}}
193
+ {{#if this.missingArticleBlock}}
194
+ <ValidationCard
195
+ @enabled={{this.missingArticleBlock}}
196
+ @title={{t 'besluit-plugin.missing-article-block-warning'}}
197
+ @onClickFix={{this.insertArticleBlock}}
198
+ >
199
+ {{t 'besluit-plugin.insert.article-block'}}
200
+ </ValidationCard>
201
+ {{/if}}
202
+ </template>
203
+ }
204
+ interface ValidationCardSig {
205
+ Args: {
206
+ enabled: boolean;
207
+ onClickFix: () => void;
208
+ title: string;
209
+ };
210
+ Blocks: {
211
+ default: [];
212
+ };
213
+ }
214
+ const ValidationCard: TemplateOnlyComponent<ValidationCardSig> = <template>
215
+ <AuAlert
216
+ class='say-validation-alert'
217
+ @skin='warning'
218
+ @closable={{false}}
219
+ @icon={{AlertTriangleIcon}}
220
+ @title={{@title}}
221
+ >
222
+ <AuButton
223
+ @iconAlignment='left'
224
+ @skin='link-secondary'
225
+ @disabled={{not @enabled}}
226
+ {{on 'click' @onClickFix}}
227
+ >
228
+ {{yield}}
229
+ </AuButton>
230
+ </AuAlert>
231
+ </template>;
@@ -0,0 +1,81 @@
1
+ import AuButton from '@appuniversum/ember-appuniversum/components/au-button';
2
+ import { on } from '@ember/modifier';
3
+ import { action } from '@ember/object';
4
+ import Component from '@glimmer/component';
5
+ import { SayController } from '@lblod/ember-rdfa-editor';
6
+ import { getCurrentBesluitRange } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
7
+ import insertArticle from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/decision-plugin/commands/insert-article-command';
8
+ import { buildArticleStructure } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/decision-plugin/utils/build-article-structure';
9
+ import t from 'ember-intl/helpers/t';
10
+ import { not } from 'ember-truth-helpers';
11
+
12
+ export interface InsertArticleOptions {
13
+ uriGenerator?: () => string;
14
+ }
15
+ interface Sig {
16
+ Args: { controller: SayController; options?: InsertArticleOptions };
17
+ }
18
+ export default class InsertArticleComponent extends Component<Sig> {
19
+ get controller() {
20
+ return this.args.controller;
21
+ }
22
+
23
+ get schema() {
24
+ return this.controller.schema;
25
+ }
26
+ get decisionRange() {
27
+ return getCurrentBesluitRange(this.controller);
28
+ }
29
+ get decisionLocation() {
30
+ return this.decisionRange
31
+ ? { pos: this.decisionRange.from, node: this.decisionRange.node }
32
+ : null;
33
+ }
34
+ get canInsert() {
35
+ if (!this.decisionLocation) {
36
+ return false;
37
+ }
38
+ const article = buildArticleStructure(
39
+ this.schema,
40
+ this.args.options?.uriGenerator,
41
+ );
42
+ return this.controller.checkCommand(
43
+ insertArticle({ node: article, decisionLocation: this.decisionLocation }),
44
+ );
45
+ }
46
+
47
+ @action
48
+ doInsert() {
49
+ const structureNode = buildArticleStructure(
50
+ this.schema,
51
+ this.args.options?.uriGenerator,
52
+ );
53
+ if (!structureNode) {
54
+ return;
55
+ }
56
+ if (!this.decisionLocation) {
57
+ return;
58
+ }
59
+ this.controller.doCommand(
60
+ insertArticle({
61
+ node: structureNode,
62
+ decisionLocation: this.decisionLocation,
63
+ }),
64
+ );
65
+ this.controller.focus();
66
+ }
67
+
68
+ <template>
69
+ <li class='au-csidebar-list__item'>
70
+ <AuButton
71
+ @icon='add'
72
+ @iconAlignment='left'
73
+ @skin='link'
74
+ @disabled={{not this.canInsert}}
75
+ {{on 'click' this.doInsert}}
76
+ >
77
+ {{t 'besluit-plugin.insert.article'}}
78
+ </AuButton>
79
+ </li>
80
+ </template>
81
+ }
@@ -0,0 +1,68 @@
1
+ import { hash } from '@ember/helper';
2
+ import Component from '@glimmer/component';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { FunctionBasedModifier, modifier } from 'ember-modifier';
5
+ import { Velcro } from 'ember-velcro';
6
+ import { Signature as VelcroModifierSignature } from 'ember-velcro/modifiers/velcro';
7
+ import { ModifierLike } from '@glint/template';
8
+ export type Placement = VelcroModifierSignature['Args']['Named']['placement'];
9
+
10
+ interface HoverModifierSig {
11
+ Element: HTMLElement;
12
+ }
13
+ interface Sig {
14
+ Args: { placement?: Placement };
15
+ Blocks: {
16
+ hover: [
17
+ hover: {
18
+ velcroHook: ModifierLike<Velcro['velcroHook']>;
19
+ handleHover: ModifierLike<FunctionBasedModifier<HoverModifierSig>>;
20
+ },
21
+ ];
22
+ tooltip: [loop: ModifierLike<Velcro['velcroLoop']>];
23
+ };
24
+ }
25
+
26
+ export default class HoverTooltip extends Component<Sig> {
27
+ hover = modifier<HoverModifierSig>(
28
+ (element) => {
29
+ element.addEventListener('mouseenter', this.showTooltip);
30
+ element.addEventListener('mouseleave', this.hideTooltip);
31
+ element.addEventListener('focus', this.showTooltip);
32
+ element.addEventListener('blur', this.hideTooltip);
33
+ return () => {
34
+ element.removeEventListener('mouseenter', this.showTooltip);
35
+ element.removeEventListener('mouseleave', this.hideTooltip);
36
+ element.removeEventListener('focus', this.showTooltip);
37
+ element.removeEventListener('blur', this.hideTooltip);
38
+ };
39
+ },
40
+ { eager: false },
41
+ );
42
+ @tracked tooltipOpen = false;
43
+
44
+ get placement(): Placement | undefined {
45
+ return this.args.placement ?? 'top';
46
+ }
47
+
48
+ showTooltip = () => {
49
+ this.tooltipOpen = true;
50
+ };
51
+
52
+ hideTooltip = () => {
53
+ this.tooltipOpen = false;
54
+ };
55
+ <template>
56
+ <Velcro @placement={{this.placement}} as |velcro|>
57
+ {{#let velcro.loop as |loop|}}
58
+ {{yield
59
+ (hash velcroHook=velcro.hook handleHover=(modifier this.hover))
60
+ to='hover'
61
+ }}
62
+ {{#if this.tooltipOpen}}
63
+ {{yield loop to='tooltip'}}
64
+ {{/if}}
65
+ {{/let}}
66
+ </Velcro>
67
+ </template>
68
+ }
@@ -0,0 +1,15 @@
1
+ {{! @glint-nocheck: not typesafe yet }}
2
+ {{! template-lint-disable no-bare-strings }}
3
+ {{#if @inline}}
4
+ <span
5
+ {{did-insert this.handleInit}}
6
+ {{did-update this.onContentUpdate @content}}
7
+ ...attributes
8
+ />
9
+ {{else}}
10
+ <div
11
+ {{did-insert this.handleInit}}
12
+ {{did-update this.onContentUpdate @content}}
13
+ ...attributes
14
+ />
15
+ {{/if}}
@@ -0,0 +1,98 @@
1
+ import {
2
+ EditorState,
3
+ NodeSelection,
4
+ ProseParser,
5
+ SayController,
6
+ SayView,
7
+ Schema,
8
+ Transaction,
9
+ } from '@lblod/ember-rdfa-editor';
10
+ import { action } from '@ember/object';
11
+ import Component from '@glimmer/component';
12
+
13
+ type Args = {
14
+ onInit?(view: SayView): void;
15
+ onUpdate?(content: string): void;
16
+ onFocus?(view: SayView): void;
17
+ getPos(): number;
18
+ schema: Schema;
19
+ content?: string;
20
+ inline?: boolean;
21
+ controller: SayController;
22
+ outerView: SayView;
23
+ };
24
+
25
+ export default class ProseMirrorEditor extends Component<Args> {
26
+ view?: SayView;
27
+
28
+ initialContent: string;
29
+ constructor(owner: unknown, args: Args) {
30
+ super(owner, args);
31
+ this.initialContent = this.args.content || '';
32
+ }
33
+ get outerView(): SayView {
34
+ return this.args.outerView;
35
+ }
36
+ @action
37
+ handleInit(target: HTMLElement) {
38
+ const state = EditorState.create({ schema: this.args.schema });
39
+ const parser = ProseParser.fromSchema(this.args.schema);
40
+
41
+ this.view = new SayView(
42
+ { mount: target },
43
+ {
44
+ state,
45
+ domParser: parser,
46
+ dispatchTransaction: this.dispatch,
47
+ handleDOMEvents: {
48
+ mousedown: () => {
49
+ // Kludge to prevent issues due to the fact that the whole
50
+ // footnote is node-selected (and thus DOM-selected) when
51
+ // the parent editor is focused.
52
+
53
+ if (this.outerView.hasFocus()) this.view?.focus();
54
+ },
55
+ focus: () => {
56
+ const pos = this.args.getPos();
57
+ if (pos !== undefined) {
58
+ const outerSelectionTr = this.outerView.state.tr;
59
+ const outerSelection = new NodeSelection(
60
+ this.outerView.state.doc.resolve(pos),
61
+ );
62
+ outerSelectionTr.setSelection(outerSelection);
63
+ this.outerView.dispatch(outerSelectionTr);
64
+ }
65
+
66
+ if (this.view) {
67
+ this.args.controller.setActiveView(this.view);
68
+ this.args.onFocus?.(this.view);
69
+ }
70
+ },
71
+ },
72
+ },
73
+ );
74
+ if (this.args.content) {
75
+ this.view.setHtmlContent(this.initialContent);
76
+ }
77
+ this.args.onInit?.(this.view);
78
+ }
79
+
80
+ @action
81
+ onContentUpdate() {
82
+ if (this.view) {
83
+ const newContent = this.args.content;
84
+ const currentContent = this.view.htmlContent;
85
+ if (currentContent !== newContent) {
86
+ this.view.setHtmlContent(newContent ?? '');
87
+ }
88
+ }
89
+ }
90
+
91
+ dispatch = (tr: Transaction) => {
92
+ if (this.view) {
93
+ const newState = this.view.state.apply(tr);
94
+ this.view.updateState(newState);
95
+ this.args.onUpdate?.(this.view.htmlContent);
96
+ }
97
+ };
98
+ }
@@ -1,4 +1,3 @@
1
- import { findParentNode } from '@curvenote/prosemirror-utils';
2
1
  import { action } from '@ember/object';
3
2
  import Component from '@glimmer/component';
4
3
  import { tracked } from '@glimmer/tracking';
@@ -6,6 +5,7 @@ import { SayController } from '@lblod/ember-rdfa-editor';
6
5
  import { AddIcon } from '@appuniversum/ember-appuniversum/components/icons/add';
7
6
  import { OutgoingTriple } from '@lblod/ember-rdfa-editor/core/rdfa-processor';
8
7
  import { RDF } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/constants';
8
+ import { getCurrentBesluitRange } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/besluit-topic-plugin/utils/helpers';
9
9
 
10
10
  /**
11
11
  * Card displaying a hint of the Date plugin
@@ -53,24 +53,21 @@ export default class RoadsignRegulationCard extends Component<Args> {
53
53
  }
54
54
 
55
55
  get showCard() {
56
- const selection = this.controller.mainEditorState.selection;
57
- const besluitNode = findParentNode((node) => {
58
- if (node.type === this.schema.nodes['besluit']) {
59
- const properties = node.attrs.properties as OutgoingTriple[];
60
- const decisionHasAcceptedType = Boolean(
61
- properties.find((property) => {
62
- const { predicate, object } = property;
63
- return (
64
- RDF('type').matches(predicate) &&
65
- object.termType === 'NamedNode' &&
66
- acceptedTypes.includes(object.value)
67
- );
68
- }),
69
- );
70
- return decisionHasAcceptedType;
71
- }
56
+ const decisionRange = getCurrentBesluitRange(this.controller);
57
+ if (!decisionRange) {
72
58
  return false;
73
- })(selection);
74
- return !!besluitNode;
59
+ }
60
+ const decisionNode = decisionRange.node;
61
+ const properties: OutgoingTriple[] = decisionNode.attrs.properties;
62
+
63
+ const decisionHasAcceptedType = properties.some((property) => {
64
+ const { predicate, object } = property;
65
+ return (
66
+ RDF('type').matches(predicate) &&
67
+ object.termType === 'NamedNode' &&
68
+ acceptedTypes.includes(object.value)
69
+ );
70
+ });
71
+ return decisionHasAcceptedType;
75
72
  }
76
73
  }