@lblod/ember-rdfa-editor-lblod-plugins 8.1.0 → 8.2.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.
package/CHANGELOG.md CHANGED
@@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [8.2.1] - 2023-06-28
11
+ ### Fixed
12
+ - GN-4200: Fixed bug with TOC scroll in GN and RB
13
+ ### Dependencies
14
+ - Bump `date-fns` from 2.29.3 to 2.30.0
15
+
16
+ ## [8.2.0] - 2023-06-26
17
+ ### Added
18
+ - Add a toggle to show the number as words in a number variable
19
+
20
+ ### Dependencies
21
+ - Bumps `sass` from 1.56.1 to 1.63.6
22
+ - Bumps `@types/ember` from 4.0.2 to 4.0.4
23
+ - Bumps `@types/ember-data__store` from 4.0.2 to 4.0.3
24
+ - Bumps `@types/ember__template` from 4.0.1 to 4.0.2
25
+ - Bumps `@types/rdfjs__parser-n3` from 1.1.5 to 2.0.1
26
+
10
27
  ## [8.1.0] - 2023-06-22
11
28
  ### Added
12
29
  - Numbers inputted into a number variable are validated on defined min/max and if it is a number
30
+ - Add toggle for the user to show number variable as words
13
31
 
14
32
  ### Fixed
15
33
  - Fixed woodpecker builds crashing on syntax errors
@@ -497,7 +515,7 @@ add onclick handler to pencil icon in variable plugin
497
515
 
498
516
  # Changelog
499
517
 
