@ulb-darmstadt/shacl-form 1.10.4 → 2.0.0-rc2

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 (55) hide show
  1. package/dist/bundle.d.ts +3 -0
  2. package/dist/bundle.js +415 -0
  3. package/dist/constants.d.ts +16 -16
  4. package/dist/constraints.d.ts +2 -2
  5. package/dist/form.d.ts +4 -3
  6. package/dist/index.js +62 -0
  7. package/dist/plugins/assets/plugin-VN3CfgGe.js +1 -0
  8. package/dist/plugins/file-upload.js +1 -0
  9. package/dist/plugins/leaflet.d.ts +8 -2
  10. package/dist/plugins/leaflet.js +5 -708
  11. package/dist/{themes/default.d.ts → theme.default.d.ts} +2 -2
  12. package/package.json +20 -26
  13. package/dist/form-bootstrap.d.ts +0 -5
  14. package/dist/form-bootstrap.js +0 -413
  15. package/dist/form-default.d.ts +0 -5
  16. package/dist/form-default.js +0 -402
  17. package/dist/form-material.d.ts +0 -5
  18. package/dist/form-material.js +0 -722
  19. package/dist/plugins/fixed-list.d.ts +0 -9
  20. package/dist/plugins/map-util.d.ts +0 -5
  21. package/dist/plugins/mapbox.d.ts +0 -19
  22. package/dist/plugins/mapbox.js +0 -2904
  23. package/dist/themes/bootstrap.d.ts +0 -10
  24. package/dist/themes/material.d.ts +0 -15
  25. package/src/config.ts +0 -110
  26. package/src/constants.ts +0 -30
  27. package/src/constraints.ts +0 -149
  28. package/src/exports.ts +0 -7
  29. package/src/form-bootstrap.ts +0 -12
  30. package/src/form-default.ts +0 -12
  31. package/src/form-material.ts +0 -12
  32. package/src/form.ts +0 -319
  33. package/src/globals.d.ts +0 -2
  34. package/src/group.ts +0 -34
  35. package/src/loader.ts +0 -187
  36. package/src/node.ts +0 -192
  37. package/src/plugin.ts +0 -60
  38. package/src/plugins/file-upload.ts +0 -26
  39. package/src/plugins/fixed-list.ts +0 -19
  40. package/src/plugins/leaflet.ts +0 -196
  41. package/src/plugins/map-util.ts +0 -41
  42. package/src/plugins/mapbox.ts +0 -157
  43. package/src/property-template.ts +0 -151
  44. package/src/property.ts +0 -309
  45. package/src/serialize.ts +0 -96
  46. package/src/shacl-engine.d.ts +0 -2
  47. package/src/styles.css +0 -49
  48. package/src/theme.ts +0 -132
  49. package/src/themes/bootstrap.css +0 -6
  50. package/src/themes/bootstrap.ts +0 -44
  51. package/src/themes/default.css +0 -4
  52. package/src/themes/default.ts +0 -258
  53. package/src/themes/material.css +0 -14
  54. package/src/themes/material.ts +0 -253
  55. package/src/util.ts +0 -275
