11import { property } from 'lit/decorators.js'
22import { html } from 'lit/html.js'
33import ns from '../../lib/ns'
4- import { customElement , generateId , WebComponent } from '@/lib/components'
5- import { NamedNode } from 'rdflib'
4+ import { customElement , WebComponent } from '@/lib/components'
5+ import { Literal , LiveStore , NamedNode , Statement , st } from 'rdflib'
66import { label } from '../../utils'
77import { mostSpecificClassURI } from '../../lib/forms/rdfFormsHelper'
8- import { fieldParams as fieldTypeParams , InputType } from '../../lib/forms/fieldParams'
8+ import { FieldParamsObject , fieldParams as fieldTypeParams , InputType } from '../../lib/forms/fieldParams'
99import { DEFAULT_STORE , storeContext , StoreContext } from '@/lib/forms/store/StoreContext'
1010import { consume } from '@lit/context'
1111import '@/components/input'
@@ -33,9 +33,7 @@ export default class RDFInput extends WebComponent {
3333 accessor readonly = true ;
3434
3535 render ( ) {
36- const formGraph = this . getFormGraph ( this . formSubject )
37- const statementCount = this . storeContext . store ?. statements ?. length ?? 0
38- console . log ( 'RDFInput render statement count:' , statementCount )
36+ const formGraph = this . getGraph ( this . formSubject )
3937
4038 // for building the HTML input element
4139 const uiPropertyTerm = this . getFormProperty ( this . formSubject , ns . ui ( 'property' ) , formGraph )
@@ -59,10 +57,11 @@ export default class RDFInput extends WebComponent {
5957 placeholder ="${ placeholder } "
6058 type="${ inputType } "
6159 ?readonly=${ readonly }
60+ @input=${ this . updateData ( ) }
6261 > </ solid-ui-input > `
6362 }
6463
65- private getFormGraph ( subject ?: NamedNode ) {
64+ private getGraph ( subject ?: NamedNode ) {
6665 return subject ?. doc ? subject . doc ( ) : undefined
6766 }
6867
@@ -113,4 +112,89 @@ export default class RDFInput extends WebComponent {
113112 const stripped = params . defaultInputValue ?? ''
114113 return stripped . replace ( / / g, '' )
115114 }
115+
116+ private updateData ( ) {
117+ return ( e : CustomEvent ) => {
118+ const newValue = ( e . target as HTMLInputElement ) . value
119+
120+ const uiPropertyTerm = this . getFormProperty ( this . formSubject , ns . ui ( 'property' ) , this . getGraph ( this . formSubject ) )
121+ if ( ! uiPropertyTerm || ! this . dataSubject ) return
122+
123+ const currentStoreContext = this . storeContext . store
124+ if ( ! currentStoreContext . updater . editable ( this . dataSubject ) ) return
125+
126+ const toDeleteSt = currentStoreContext . statementsMatching ( this . dataSubject , uiPropertyTerm )
127+
128+ if ( newValue ) {
129+ let objectFromNewValue
130+ const fieldType = this . formSubject ? mostSpecificClassURI ( this . storeContext . store , this . formSubject ) : undefined
131+ const params : FieldParamsObject = fieldType ? fieldTypeParams [ fieldType ] ?? { } : { }
132+ if ( params . namedNode ) {
133+ objectFromNewValue = currentStoreContext . sym ( newValue )
134+ } else if ( params . defaultInputValue ) {
135+ objectFromNewValue = encodeURIComponent ( newValue . replace ( / / g, '' ) )
136+ objectFromNewValue = currentStoreContext . sym ( params . defaultInputValue + objectFromNewValue )
137+ } else {
138+ if ( params . dt ) {
139+ objectFromNewValue = new Literal (
140+ newValue . trim ( ) ,
141+ undefined ,
142+ ns . xsd ( params . dt )
143+ )
144+ } else {
145+ objectFromNewValue = new Literal ( newValue )
146+ }
147+ }
148+ let toInsertSt = toDeleteSt . map ( statement => st ( statement . subject , statement . predicate , objectFromNewValue , statement . why ) ) // can include >1 doc
149+ if ( toInsertSt . length === 0 ) {
150+ toInsertSt = [ st ( this . formSubject , property as any , objectFromNewValue , this . getGraph ( this . dataSubject ) ) ]
151+ }
152+
153+ this . updateMany ( currentStoreContext , toDeleteSt , toInsertSt )
154+ }
155+ }
156+ }
157+
158+ private updateMany (
159+ store : LiveStore ,
160+ ds : Statement [ ] ,
161+ is : Statement [ ]
162+ ) {
163+ const getDocUri = ( statement : Statement ) => {
164+ const why = statement . why as any
165+ return why ?. uri ?? why ?. value
166+ }
167+
168+ const docs : string [ ] = [ ]
169+ is . forEach ( st => {
170+ const uri = getDocUri ( st )
171+ if ( uri && ! docs . includes ( uri ) ) docs . push ( uri )
172+ } )
173+ ds . forEach ( st => {
174+ const uri = getDocUri ( st )
175+ if ( uri && ! docs . includes ( uri ) ) docs . push ( uri )
176+ } )
177+ if ( docs . length === 0 ) {
178+ throw new Error ( 'No concrete document to update' )
179+ }
180+ if ( ! store . updater ) {
181+ throw new Error ( 'Store has no updater' )
182+ }
183+ if ( docs . length === 1 ) {
184+ return store . updater . update ( ds , is as any )
185+ }
186+
187+ const doc = docs . pop ( )
188+ const is1 = is . filter ( st => getDocUri ( st ) === doc )
189+ const is2 = is . filter ( st => getDocUri ( st ) !== doc )
190+ const ds1 = ds . filter ( st => getDocUri ( st ) === doc )
191+ const ds2 = ds . filter ( st => getDocUri ( st ) !== doc )
192+ store . updater . update ( ds1 , is1 as any , ( uri , ok , body ) => {
193+ if ( ok ) {
194+ this . updateMany ( store , ds2 , is2 )
195+ } else {
196+ throw new Error ( `Failed to update data for ${ uri } : ${ body } ` )
197+ }
198+ } )
199+ }
116200}
0 commit comments