@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.
- package/dist/bundle.d.ts +3 -0
- package/dist/bundle.js +415 -0
- package/dist/constants.d.ts +16 -16
- package/dist/constraints.d.ts +2 -2
- package/dist/form.d.ts +4 -3
- package/dist/index.js +62 -0
- package/dist/plugins/assets/plugin-VN3CfgGe.js +1 -0
- package/dist/plugins/file-upload.js +1 -0
- package/dist/plugins/leaflet.d.ts +8 -2
- package/dist/plugins/leaflet.js +5 -708
- package/dist/{themes/default.d.ts → theme.default.d.ts} +2 -2
- package/package.json +20 -26
- package/dist/form-bootstrap.d.ts +0 -5
- package/dist/form-bootstrap.js +0 -413
- package/dist/form-default.d.ts +0 -5
- package/dist/form-default.js +0 -402
- package/dist/form-material.d.ts +0 -5
- package/dist/form-material.js +0 -722
- package/dist/plugins/fixed-list.d.ts +0 -9
- package/dist/plugins/map-util.d.ts +0 -5
- package/dist/plugins/mapbox.d.ts +0 -19
- package/dist/plugins/mapbox.js +0 -2904
- package/dist/themes/bootstrap.d.ts +0 -10
- package/dist/themes/material.d.ts +0 -15
- package/src/config.ts +0 -110
- package/src/constants.ts +0 -30
- package/src/constraints.ts +0 -149
- package/src/exports.ts +0 -7
- package/src/form-bootstrap.ts +0 -12
- package/src/form-default.ts +0 -12
- package/src/form-material.ts +0 -12
- package/src/form.ts +0 -319
- package/src/globals.d.ts +0 -2
- package/src/group.ts +0 -34
- package/src/loader.ts +0 -187
- package/src/node.ts +0 -192
- package/src/plugin.ts +0 -60
- package/src/plugins/file-upload.ts +0 -26
- package/src/plugins/fixed-list.ts +0 -19
- package/src/plugins/leaflet.ts +0 -196
- package/src/plugins/map-util.ts +0 -41
- package/src/plugins/mapbox.ts +0 -157
- package/src/property-template.ts +0 -151
- package/src/property.ts +0 -309
- package/src/serialize.ts +0 -96
- package/src/shacl-engine.d.ts +0 -2
- package/src/styles.css +0 -49
- package/src/theme.ts +0 -132
- package/src/themes/bootstrap.css +0 -6
- package/src/themes/bootstrap.ts +0 -44
- package/src/themes/default.css +0 -4
- package/src/themes/default.ts +0 -258
- package/src/themes/material.css +0 -14
- package/src/themes/material.ts +0 -253
- 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
|
-
}
|
package/src/shacl-engine.d.ts
DELETED
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
|
-
}
|
package/src/themes/bootstrap.css
DELETED
|
@@ -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; }
|
package/src/themes/bootstrap.ts
DELETED
|
@@ -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
|
-
}
|
package/src/themes/default.css
DELETED
|
@@ -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); }
|
package/src/themes/default.ts
DELETED
|
@@ -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
|
-
}
|
package/src/themes/material.css
DELETED
|
@@ -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; }
|