package/src/serialize.ts DELETED
@@ -1,96 +0,0 @@
1
- import { DataFactory, NamedNode, Writer, Quad, Literal, Prefixes } from 'n3'
2
- import { PREFIX_XSD, RDF_PREDICATE_TYPE, PREFIX_SHACL } from './constants'
3
- import { Editor } from './theme'
4
- import { NodeObject } from 'jsonld'
5
-
6
- export function serialize(quads: Quad[], format: string, prefixes?: Prefixes): string {
7
- if (format === 'application/ld+json') {
8
- return serializeJsonld(quads)
9
- } else {
10
- const writer = new Writer({ format: format, prefixes: prefixes })
11
- writer.addQuads(quads)
12
- let serialized = ''
13
- writer.end((error, result) => {
14
- if (error) {
15
- console.error(error)
16
- }
17
- serialized = result
18
- })
19
- return serialized
20
- }
21
- }
22
-
23
- function serializeJsonld(quads: Quad[]): string {
24
- const triples: NodeObject[] = []
25
- for (const quad of quads) {
26
- const triple: NodeObject = { '@id': quad.subject.id }
27
-
28
- if (quad.predicate === RDF_PREDICATE_TYPE) {
29
- triple['@type'] = quad.object.id
30
- } else {
31
- let object: string | {} = quad.object.value
32
- if (quad.object instanceof Literal) {
33
- if (quad.object.language) {
34
- object = { '@language': quad.object.language, '@value': quad.object.value }
35
- } else if (quad.object.datatype && quad.object.datatype.value !== `${PREFIX_XSD}#string`) {
36
- object = { '@type': quad.object.datatype.value, '@value': quad.object.value }
37
- }
38
- } else {
39
- object = { '@id': quad.object.id }
40
- }
41
- triple[quad.predicate.value] = object
42
- }
43
- triples.push(triple)
44
- }
45
- return JSON.stringify(triples)
46
- }
47
-
48
- export function toRDF(editor: Editor): NamedNode | Literal | undefined {
49
- let languageOrDatatype: NamedNode<string> | string | undefined = editor.shaclDatatype
50
- let value: number | string = editor.value
51
- if (value) {
52
- if (value.startsWith('<') && value.endsWith('>') && value.indexOf(':') > -1) {
53
- return DataFactory.namedNode(value.substring(1, value.length - 1))
54
- } else if (editor.dataset.class || editor.dataset.nodeKind === PREFIX_SHACL + 'IRI') {
55
- return DataFactory.namedNode(value)
56
- } else if (editor.dataset.link) {
57
- return JSON.parse(editor.dataset.link)
58
- } else {
59
- if (editor.dataset.lang) {
60
- languageOrDatatype = editor.dataset.lang
61
- }
62
- else if (editor['type'] === 'number') {
63
- value = parseFloat(value)
64
- }
65
- else if (editor['type'] === 'file' && editor['binaryData']) {
66
- value = editor['binaryData']
67
- }
68
- else if (editor['type'] === 'datetime-local') {
69
- // if seconds in value are 0, the input field omits them which is then not a valid xsd:dateTime
70
- value = new Date(value).toISOString().slice(0, 19)
71
- }
72
- // check if value is a typed rdf literal or langString
73
- if (!languageOrDatatype && typeof value === 'string') {
74
- // check for typed rdf literal
75
- let tokens = value.split('^^')
76
- if (tokens.length === 2 && tokens[0].startsWith('"') && tokens[0].endsWith('"') && tokens[1].split(':').length === 2) {
77
- value = tokens[0].substring(1, tokens[0].length - 1)
78
- languageOrDatatype = DataFactory.namedNode(tokens[1])
79
- } else {
80
- // check for langString
81
- tokens = value.split('@')
82
- if (tokens.length === 2 && tokens[0].startsWith('"') && tokens[0].endsWith('"')) {
83
- value = tokens[0].substring(1, tokens[0].length - 1)
84
- languageOrDatatype = tokens[1]
85
- }
86
- }
87
- }
88
- return DataFactory.literal(value, languageOrDatatype)
89
- }
90
- } else if (editor['type'] === 'checkbox' || editor.getAttribute('type') === 'checkbox') {
91
- // emit boolean 'false' only when required
92
- if (editor['checked'] || parseInt(editor.dataset.minCount || '0') > 0) {
93
- return DataFactory.literal(editor['checked'] ? 'true' : 'false', languageOrDatatype)
94
- }
95
- }
96
- }
@@ -1,2 +0,0 @@
1
- declare module 'shacl-engine'
2
- declare module '@rdfjs/data-model'
package/src/styles.css DELETED
@@ -1,49 +0,0 @@
1
- form { display:block; --label-width: 8em; --caret-size: 10px; }
2
- form.mode-edit { padding-left: 1em; }
3
- form, form * { box-sizing: border-box; }
4
- shacl-node, .collapsible::part(content) { display: flex; flex-direction: column; width: 100%; position: relative; }
5
- shacl-node .remove-button { margin-left: 4px; margin-top: 1px; }
6
- shacl-node .add-button { color: #555; background-color: transparent; margin: 4px 24px 0 0; border: 0; }
7
- shacl-node .add-button:hover { color:#222; }
8
- shacl-node .add-button:focus { box-shadow: none; }
9
- shacl-node h1 { font-size: 16px; border-bottom: 1px solid #AAA; margin-top: 4px; color: #555; }
10
- shacl-property:not(:has(>.collapsible)), shacl-property>.collapsible::part(content) { display: flex; flex-direction: column; align-items: end; position: relative; }
11
- shacl-property:not(.may-add) > .add-button { display: none; }
12
- shacl-property:not(.may-remove) > .property-instance > .remove-button:not(.persistent) { visibility: hidden; }
13
- shacl-property:not(.may-remove) > .shacl-or-constraint > .remove-button:not(.persistent) { visibility: hidden; }
14
- .mode-view .shacl-group:not(:has(shacl-property)) { display: none; }
15
- .property-instance, .shacl-or-constraint { display: flex; align-items: flex-start; padding: 4px 0; width: 100%; position: relative; }
16
- .shacl-or-constraint > div { display: flex; flex-grow: 1; align-items: flex-start; }
17
- .shacl-or-constraint label { display: inline-block; word-break: break-word; width: var(--label-width); line-height: 1em; padding-top: 0.15em; padding-right: 1em; flex-shrink: 0; position: relative; }
18
- .property-instance label[title] { cursor: help; text-decoration: underline dashed #AAA; }
19
- .property-instance.linked label:after, label.linked:after { content: '\1F517'; font-size: 0.6em; padding-left: 6px; }
20
- .mode-edit .property-instance label.required::before { color: red; content: '\2736'; font-size: 0.6rem; position: absolute; left: -1.4em; top: 0.15rem; }
21
- .property-instance.valid::before { content: ''; position: absolute; left: calc(var(--label-width) - 1em); top:0.5em; width: 0.9em; height: 0.9em; background: url('data:image/svg+xml;utf8,<svg viewBox="0 0 1024 1024" fill="green" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M866.133333 258.133333L362.666667 761.6l-204.8-204.8L98.133333 618.666667 362.666667 881.066667l563.2-563.2z"/></svg>'); }
22
- .editor:not([type='checkbox']) { flex-grow: 1; }
23
- textarea.editor { resize: vertical; }
24
- .lang-chooser { border: 0; background-color: #e9e9ed; padding: 2px 4px; align-self: flex-start; }
25
- .validation-error { position: absolute; left: calc(var(--label-width) - 1em); color: red; cursor: help; }
26
- .validation-error::before { content: '\26a0' }
27
- .validation-error.node { left: -1em; }
28
- .invalid > .editor { border-color: red !important; }
29
- .ml-0 { margin-left: 0 !important; }
30
- .pr-0 { padding-right: 0 !important; }
31
- .mode-view .property-instance:not(:first-child) > label { visibility: hidden; }
32
- .mode-view .property-instance label { width: var(--label-width); }
33
-
34
- .d-flex { display: flex; }
35
- .lang { opacity: 0.65; font-size: 0.6em; }
36
- a, a:visited { color: inherit; }
37
-
38
- .fadeIn, .fadeOut { animation: fadeIn 0.2s ease-out; }
39
- .fadeOut { animation-direction: reverse; animation-timing-function: ease-out;}
40
- @keyframes fadeIn {
41
- 0% { opacity: 0; transform: scaleY(0.8); }
42
- 100% { opacity: 1; transform: scaleY(1); }
43
- }
44
- .collapsible::part(label) { font-weight: 600; }
45
- .collapsible > .property-instance:nth-child(even) { background-color: #F8F8F8; }
46
- .collapsible > .property-instance > shacl-node > h1 { display: none; }
47
- .ref-link { cursor: pointer; }
48
- .ref-link:hover { text-decoration: underline; }
49
- .node-id-display { color: #999; font-size: 11px; }
package/src/theme.ts DELETED
@@ -1,132 +0,0 @@
1
- import { Literal, NamedNode } from 'n3'
2
- import { Term } from '@rdfjs/types'
3
- import { PREFIX_XSD, PREFIX_RDF } from './constants'
4
- import { createInputListEntries, findInstancesOf, findLabel, isURL } from './util'
5
- import { ShaclPropertyTemplate } from './property-template'
6
- import css from './styles.css?raw'
7
-
8
- export type Editor = HTMLElement & { value: string, type?: string, shaclDatatype?: NamedNode<string>, binaryData?: string, checked?: boolean, disabled?: boolean }
9
- export type InputListEntry = { value: Term | string, label?: string, children?: InputListEntry[] }
10
-
11
- export abstract class Theme {
12
- stylesheet: CSSStyleSheet
13
-
14
- constructor(styles?: string) {
15
- let aggregatedStyles = css
16
- if (styles) {
17
- aggregatedStyles += '\n' + styles
18
- }
19
- this.stylesheet = new CSSStyleSheet()
20
- this.stylesheet.replaceSync(aggregatedStyles)
21
- }
22
-
23
- apply(_: HTMLFormElement) {
24
- // NOP
25
- }
26
-
27
- createViewer(label: string, value: Term, template: ShaclPropertyTemplate): HTMLElement {
28
- const viewer = document.createElement('div')
29
- const labelElem = document.createElement('label')
30
- labelElem.innerHTML = label + ':'
31
- if (template.description) {
32
- labelElem.setAttribute('title', template.description.value)
33
- }
34
- viewer.appendChild(labelElem)
35
- let name = value.value
36
- let lang: HTMLElement | null = null
37
- if (value instanceof NamedNode) {
38
- const quads = template.config.store.getQuads(name, null, null, null)
39
- if (quads.length) {
40
- const s = findLabel(quads, template.config.languages)
41
- if (s) {
42
- name = s
43
- }
44
- }
45
- } else if (value instanceof Literal) {
46
- if (value.language) {
47
- lang = document.createElement('span')
48
- lang.classList.add('lang')
49
- lang.innerText = `@${value.language}`
50
- } else if (value.datatype.value === `${PREFIX_XSD}date`) {
51
- name = new Date(Date.parse(value.value)).toDateString()
52
- } else if (value.datatype.value === `${PREFIX_XSD}dateTime`) {
53
- name = new Date(Date.parse(value.value)).toLocaleString()
54
- }
55
- }
56
- let valueElem: HTMLElement
57
- if (isURL(value.value)) {
58
- valueElem = document.createElement('a')
59
- valueElem.setAttribute('href', value.value)
60
- } else {
61
- valueElem = document.createElement('div')
62
- }
63
- valueElem.classList.add('d-flex')
64
- valueElem.innerText = name
65
- if (lang) {
66
- valueElem.appendChild(lang)
67
- }
68
- viewer.appendChild(valueElem)
69
- return viewer
70
- }
71
-
72
- abstract createListEditor(label: string, value: Term | null, required: boolean, listEntries: InputListEntry[], template?: ShaclPropertyTemplate): HTMLElement
73
- abstract createLangStringEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
74
- abstract createTextEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
75
- abstract createNumberEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
76
- abstract createDateEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
77
- abstract createBooleanEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
78
- abstract createFileEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement
79
- abstract createButton(label: string, primary: boolean): HTMLElement
80
- }
81
-
82
- export function fieldFactory(template: ShaclPropertyTemplate, value: Term | null, editable: boolean): HTMLElement {
83
- if (editable) {
84
- const required = template.minCount !== undefined && template.minCount > 0
85
- // if we have a class, find the instances and display them in a list
86
- if (template.class) {
87
- return template.config.theme.createListEditor(template.label, value, required, findInstancesOf(template.class, template), template)
88
- }
89
-
90
- // check if it is a list
91
- if (template.shaclIn) {
92
- const list = template.config.lists[template.shaclIn]
93
- if (list?.length) {
94
- const listEntries = createInputListEntries(list, template.config.store, template.config.languages)
95
- return template.config.theme.createListEditor(template.label, value, required, listEntries, template)
96
- }
97
- else {
98
- console.error('list not found:', template.shaclIn, 'existing lists:', template.config.lists)
99
- }
100
- }
101
-
102
- // check if it is a langstring
103
- if (template.datatype?.value === `${PREFIX_RDF}langString` || template.languageIn?.length) {
104
- return template.config.theme.createLangStringEditor(template.label, value, required, template)
105
- }
106
-
107
- switch (template.datatype?.value.replace(PREFIX_XSD, '')) {
108
- case 'integer':
109
- case 'float':
110
- case 'double':
111
- case 'decimal':
112
- return template.config.theme.createNumberEditor(template.label, value, required, template)
113
- case 'date':
114
- case 'dateTime':
115
- return template.config.theme.createDateEditor(template.label, value, required, template)
116
- case 'boolean':
117
- return template.config.theme.createBooleanEditor(template.label, value, required, template)
118
- case 'base64Binary':
119
- return template.config.theme.createFileEditor(template.label, value, required, template)
120
- }
121
-
122
- // nothing found (or datatype is 'string'), fallback to 'text'
123
- return template.config.theme.createTextEditor(template.label, value, required, template)
124
- } else {
125
- if (value) {
126
- return template.config.theme.createViewer(template.label, value, template)
127
- }
128
- const fallback = document.createElement('div')
129
- fallback.innerHTML = 'No value'
130
- return fallback
131
- }
132
- }
@@ -1,6 +0,0 @@
1
- form.mode-edit { --label-width: 0em; }
2
- .lang-chooser { right: 24px; font-size: 0.8em; }
3
- .property-instance[data-description]::after { content: attr(data-description); position: absolute; bottom: -12px; left: 13px; font-size: 12px; opacity: 0.7;}
4
- .property-instance { margin-bottom:14px; }
5
- .form-floating[data-description] { margin-bottom: 28px; }
6
- .remove-button { padding: 6px; }
@@ -1,44 +0,0 @@
1
- import { DefaultTheme } from './default'
2
- import { Term } from '@rdfjs/types'
3
- import { ShaclPropertyTemplate } from '../property-template'
4
- import { Editor } from '../theme'
5
- import bootstrap from 'bootstrap/dist/css/bootstrap.min.css?raw'
6
- import css from './bootstrap.css?raw'
7
-
8
- export class BootstrapTheme extends DefaultTheme {
9
- constructor() {
10
- super(bootstrap + '\n' + css)
11
- }
12
-
13
- apply(root: HTMLFormElement): void {
14
- super.apply(root)
15
- root.dataset.bsTheme = 'light'
16
- }
17
-
18
- createDefaultTemplate(label: string, value: Term | null, required: boolean, editor: Editor, template?: ShaclPropertyTemplate | undefined): HTMLElement {
19
- const result = super.createDefaultTemplate(label, value, required, editor, template)
20
- if (editor.type !== 'checkbox') {
21
- result.classList.add('form-floating')
22
- if (editor.tagName === 'SELECT') {
23
- editor.classList.add('form-select')
24
- } else {
25
- editor.classList.add('form-control')
26
- }
27
- }
28
- const labelElem = result.querySelector('label')
29
- labelElem?.classList.add('form-label')
30
- if (labelElem?.title) {
31
- result.dataset.description = labelElem.title
32
- labelElem.removeAttribute('title')
33
- }
34
-
35
- result.prepend(editor)
36
- return result
37
- }
38
-
39
- createButton(label: string, primary: boolean): HTMLElement {
40
- const button = super.createButton(label, primary)
41
- button.classList.add('btn', primary ? 'btn-primary' : 'btn-outline-secondary')
42
- return button
43
- }
44
- }
@@ -1,4 +0,0 @@
1
- .editor:not([type='checkbox']) { border: 1px solid #DDD; }
2
- .property-instance label { display: inline-flex; word-break: break-word; line-height: 1em; padding-top: 0.15em; padding-right: 1em; flex-shrink: 0; position: relative; }
3
- .property-instance:not(:first-child) > label:not(.persistent) { visibility: hidden; max-height: 0; }
4
- .mode-edit .property-instance label { width: var(--label-width); }
@@ -1,258 +0,0 @@
1
- import { Term } from '@rdfjs/types'
2
- import { ShaclPropertyTemplate } from "../property-template"
3
- import { Editor, InputListEntry, Theme } from "../theme"
4
- import { PREFIX_SHACL, PREFIX_XSD } from '../constants'
5
- import { Literal, NamedNode } from 'n3'
6
- import { Term as N3Term } from 'n3'
7
- import css from './default.css?raw'
8
- import { RokitInput, RokitSelect, RokitTextArea } from '@ro-kit/ui-widgets'
9
-
10
- export class DefaultTheme extends Theme {
11
- idCtr = 0
12
-
13
- constructor(overiddenCss?: string) {
14
- super(overiddenCss ? overiddenCss : css)
15
- }
16
-
17
- createDefaultTemplate(label: string, value: Term | null, required: boolean, editor: Editor, template?: ShaclPropertyTemplate): HTMLElement {
18
- editor.id = `e${this.idCtr++}`
19
- editor.classList.add('editor')
20
- if (template?.datatype) {
21
- // store datatype on editor, this is used for RDF serialization
22
- editor.shaclDatatype = template.datatype
23
- } else if (value instanceof Literal) {
24
- editor.shaclDatatype = value.datatype
25
- }
26
- if (template?.minCount !== undefined) {
27
- editor.dataset.minCount = String(template.minCount)
28
- }
29
- if (template?.class) {
30
- editor.dataset.class = template.class.value
31
- }
32
- if (template?.nodeKind) {
33
- editor.dataset.nodeKind = template.nodeKind.value
34
- } else if (value instanceof NamedNode) {
35
- editor.dataset.nodeKind = PREFIX_SHACL + 'IRI'
36
- }
37
- if (template?.hasValue || template?.readonly) {
38
- editor.disabled = true
39
- }
40
- editor.value = value?.value || template?.defaultValue?.value || ''
41
-
42
- const labelElem = document.createElement('label')
43
- labelElem.htmlFor = editor.id
44
- labelElem.innerText = label
45
- if (template?.description) {
46
- labelElem.setAttribute('title', template.description.value)
47
- }
48
-
49
- const placeholder = template?.description ? template.description.value : template?.pattern ? template.pattern : null
50
- if (placeholder) {
51
- editor.setAttribute('placeholder', placeholder)
52
- }
53
- if (required) {
54
- editor.setAttribute('required', 'true')
55
- labelElem.classList.add('required')
56
- }
57
-
58
- const result = document.createElement('div')
59
- result.appendChild(labelElem)
60
- result.appendChild(editor)
61
- return result
62
- }
63
-
64
- createDateEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
65
- const editor = new RokitInput()
66
- if (template.datatype?.value === PREFIX_XSD + 'dateTime') {
67
- editor.type = 'datetime-local'
68
- // this enables seconds in dateTime input
69
- editor.setAttribute('step', '1')
70
- }
71
- else {
72
- editor.type = 'date'
73
- }
74
- editor.clearable = true
75
- editor.dense = true
76
- editor.classList.add('pr-0')
77
- const result = this.createDefaultTemplate(label, null, required, editor, template)
78
- if (value) {
79
- try {
80
- let isoDate = new Date(value.value).toISOString()
81
- if (template.datatype?.value === PREFIX_XSD + 'dateTime') {
82
- isoDate = isoDate.slice(0, 19)
83
- } else {
84
- isoDate = isoDate.slice(0, 10)
85
- }
86
- editor.value = isoDate
87
- } catch(ex) {
88
- console.error(ex, value)
89
- }
90
- }
91
- return result
92
- }
93
-
94
- createTextEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
95
- let editor
96
- if (template.singleLine === false) {
97
- editor = new RokitTextArea()
98
- editor.resize = 'auto'
99
- }
100
- else {
101
- editor = new RokitInput()
102
- }
103
- editor.dense = true
104
- if (template.pattern) {
105
- editor.pattern = template.pattern
106
- }
107
- if (template.minLength) {
108
- editor.minLength = template.minLength
109
- }
110
- if (template.maxLength) {
111
- editor.maxLength = template.maxLength
112
- }
113
- return this.createDefaultTemplate(label, value, required, editor, template)
114
- }
115
-
116
- createLangStringEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
117
- const result = this.createTextEditor(label, value, required, template)
118
- const editor = result.querySelector(':scope .editor') as Editor
119
- let langChooser: HTMLSelectElement | HTMLInputElement
120
- if (template.languageIn?.length) {
121
- langChooser = document.createElement('select')
122
- for (const lang of template.languageIn) {
123
- const option = document.createElement('option')
124
- option.innerText = lang.value
125
- langChooser.appendChild(option)
126
- }
127
- } else {
128
- langChooser = document.createElement('input')
129
- langChooser.maxLength = 5 // e.g. en-US
130
- langChooser.size = 5
131
- langChooser.placeholder = 'lang?'
132
- }
133
- langChooser.title = 'Language of the text'
134
- langChooser.classList.add('lang-chooser')
135
- langChooser.slot = 'suffix'
136
- // if lang chooser changes, fire a change event on the text input instead. this is for shacl validation handling.
137
- langChooser.addEventListener('change', (ev) => {
138
- ev.stopPropagation();
139
- if (editor) {
140
- editor.dataset.lang = langChooser.value
141
- editor.dispatchEvent(new Event('change', { bubbles: true }))
142
- }
143
- })
144
- if (value instanceof Literal) {
145
- langChooser.value = value.language
146
- }
147
- editor.dataset.lang = langChooser.value
148
- editor.appendChild(langChooser)
149
- return result
150
- }
151
-
152
- createBooleanEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
153
- const editor = document.createElement('input')
154
- editor.type = 'checkbox'
155
- editor.classList.add('ml-0')
156
-
157
- const result = this.createDefaultTemplate(label, null, required, editor, template)
158
-
159
- // 'required' on checkboxes forces the user to tick the checkbox, which is not what we want here
160
- editor.removeAttribute('required')
161
- result.querySelector(':scope label')?.classList.remove('required')
162
- if (value instanceof Literal) {
163
- editor.checked = value.value === 'true'
164
- }
165
- return result
166
- }
167
-
168
- createFileEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
169
- const editor = document.createElement('input')
170
- editor.type = 'file'
171
- editor.addEventListener('change', (e) => {
172
- if (editor.files?.length) {
173
- e.stopPropagation()
174
- const reader = new FileReader()
175
- reader.readAsDataURL(editor.files[0])
176
- reader.onload = () => {
177
- (editor as Editor)['binaryData'] = btoa(reader.result as string)
178
- editor.parentElement?.dispatchEvent(new Event('change', { bubbles: true }))
179
- }
180
- } else {
181
- (editor as Editor)['binaryData'] = undefined
182
- }
183
- })
184
- return this.createDefaultTemplate(label, value, required, editor, template)
185
- }
186
-
187
- createNumberEditor(label: string, value: Term | null, required: boolean, template: ShaclPropertyTemplate): HTMLElement {
188
- const editor = new RokitInput()
189
- editor.type = 'number'
190
- editor.clearable = true
191
- editor.dense = true
192
- editor.classList.add('pr-0')
193
- const min = template.minInclusive !== undefined ? template.minInclusive : template.minExclusive !== undefined ? template.minExclusive + 1 : undefined
194
- const max = template.maxInclusive !== undefined ? template.maxInclusive : template.maxExclusive !== undefined ? template.maxExclusive - 1 : undefined
195
- if (min !== undefined) {
196
- editor.min = String(min)
197
- }
198
- if (max !== undefined) {
199
- editor.max = String(max)
200
- }
201
- if (template.datatype?.value !== PREFIX_XSD + 'integer') {
202
- editor.step = '0.1'
203
- }
204
- return this.createDefaultTemplate(label, value, required, editor, template)
205
- }
206
-
207
- createListEditor(label: string, value: Term | null, required: boolean, listEntries: InputListEntry[], template?: ShaclPropertyTemplate): HTMLElement {
208
- const editor = new RokitSelect()
209
- editor.clearable = true
210
- editor.dense = true
211
- const result = this.createDefaultTemplate(label, null, required, editor, template)
212
- const ul = document.createElement('ul')
213
- let isFlatList = true
214
-
215
- const appendListEntry = (entry: InputListEntry, parent: HTMLUListElement) => {
216
- const li = document.createElement('li')
217
- if (typeof entry.value === 'string') {
218
- li.dataset.value = entry.value
219
- li.innerText = entry.label ? entry.label : entry.value
220
- } else {
221
- li.dataset.value = (entry.value as N3Term).id
222
- if (entry.value instanceof NamedNode) {
223
- li.dataset.value = '<' + li.dataset.value + ">"
224
- }
225
- li.innerText = entry.label ? entry.label : entry.value.value
226
- }
227
- parent.appendChild(li)
228
- if (entry.children?.length) {
229
- isFlatList = false
230
- const ul = document.createElement('ul')
231
- li.appendChild(ul)
232
- for (const child of entry.children) {
233
- appendListEntry(child, ul)
234
- }
235
- }
236
- }
237
-
238
- for (const item of listEntries) {
239
- appendListEntry(item, ul)
240
- }
241
- if (!isFlatList) {
242
- editor.collapse = true
243
- }
244
-
245
- editor.appendChild(ul)
246
- if (value) {
247
- editor.value = (value as N3Term).id
248
- }
249
- return result
250
- }
251
-
252
- createButton(label: string, _: boolean): HTMLElement {
253
- const button = document.createElement('button')
254
- button.type = 'button'
255
- button.innerHTML = label
256
- return button
257
- }
258
- }
@@ -1,14 +0,0 @@
1
- :host {
2
- --mdui-color-primary-light: var(--mdui-color-primary-light);
3
- --mdui-color-primary-dark: var(--mdui-color-primary-dark);
4
- --mdui-color-background-light: var(--mdui-color-background-light);
5
- }
6
- /* this prevents hiding the date picker icon and number controls */
7
- mdui-text-field::part(input) {
8
- clip-path: none;
9
- appearance: inherit;
10
- }
11
- form.mode-edit { --label-width: 0em; }
12
- .property-instance { margin-bottom:14px; }
13
- .mode-edit .property-instance *[required]::part(icon) { align-self: flex-start; padding-top: 0.7em; }
14
- .mode-edit .property-instance *[required]::part(icon)::before { color: red; content: '\2736'; font-size: 0.6em; }