500
- [unreleased]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.1.0...HEAD
518
+ [unreleased]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.2.1...HEAD
501
519
  [8.0.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.0.0...v8.0.1
502
520
  [8.0.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v7.1.0...v8.0.0
503
521
  [7.1.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v7.0.0...v7.1.0
@@ -513,4 +531,6 @@ add onclick handler to pencil icon in variable plugin
513
531
  [3.0.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v2.1.2...v3.0.0
514
532
  [2.1.2]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v2.1.1...v2.1.2
515
533
  [2.1.1]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v2.1.0...v2.1.1
534
+ [8.2.1]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.2.0...v8.2.1
535
+ [8.2.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.1.0...v8.2.0
516
536
  [8.1.0]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v8.0.1...v8.1.0
package/README.md CHANGED
@@ -427,14 +427,17 @@ In order to enable the plugin you need to add the table of contents button to th
427
427
  ```
428
428
  ### Configuring the plugin with a custom config
429
429
 
430
- You can configure the nodeview with the hiearchy of the nodes
430
+ You can configure the nodeview with the hierarchy of the nodes.
431
+ For very custom setups, the plugin might be unable to find your scrollContainer (htmlElement providing scroll to your document). You can pass the scrollContainer element via the `scrollContainer()` function in the plugin config options instead.
431
432
 
432
433
  ```js
433
434
  {
434
435
  nodeHierarchy: [
435
436
  'title|chapter|section|subsection|article',
436
- 'structure_header|article_header',
437
- ],
437
+ 'structure_header|article_header',
438
+ ],
439
+ scrollContainer: () =>
440
+ document.getElementsByClassName('say-container__main')[0],
438
441
  },
439
442
  ```
440
443
 
@@ -1,8 +1,6 @@
1
1
  import Component from '@glimmer/component';
2
2
  import { action } from '@ember/object';
3
3
  import { inject as service } from '@ember/service';
4
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
- // @ts-ignore
6
4
  import { localCopy } from 'tracked-toolbox';
7
5
  import Intl from 'ember-intl/services/intl';
8
6
 
@@ -13,7 +11,6 @@ type Args = {
13
11
 
14
12
  export default class RdfaDatePluginDateTimePicker extends Component<Args> {
15
13
  @service declare intl: Intl;
16
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
17
14
  @localCopy('args.value') declare date?: Date;
18
15
 
19
16
  get hours() {
@@ -88,14 +88,28 @@ export default class TableOfContentsComponent extends Component<EmberNodeArgs> {
88
88
  selection.from
89
89
  );
90
90
  const config = this.config[0];
91
+ let scrollContainer: HTMLElement | undefined;
91
92
  if (config.scrollContainer) {
92
- const scrollContainer: HTMLElement = config.scrollContainer;
93
+ scrollContainer = config.scrollContainer();
94
+ } else {
95
+ scrollContainer = this.getScrollContainer();
96
+ }
97
+ if (scrollContainer) {
98
+ /*
99
+ coords.top = The distance from the top of the page to your element, this changes with the amount you
100
+ have scrolled so far
101
+ scrollContainerDistanceToTop = absolute y-coord of the start of the scroll container.
102
+ The difference between these two plus the alreadyScrolled distance is where we want to scroll
103
+ */
93
104
  const alreadyScrolled = scrollContainer.scrollTop;
94
- const MAGIC_NUMBER_TOPBAR_HEIGHT: number =
95
- config.scrollingPadding ?? 150;
105
+ const scrollContainerDistanceToTop =
106
+ scrollContainer.getBoundingClientRect().y;
107
+ const topPadding = 10; // We need top padding so the wanted position is not just on top of the page
96
108
  scrollContainer.scrollTo(
97
109
  0,
98
- coords.top + alreadyScrolled - MAGIC_NUMBER_TOPBAR_HEIGHT
110
+ coords.top +
111
+ alreadyScrolled -
112
+ (scrollContainerDistanceToTop + topPadding)
99
113
  );
100
114
  } else {
101
115
  tr.scrollIntoView();
@@ -105,4 +119,22 @@ export default class TableOfContentsComponent extends Component<EmberNodeArgs> {
105
119
  });
106
120
  this.controller.focus();
107
121
  }
122
+ getScrollContainer(): HTMLElement | undefined {
123
+ let currentElement = this.controller.mainEditorView.dom;
124
+ while (currentElement.parentElement) {
125
+ const parent = currentElement.parentElement;
126
+ if (this.isScrollable(parent)) {
127
+ return parent;
128
+ }
129
+ currentElement = parent;
130
+ }
131
+ return;
132
+ }
133
+ isScrollable(element: HTMLElement): boolean {
134
+ const hasScrollableContent = element.scrollHeight > element.clientHeight;
135
+ const overflowYStyle = window.getComputedStyle(element).overflowY;
136
+ const isOverflowHidden = overflowYStyle.indexOf('hidden') !== -1;
137
+
138
+ return hasScrollableContent && !isOverflowHidden;
139
+ }
108
140
  }
@@ -42,6 +42,13 @@
42
42
  {{on 'keyup' this.leaveWithArrows}}
43
43
  {{on 'keydown' this.setPosBeforeKeypress}}
44
44
  />
45
+ <AuToggleSwitch
46
+ @identifier="writtenNumber"
47
+ @name="writtenNumber"
48
+ @checked={{this.writtenNumber}}
49
+ @onChange={{this.changeWrittenNumber}}
50
+ @label={{t 'variable.number.written-number-label'}}
51
+ />
45
52
  {{#if this.errorMessage}}
46
53
  <AuHelpText @small={{true}} @error={{true}}>
47
54
  {{this.errorMessage}}
@@ -11,14 +11,13 @@ import { action } from '@ember/object';
11
11
  import { tracked } from '@glimmer/tracking';
12
12
  import { service } from '@ember/service';
13
13
  import intlService from 'ember-intl/services/intl';
14
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15
- // @ts-ignore
16
14
  import { localCopy } from 'tracked-toolbox';
17
15
  import {
18
16
  MAXIMUM_VALUE_PNODE_KEY,
19
17
  MINIMUM_VALUE_PNODE_KEY,
20
18
  } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/variable-plugin/utils/constants';
21
19
  import { isBlank } from '@ember/utils';
20
+ import n2words from 'n2words';
22
21
 
23
22
  type Args = {
24
23
  getPos: () => number | undefined;
@@ -30,8 +29,9 @@ type Args = {
30
29
  contentDecorations?: DecorationSource;
31
30
  };
32
31
  export default class VariableNumberPluginNumberComponent extends Component<Args> {
33
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
34
32
  @localCopy('args.node.attrs.value', '') declare inputNumber: string;
33
+ @localCopy('args.node.attrs.writtenNumber', false)
34
+ declare writtenNumber: boolean;
35
35
  @tracked errorMessage = '';
36
36
  @service declare intl: intlService;
37
37
  cursorPositionKeyDown: number | null = null;
@@ -44,7 +44,16 @@ export default class VariableNumberPluginNumberComponent extends Component<Args>
44
44
  return this.args.node;
45
45
  }
46
46
  get formattedNumber() {
47
- return this.node.attrs.value as string;
47
+ const value = this.node.attrs.value as string;
48
+
49
+ if (Number.isNaN(Number(value)) || value === null || value === '') {
50
+ return value;
51
+ }
52
+ if (!this.writtenNumber) {
53
+ return value;
54
+ } else {
55
+ return n2words(Number(value), { lang: 'nl' });
56
+ }
48
57
  }
49
58
 
50
59
  get selected() {
@@ -64,6 +73,11 @@ export default class VariableNumberPluginNumberComponent extends Component<Args>
64
73
  this.validateAndSave();
65
74
  }
66
75
 
76
+ @action
77
+ changeWrittenNumber() {
78
+ this.args.updateAttribute('writtenNumber', !this.writtenNumber);
79
+ }
80
+
67
81
  validateAndSave() {
68
82
  if (isBlank(this.inputNumber)) {
69
83
  this.errorMessage = '';
@@ -1,5 +1,4 @@
1
1
  export type TableOfContentsConfig = {
2
2
  nodeHierarchy: string[];
3
- scrollContainer?: HTMLElement;
4
- scrollingPadding?: number;
3
+ scrollContainer?: () => HTMLElement;
5
4
  }[];
@@ -14,8 +14,11 @@ import {
14
14
  MAXIMUM_VALUE_PNODE_KEY,
15
15
  MINIMUM_VALUE_HTML_ATTRIBUTE_KEY,
16
16
  MINIMUM_VALUE_PNODE_KEY,
17
+ WRITTEN_NUMBER_HTML_ATTRIBUTE_KEY,
18
+ WRITTEN_NUMBER_PNODE_KEY,
17
19
  } from './utils/constants';
18
20
  import { Attrs, DOMOutputSpec, PNode } from '@lblod/ember-rdfa-editor';
21
+ import n2words from 'n2words';
19
22
 
20
23
  export const CONTENT_SELECTOR = `span[property~='${EXT('content').prefixed}'],
21
24
  span[property~='${EXT('content').full}']`;
@@ -33,6 +36,10 @@ export const getHTMLNodeExtraAttributes = ({
33
36
  node.getAttribute(MINIMUM_VALUE_HTML_ATTRIBUTE_KEY) ?? null,
34
37
  [MAXIMUM_VALUE_PNODE_KEY]:
35
38
  node.getAttribute(MAXIMUM_VALUE_HTML_ATTRIBUTE_KEY) ?? null,
39
+ [WRITTEN_NUMBER_PNODE_KEY]:
40
+ node.getAttribute(WRITTEN_NUMBER_HTML_ATTRIBUTE_KEY) === 'true'
41
+ ? true
42
+ : false,
36
43
  };
37
44
  }
38
45
 
@@ -52,12 +59,40 @@ export const getPNodeExtraAttributes = ({
52
59
  (node.attrs[MINIMUM_VALUE_PNODE_KEY] as string) ?? null,
53
60
  [MAXIMUM_VALUE_HTML_ATTRIBUTE_KEY]:
54
61
  (node.attrs[MAXIMUM_VALUE_PNODE_KEY] as string) ?? null,
62
+ [WRITTEN_NUMBER_HTML_ATTRIBUTE_KEY]: String(
63
+ node.attrs[WRITTEN_NUMBER_PNODE_KEY] ?? false
64
+ ),
55
65
  };
56
66
  }
57
67
 
58
68
  return {};
59
69
  };
60
70
 
71
+ export const contentToDom = ({
72
+ content,
73
+ type,
74
+ node,
75
+ }: {
76
+ content: string;
77
+ type: string;
78
+ node: PNode;
79
+ }) => {
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' });
88
+ } else {
89
+ return content;
90
+ }
91
+ } else {
92
+ return content;
93
+ }
94
+ };
95
+
61
96
  export const parseAttributes = (node: HTMLElement): false | Attrs => {
62
97
  if (
63
98
  hasRDFaAttribute(node, 'typeof', EXT('Mapping')) &&
@@ -154,9 +189,10 @@ export const attributesToDOM = (node: PNode, content = null): DOMOutputSpec => {
154
189
  'span',
155
190
  {
156
191
  property: EXT('content').prefixed,
192
+ content: content ? content : '',
157
193
  ...(!!datatype && { datatype: datatype as string }),
158
194
  },
159
- content ? content : 0,
195
+ content ? contentToDom({ content, type: type as string, node }) : 0,
160
196
  ],
161
197
  ];
162
198
  };
@@ -196,6 +232,9 @@ export const emberNodeConfig: EmberNodeConfig = {
196
232
  maximumValue: {
197
233
  default: null,
198
234
  },
235
+ writtenNumber: {
236
+ default: false,
237
+ },
199
238
  },
200
239
  toDOM: (node) => {
201
240
  return attributesToDOM(node);
@@ -29,9 +29,9 @@ const emberNodeConfig = (): EmberNodeConfig => {
29
29
  getAttrs: (node: HTMLElement) => {
30
30
  const attrs = parseAttributes(node);
31
31
  if (attrs && attrs.type === 'number') {
32
- const content = [...node.children].find((el) =>
33
- hasRDFaAttribute(el, 'property', EXT('content'))
34
- )?.innerHTML;
32
+ const content = [...node.children]
33
+ .find((el) => hasRDFaAttribute(el, 'property', EXT('content')))
34
+ ?.getAttribute('content');
35
35
  return { ...attrs, value: content };
36
36
  } else {
37
37
  return false;
@@ -115,6 +115,8 @@ export const DEFAULT_VARIABLE_TYPES: Record<string, VariableType> = {
115
115
 
116
116
  export const MINIMUM_VALUE_PNODE_KEY = 'minimumValue';
117
117
  export const MAXIMUM_VALUE_PNODE_KEY = 'maximumValue';
118
+ export const WRITTEN_NUMBER_PNODE_KEY = 'writtenNumber';
118
119
 
119
120
  export const MINIMUM_VALUE_HTML_ATTRIBUTE_KEY = 'data-minimum-value';
120
121
  export const MAXIMUM_VALUE_HTML_ATTRIBUTE_KEY = 'data-maximum-value';
122
+ export const WRITTEN_NUMBER_HTML_ATTRIBUTE_KEY = 'data-written-number';
@@ -106,7 +106,7 @@
106
106
  }
107
107
 
108
108
  .say-number-tooltip {
109
- width: 140px;
109
+ width: 200px;
110
110
 
111
111
  // AuInput @type='number' overrides width to be 100px, we have to override it again
112
112
  input[type='number'] {
@@ -18,5 +18,7 @@ export default class TableOfContentsComponent extends Component<EmberNodeArgs> {
18
18
  pos: number;
19
19
  }): OutlineEntry[];
20
20
  moveToPosition(pos: number): void;
21
+ getScrollContainer(): HTMLElement | undefined;
22
+ isScrollable(element: HTMLElement): boolean;
21
23
  }
22
24
  export {};
@@ -12,6 +12,7 @@ type Args = {
12
12
  };
13
13
  export default class VariableNumberPluginNumberComponent extends Component<Args> {
14
14
  inputNumber: string;
15
+ writtenNumber: boolean;
15
16
  errorMessage: string;
16
17
  intl: intlService;
17
18
  cursorPositionKeyDown: number | null;
@@ -22,6 +23,7 @@ export default class VariableNumberPluginNumberComponent extends Component<Args>
22
23
  get minValue(): number;
23
24
  get maxValue(): number;
24
25
  onInputNumberChange(event: InputEvent): void;
26
+ changeWrittenNumber(): void;
25
27
  validateAndSave(): void;
26
28
  selectThisNode(): void;
27
29
  leaveOnEnter(event: KeyboardEvent): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lblod/ember-rdfa-editor-lblod-plugins",
3
- "version": "8.1.0",
3
+ "version": "8.2.1",
4
4
  "description": "Ember addon providing lblod specific plugins for the ember-rdfa-editor",
5
5
  "keywords": [
6
6
  "ember-addon",
@@ -39,10 +39,10 @@
39
39
  "@rdfjs/dataset": "^2.0.1",
40
40
  "@rdfjs/parser-n3": "^2.0.1",
41
41
  "@types/rdf-validate-shacl": "^0.4.0",
42
- "@types/rdfjs__parser-n3": "^1.1.5",
42
+ "@types/rdfjs__parser-n3": "^2.0.1",
43
43
  "buffer": "^6.0.3",
44
44
  "codemirror": "^6.0.1",
45
- "date-fns": "^2.29.3",
45
+ "date-fns": "^2.30.0",
46
46
  "ember-auto-import": "^2.4.3",
47
47
  "ember-cli-babel": "^7.26.11",
48
48
  "ember-cli-htmlbars": "^6.1.1",
@@ -53,6 +53,7 @@
53
53
  "ember-resources": "^5.6.2",
54
54
  "ember-velcro": "^1.1.0",
55
55
  "fetch-sparql-endpoint": "^3.0.0",
56
+ "n2words": "^1.16.4",
56
57
  "process": "0.11.10",
57
58
  "rdf-ext": "^2.1.0",
58
59
  "rdf-validate-shacl": "^0.4.5",
@@ -1,5 +1,4 @@
1
1
  export type TableOfContentsConfig = {
2
2
  nodeHierarchy: string[];
3
- scrollContainer?: HTMLElement;
4
- scrollingPadding?: number;
3
+ scrollContainer?: () => HTMLElement;
5
4
  }[];
@@ -7,9 +7,11 @@ export declare const getHTMLNodeExtraAttributes: ({ node, type, }: {
7
7
  }) => {
8
8
  minimumValue: string | null;
9
9
  maximumValue: string | null;
10
+ writtenNumber: boolean;
10
11
  } | {
11
12
  minimumValue?: undefined;
12
13
  maximumValue?: undefined;
14
+ writtenNumber?: undefined;
13
15
  };
14
16
  export declare const getPNodeExtraAttributes: ({ node, type, }: {
15
17
  node: PNode;
@@ -17,10 +19,17 @@ export declare const getPNodeExtraAttributes: ({ node, type, }: {
17
19
  }) => {
18
20
  "data-minimum-value": string;
19
21
  "data-maximum-value": string;
22
+ "data-written-number": string;
20
23
  } | {
21
24
  "data-minimum-value"?: undefined;
22
25
  "data-maximum-value"?: undefined;
26
+ "data-written-number"?: undefined;
23
27
  };
28
+ export declare const contentToDom: ({ content, type, node, }: {
29
+ content: string;
30
+ type: string;
31
+ node: PNode;
32
+ }) => string;
24
33
  export declare const parseAttributes: (node: HTMLElement) => false | Attrs;
25
34
  export declare const attributesToDOM: (node: PNode, content?: null) => DOMOutputSpec;
26
35
  export declare const emberNodeConfig: EmberNodeConfig;
@@ -14,5 +14,7 @@ export type VariableType = {
14
14
  export declare const DEFAULT_VARIABLE_TYPES: Record<string, VariableType>;
15
15
  export declare const MINIMUM_VALUE_PNODE_KEY = "minimumValue";
16
16
  export declare const MAXIMUM_VALUE_PNODE_KEY = "maximumValue";
17
+ export declare const WRITTEN_NUMBER_PNODE_KEY = "writtenNumber";
17
18
  export declare const MINIMUM_VALUE_HTML_ATTRIBUTE_KEY = "data-minimum-value";
18
19
  export declare const MAXIMUM_VALUE_HTML_ATTRIBUTE_KEY = "data-maximum-value";
20
+ export declare const WRITTEN_NUMBER_HTML_ATTRIBUTE_KEY = "data-written-number";
@@ -183,11 +183,12 @@ variable:
183
183
  number:
184
184
  placeholder: number
185
185
  type-number: Type a number...
186
- error-not-integer: Enkel gehele getallen zijn toegelaten
187
- error-not-number: Enkel getallen zijn toegelaten
188
- error-number-between: Het getal moet tussen {minValue} en {maxValue} liggen
189
- error-number-above: Het getal moet groter dan {minValue} zijn
190
- error-number-below: Het getal moet kleiner dan {maxValue} zijn
186
+ error-not-integer: Only integers are allowed
187
+ error-not-number: Only numbers are allowed
188
+ error-number-between: The number should be between {minValue} and {maxValue}
189
+ error-number-above: The number should be bigger than {minValue}
190
+ error-number-below: The number should be smaller than {maxValue}
191
+ written-number-label: Show as words
191
192
  variable-plugin:
192
193
  insert-variable: Insert variable
193
194
  button: Insert
@@ -195,11 +195,12 @@ variable:
195
195
  number:
196
196
  placeholder: nummer
197
197
  type-number: typ een nummer...
198
- error-not-integer: Only integers are allowed
199
- error-not-number: Only numbers are allowed
200
- error-number-between: The number should be between {minValue} and {maxValue}
201
- error-number-above: The number should be bigger than {minValue}
202
- error-number-below: The number should be smaller than {maxValue}
198
+ error-not-integer: Enkel gehele getallen zijn toegelaten
199
+ error-not-number: Enkel getallen zijn toegelaten
200
+ error-number-between: Het getal moet tussen {minValue} en {maxValue} liggen
201
+ error-number-above: Het getal moet groter dan {minValue} zijn
202
+ error-number-below: Het getal moet kleiner dan {maxValue} zijn
203
+ written-number-label: Getal voluit schrijven
203
204
  variable-plugin:
204
205
  insert-variable: Voeg variabele in
205
206
  button: Voeg in
package/types/global.d.ts CHANGED
@@ -5,3 +5,16 @@ declare module '@lblod/ember-rdfa-editor-lblod-plugins/templates/*' {
5
5
  const tmpl: TemplateFactory;
6
6
  export default tmpl;
7
7
  }
8
+ declare module 'n2words' {
9
+ export default function n2words(
10
+ number: number,
11
+ options: { lang: string }
12
+ ): string;
13
+ }
14
+
15
+ declare module 'tracked-toolbox' {
16
+ export function localCopy<C extends Component = Component, T = unknown>(
17
+ memo: UsefulPropsOf<C>,
18
+ initializer?: T | (() => T)
19
+ ): PropertyDecorator;
20
+ }