Skip to content

Commit 669a483

Browse files
author
Tim Berners-Lee
committed
autocompleteField.ts is a nwe form field, which identifies an object in a public database by autocompleting on its name. Very early stage ... much to do still for this file.
1 parent d9a2e41 commit 669a483

1 file changed

Lines changed: 172 additions & 0 deletions

File tree

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/* Form field for doing autocompleete
2+
*/
3+
import { ns, style, widgets, store } from 'solid-ui'
4+
5+
// import { renderAutoComplete } from './autocompletePicker'
6+
import { renderAutocompleteControl } from './autocompletBar'
7+
8+
import { NamedNode, BlankNode, Variable, st } from 'rdflib'
9+
10+
/**
11+
* Render a autocomplete form field
12+
*
13+
* The same function is used for many similar one-value fields, with different
14+
* regexps used to validate.
15+
*
16+
* @param dom The HTML Document object aka Document Object Model
17+
* @param container If present, the created widget will be appended to this
18+
* @param already A hash table of (form, subject) kept to prevent recursive forms looping
19+
* @param subject The thing about which the form displays/edits data
20+
* @param form The form or field to be rendered
21+
* @param doc The web document in which the data is
22+
* @param callbackFunction Called when data is changed?
23+
*
24+
* @returns The HTML widget created
25+
*/
26+
// eslint-disable-next-line complexity
27+
export function autocompleteField (
28+
dom: HTMLDocument,
29+
container: HTMLElement | undefined,
30+
already,
31+
subject: NamedNode | BlankNode | Variable,
32+
form: NamedNode,
33+
doc: NamedNode | undefined,
34+
callbackFunction: (ok: boolean, errorMessage: string) => void
35+
): HTMLElement {
36+
async function addOneIdAndRefresh (result, _name) {
37+
const ds = kb.statementsMatching(subject, property as any) // remove any multiple values
38+
39+
let is = ds.map(statement => st(statement.subject, statement.predicate, result, statement.why)) // can include >1 doc
40+
if (is.length === 0) {
41+
// or none
42+
is = [st(subject, property as any, result, doc)]
43+
}
44+
try {
45+
await kb.updater.updateMany(ds, is)
46+
} catch (err) {
47+
callbackFunction(false, err)
48+
box.appendChild(widgets.errorMessageBlock(dom, 'Autocomplete form data write error:' + err))
49+
return
50+
}
51+
callbackFunction(true, '')
52+
}
53+
54+
const kb = store
55+
const formDoc = form.doc ? form.doc() : null // @@ if blank no way to know
56+
57+
const box = dom.createElement('tr')
58+
if (container) container.appendChild(box)
59+
const lhs = dom.createElement('td')
60+
lhs.setAttribute('class', 'formFieldName')
61+
lhs.setAttribute('style', ' vertical-align: middle;')
62+
box.appendChild(lhs)
63+
const rhs = dom.createElement('td')
64+
rhs.setAttribute('class', 'formFieldValue')
65+
box.appendChild(rhs)
66+
67+
const property = kb.any(form, ns.ui('property'))
68+
if (!property) {
69+
box.appendChild(
70+
dom.createTextNode('Error: No property given for autocomplete field: ' + form)
71+
)
72+
return box
73+
}
74+
const searchClass = kb.any(form, ns.ui('searchClass'))
75+
if (!searchClass) {
76+
return box.appendChild(
77+
dom.createTextNode('Error: No searchClass given for autocomplete field: ' + form)
78+
)
79+
}
80+
const endPoint = kb.any(form, ns.ui('endPoint'))
81+
if (!endPoint) {
82+
return box.appendChild(
83+
dom.createTextNode('Error: No SPARQL endPoint given for autocomplete field: ' + form)
84+
)
85+
}
86+
const queryTemplate = kb.any(form, ns.ui('queryTemplate'))
87+
if (!queryTemplate) {
88+
box.appendChild(
89+
dom.createTextNode('Error: No queryTemplate given for autocomplete field: ' + form)
90+
)
91+
return box
92+
}
93+
// It can be cleaner to just remove empty fields if you can't edit them anyway
94+
const suppressEmptyUneditable = kb.anyJS(form, ns.ui('suppressEmptyUneditable'), null, formDoc)
95+
const editable = kb.updater.editable((doc as NamedNode).uri)
96+
lhs.appendChild(widgets.fieldLabel(dom, property as any, form))
97+
const uri = widgets.mostSpecificClassURI(form)
98+
let params = widgets.fieldParams[uri]
99+
if (params === undefined) params = {} // non-bottom field types can do this
100+
// const theStyle = params.style || style.textInputStyle
101+
const klass = kb.the(form, ns.ui('category'), null, formDoc)
102+
/*
103+
{ label: string;
104+
logo: string;
105+
searchByNameQuery?: string;
106+
searchByNameURI?: string;
107+
insitituteDetailsQuery?: string;
108+
endPoint?: string;
109+
class: object
110+
}
111+
*/
112+
113+
const searchByNameQuery = kb.the(form, ns.ui('searchByNameQuery'), null, formDoc)
114+
const queryParams = {
115+
label: 'from form',
116+
logo: '',
117+
class: klass,
118+
endPoint: endPoint.uri,
119+
searchByNameQuery
120+
}
121+
122+
const options = { // cancelButton?: HTMLElement,
123+
// acceptButton?: HTMLElement,
124+
class: klass,
125+
queryParams
126+
}
127+
128+
rhs.appendChild(await renderAutocompleteControl(dom, subject, options, addOneIdAndRefresh))
129+
130+
// @@ set existing value is any
131+
// renderAutoComplete(dom, options, addOneIdAndRefresh).then(acWiget => rhs.appendChild(acWiget))
132+
133+
const field = dom.createElement('input')
134+
;(field as any).style = style.textInputStyle // Do we have to override length etc?
135+
rhs.appendChild(field)
136+
field.setAttribute('type', params.type ? params.type : 'text')
137+
138+
const size = kb.any(form, ns.ui('size')) // Form has precedence
139+
field.setAttribute(
140+
'size',
141+
size ? '' + size : params.size ? '' + params.size : '20'
142+
)
143+
const maxLength = kb.any(form, ns.ui('maxLength'))
144+
field.setAttribute('maxLength', maxLength ? '' + maxLength : '4096')
145+
146+
doc = doc || widgets.fieldStore(subject, property as any, doc)
147+
148+
let obj = kb.any(subject, property as any, undefined, doc)
149+
if (!obj) {
150+
obj = kb.any(form, ns.ui('default'))
151+
}
152+
if (obj) {
153+
field.value = obj.value || ''
154+
}
155+
field.setAttribute('style', style)
156+
if (!kb.updater) {
157+
throw new Error('kb has no updater')
158+
}
159+
if (!editable) {
160+
field.readOnly = true // was: disabled. readOnly is better
161+
;(field as any).style = style.textInputStyleUneditable
162+
// backgroundColor = textInputBackgroundColorUneditable
163+
if (suppressEmptyUneditable && field.value === '') {
164+
box.style.display = 'none' // clutter
165+
}
166+
return box
167+
}
168+
169+
return box
170+
}
171+
172+
// ends

0 commit comments

Comments
 (0)