Skip to content

Commit

Permalink
first draft of plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
s-tittel committed Jan 30, 2023
1 parent 17534f8 commit a7e82c8
Show file tree
Hide file tree
Showing 21 changed files with 13,338 additions and 3,853 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/
node_modules/
out-tsc/
11 changes: 9 additions & 2 deletions demo/data3.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .

<test> a dcat:Dataset, fidbau:ArchitectureModelDataset ;
<http://example.org/fidbau#4f2a8de3-9fc8-40a9-9237-d5964520ec54>
a dcat:Dataset, fidbau:ArchitectureModelDataset ;
dcterms:title "Einsteinturm" ;
dcterms:spatial [
a dcterms:Location ;
geo:asWKT "POINT(8.65,49.87)"^^geo:wktLiteral ;
dcterms:description "Building has been realized here" ;
] ;
schema:material "Holz" .
schema:material "Holz" ;
<http://purl.org/dc/terms/creator> _:n1150716783622461953 .
_:n1150716783622461953
<http://xmlns.com/foaf/0.1/name> "Stephan Tittel" ;
<http://xmlns.com/foaf/0.1/mbox> "[email protected]" ;
<http://purl.org/dc/terms/identifier> "https://orcid.org/0000-0002-0048-6835" ;
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Agent> .
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h3>SHACL form demo</h3>
<textarea id="shacl-data-input"></textarea>
<shacl-form id="shacl-form" class="bootstrap2"
data-language="de"
data-value-subject2="test"
data-value-subject2="http://example.org/fidbau#7c49b1eb-14fe-4e7a-bf11-0720e3499485"
>
<button type="submit" class="btn btn-primary" onclick="save()">Submit</button>
</shacl-form>
Expand Down
1 change: 1 addition & 0 deletions demo/shapes3.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ fidbau:Dataset
sh:name "Issued" ;
sh:description "Date when this dataset has been issued" ;
sh:path dcterms:issued ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:datatype xsd:date ;
], [
Expand Down
16,560 changes: 12,882 additions & 3,678 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ulb-darmstadt/shacl-form",
"version": "1.0.11",
"version": "1.0.12",
"description": "SHACL form generator",
"main": "dist/index.js",
"module": "dist/index.js",
Expand All @@ -25,15 +25,15 @@
],
"scripts": {
"build": "npm run clean && webpack --mode production",
"clean": "rm -rf dist && mkdir dist",
"clean": "rimraf dist",
"test": "echo \"no tests specified\" && exit 0",
"serve": "webpack serve --mode development"
},
"devDependencies": {
"@types/n3": "^1.10.4",
"buffer": "^6.0.3",
"css-loader": "^6.7.3",
"npm-dts-webpack-plugin": "^1.3.12",
"rimraf": "^4.1.2",
"save": "^2.9.0",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
Expand Down
131 changes: 131 additions & 0 deletions public/example1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example 1</title>
<script src="./index.js" type="module"></script>
</head>

<body>
<shacl-form
id="shacl-form"
data-shapes=""
>
<button type="submit" class="btn btn-primary" onclick="save()">Submit</button>
</shacl-form>
<script>
const form = document.getElementById("shacl-form")
form.dataset['shapes'] = `@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix schema: <http://schema.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dash: <http://datashapes.org/dash#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .
@prefix ex: <http://example.com/> .
@prefix lexvo: <http://lexvo.org/id/iso639-1/> .
ex:PersonShape
a sh:NodeShape ;
sh:targetClass schema:Person ;
rdfs:label "Person", "Osoba"@pl ;
sh:property ex:NameProperty ,
ex:KnowsProperty ,
ex:AgeProperty ,
ex:GenderProperty ,
ex:SpokenLanguagesProperty ,
ex:DateOfBirthProperty ,
ex:HomePageProperty ;
.
ex:SimplifiedPersonShape
a sh:NodeShape ;
sh:targetNode ex:Jane_Doe ;
rdfs:label "Person (name-only)", "Osoba (tylko imię)"@pl ;
sh:property ex:NameProperty ;
.
ex:NameProperty
sh:path schema:name ;
sh:name "Name" ;
sh:datatype xsd:string ;
dash:singleLine true ;
sh:maxCount 1 ;
sh:minCount 1 ;
sh:order 2 ;
sh:description "Enter the name of the person here. You should adhere to the scheme <firstname> <lastname>"
.
ex:KnowsProperty
sh:path schema:knows ;
sh:class schema:Person ;
sh:group ex:FriendGroup ;
sh:description "All the persons that this person knows"
.
ex:AgeProperty
sh:path schema:age ;
sh:name "Age", "Wiek"@pl ;
sh:datatype xsd:integer ;
sh:maxCount 1 ;
sh:defaultValue 21 ;
sh:order 2 ;
sh:minInclusive 18 ;
.
ex:GenderProperty
sh:path foaf:gender ;
sh:name "Gender", "Płeć"@pl ;
sh:in (
"Male" "Female" "Other" "Prefer not to tell"
) ;
sh:defaultValue "Male" ;
sh:maxCount 1 ;
sh:order 3 ;
sh:message "Please select a valid gender" ;
.
ex:DateOfBirthProperty
sh:path schema:birthDate ;
sh:name "Date of birth", "Data urodzenia"@pl ;
sh:maxCount 1 ;
sh:order 4 ;
sh:datatype xsd:date ;
.
ex:SpokenLanguagesProperty
sh:path vcard:language ;
sh:name "Spoken languages", "Języki"@pl ;
sh:nodeKind sh:IRI ;
sh:in (
lexvo:en lexvo:de lexvo:fr lexvo:pl lexvo:es
) ;
sh:order 5 ;
sh:minCount 1 ;
sh:maxCount 2 ;
.
ex:HomePageProperty
sh:path foaf:homepage ;
sh:name "Homepage URL", "Strona internetowa"@pl ;
sh:nodeKind sh:IRI ;
sh:order 6 ;
.
ex:FriendGroup
a sh:PropertyGroup ;
rdfs:label "Acquaintances", "Znajomi"@pl
.
lexvo:en rdfs:label "English", "angielski"@pl .
lexvo:de rdfs:label "German", "niemiecki"@pl .
lexvo:fr rdfs:label "French", "francuski"@pl .
lexvo:pl rdfs:label "Polish", "polski"@pl .
lexvo:es rdfs:label "Spanish", "hiszpański"@pl .`
</script>
</body>

</html>
14 changes: 10 additions & 4 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SHACL form demo</title>
<!-- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> -->
<style>
html,
body {
Expand Down Expand Up @@ -55,21 +56,26 @@ <h3>SHACL form demo</h3>
<option value="./data6.ttl">Data 6</option>
</select>
<div class="grid">
<!-- <iframe src="./example1.html"></iframe> -->
<textarea id="shacl-shape-input"></textarea>
<textarea id="shacl-data-input"></textarea>
<shacl-form id="shacl-form" class="bootstrap2"
data-language="de"
data-value-subject2="test"
data-shape-subject2="http://example.org/fidbau#ArchitectureModelDataset"
data-value-subject="http://example.org/fidbau#4f2a8de3-9fc8-40a9-9237-d5964520ec54"
>
<button type="submit" class="btn btn-primary" onclick="save()">Submit</button>
</shacl-form>
</div>
<pre id="shacl-output"></pre>
<script src="./index.js" type="module"></script>

<script src="./with-plugins.js" type="module"></script>
<script type="module">
import { BootstrapTheme } from './index.js'
import { FixedListPlugin, MapBoxPlugin } from './with-plugins.js'
const form = document.getElementById("shacl-form")
form.config.theme = new BootstrapTheme()
form.registerPlugin(new FixedListPlugin('http://purl.org/dc/terms/license', [{label:'CC-BY',value:'http://www.opendefinition.org/licenses/cc-by'}, {value:'http://license.org/2'}, {value:'http://license.org/3'}]))
form.registerPlugin(new MapBoxPlugin('http://www.opengis.net/ont/geosparql#asWKT', 'my-api-key'))

const shapes = document.getElementById("shacl-shape-input")
const data = document.getElementById("shacl-data-input")
const shapesChooser = document.getElementById("shacl-shape-input-chooser")
Expand Down
65 changes: 40 additions & 25 deletions src/form.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { ShaclNode } from './node'
import { ShaclProperty } from './property'
import { ShaclGroup } from './group'
import { InputDate, InputList, InputNumber, InputText } from './inputs'
import { Config } from './config'
import { Writer, Quad, Store, DataFactory, NamedNode, Parser } from 'n3'
import { Plugin, Plugins } from './plugin'
import { Writer, Quad, Store, DataFactory, NamedNode } from 'n3'
import { DEFAULT_PREFIXES, PREFIX_RDF, PREFIX_SHACL } from './prefixes'
import { focusFirstInputElement } from './util'
import SHACLValidator from 'rdf-validate-shacl'
import factory from 'rdf-ext'
import './styles.css'
import { DefaultTheme, Theme } from './theme'
import { DefaultTheme, Theme } from './theme.js'

export class ShaclForm extends HTMLElement {
static get observedAttributes() { return Config.keysAsDataAttributes }

config: Config = new Config()
shape: ShaclNode | undefined
form: HTMLFormElement
plugins: Plugins = {}
initTimeout: ReturnType<typeof setTimeout> | undefined

constructor() {
Expand All @@ -36,31 +41,33 @@ export class ShaclForm extends HTMLElement {
attributeChangedCallback() {
const newConfig = Config.from(this)
if (!newConfig.equals(this.config)) {
clearTimeout(this.initTimeout)
this.initTimeout = setTimeout(() => {
this.config = newConfig
this.config.loadGraphs().then(_ => this.initialize()).catch(e => {
console.log(e)
if (this.shape && this.form.contains(this.shape)) {
this.form.removeChild(this.shape)
}
})
}, 20)
this.config = newConfig
this.initialize()
}
}

private initialize() {
if (this.shape && this.form.contains(this.shape)) {
this.form.removeChild(this.shape)
}
clearTimeout(this.initTimeout)
this.initTimeout = setTimeout(() => {
this.config.loadGraphs().then(_ => {
if (this.shape && this.form.contains(this.shape)) {
this.form.removeChild(this.shape)
}

// find root shacl shape
const rootShapeShaclSubject = this.findRootShaclShapeSubject()
if (rootShapeShaclSubject) {
this.shape = new ShaclNode(this.config, rootShapeShaclSubject, null, this.config.valueSubject ? new NamedNode(this.config.valueSubject) : undefined)
this.form.prepend(this.shape)
focusFirstInputElement(this.shape)
}
// find root shacl shape
const rootShapeShaclSubject = this.findRootShaclShapeSubject()
if (rootShapeShaclSubject) {
this.shape = new ShaclNode(this, rootShapeShaclSubject, undefined, this.config.valueSubject ? new NamedNode(this.config.valueSubject) : undefined)
this.form.prepend(this.shape)
focusFirstInputElement(this.shape)
}
}).catch(e => {
console.log(e)
if (this.shape && this.form.contains(this.shape)) {
this.form.removeChild(this.shape)
}
})
}, 20)
}

public toRDF(): Quad[] {
Expand All @@ -84,6 +91,11 @@ export class ShaclForm extends HTMLElement {
return serialized
}

public registerPlugin(plugin: Plugin) {
this.plugins[plugin.predicate] = plugin
this.initialize()
}

public reportValidity(): boolean {
return this.form.reportValidity()
}
Expand All @@ -97,7 +109,7 @@ export class ShaclForm extends HTMLElement {
const validator = new SHACLValidator(shapes, { factory })
// const report = await validator.validate(data)
const report = await validator.validate(factory.dataset(this.toRDF()))

console.log('--- validation results', report.results)
for (const result of report.results) {
// See https://www.w3.org/TR/shacl/#results-validation-result for details about each property
Expand All @@ -116,7 +128,7 @@ export class ShaclForm extends HTMLElement {
}
return report.conforms
}


private findRootShaclShapeSubject(): NamedNode | undefined {
let rootShapeShaclSubject: NamedNode | null = null
Expand Down Expand Up @@ -160,7 +172,7 @@ export class ShaclForm extends HTMLElement {
rootShapeShaclSubject = rootShapes[0].subject as NamedNode
}
}
else {
else {
// choose first of all defined root shapes
const rootShapes = this.config.shapesGraph.getQuads(null, `${PREFIX_RDF}type`, `${PREFIX_SHACL}NodeShape`, null)
if (rootShapes.length == 0) {
Expand All @@ -179,3 +191,6 @@ export class ShaclForm extends HTMLElement {
}

window.customElements.define('shacl-form', ShaclForm)
window.customElements.define('shacl-node', ShaclNode)
window.customElements.define('shacl-property', ShaclProperty)
window.customElements.define('shacl-group', ShaclGroup)
2 changes: 0 additions & 2 deletions src/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,3 @@ export class ShaclGroup extends HTMLElement {
this.appendChild(header)
}
}

window.customElements.define('shacl-group', ShaclGroup)
2 changes: 2 additions & 0 deletions src/index-with-plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index'
export * from './plugins/index'
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { ShaclForm } from './form'
export { ShaclProperty } from './property'
export { Plugin } from './plugin'
export { InputBase, Editor } from './inputs'
export { Theme, BootstrapTheme, DefaultTheme } from './theme'
Loading

0 comments on commit a7e82c8

Please sign in to comment.