UNPKG

solid-app-set

Version:
1,076 lines (997 loc) 77.7 kB
// Original author: kennyluck // // Kenny's Notes: /* places to generate SPARQL update: clearInputAndSave() pasteFromClipboard()->insertTermTo(); undetermined statement generated formUndetStat() ->fillInRequest() ontological issues temporarily using the tabont namespace clipboard: 'predicates' 'objects' 'all'(internal) request: 'from' 'to' 'message' 'Request' */ var UserInputFormula // Formula to store references of user's work var TempFormula // Formula to store incomplete tripes (Requests), // temporarily disjoint with kb to avoid bugs var UI = require('solid-ui') module.exports = function UserInput (outline) { var kb = UI.store var myDocument = outline.document // is this ok? // UI.log.warn("myDocument when it's set is "+myDocument.location); this.menuId = 'predicateMenu1' /* //namespace information, as a subgraph of the knowledge base, is built in showMenu this.namespaces={}; for (var name in UI.ns) { this.namespaces[name] = UI.ns[name]('').uri; } var NameSpaces=this.namespaces; */ // hq, print and trim functions var qp = function qp (str) { console.log(str + '\n') } // var tabont = UI.ns.tabont; // var foaf = UI.ns.foaf const rdf = UI.ns.rdf // var RDFS = UI.ns.rdfs // var OWL = UI.ns.owl // var dc = UI.ns.dc // var rss = UI.ns.rss // var contact = UI.ns.contact // var mo = UI.ns.mo var bibo = UI.rdf.Namespace('http://purl.org/ontology/bibo/') // hql for pubsPane // var dcterms = UI.rdf.Namespace('http://purl.org/dc/terms/') var dcelems = UI.rdf.Namespace('http://purl.org/dc/elements/1.1/') var movedArrow = false // hq // var updateService=new updateCenter(kb); if (!UserInputFormula) { UserInputFormula = new UI.rdf.Formula() UserInputFormula.superFormula = kb // UserInputFormula.registerFormula("Your Work"); } if (!TempFormula) TempFormula = new UI.rdf.IndexedFormula() // Use RDFIndexedFormula so add returns the statement TempFormula.name = 'TempFormula' if (!UI.store.updater) UI.store.updater = new UI.rdf.UpdateManager(kb) return { // updateService: updateService, sparqler: UI.store.updater, lastModified: null, // the last <input> being modified, .isNew indicates whether it's a new input lastModifiedStat: null, // the last statement being modified statIsInverse: false, // whether the statement is an inverse /** * Triggering Events: event entry points, should be called only from outline.js but not anywhere else * in userinput.js, should be as short as possible, function names to be discussed */ // Called when the blue cross under the default pane is clicked. // Add a new row to a property list ( P and O) addNewPredicateObject: function addNewPredicateObject (e) { if (UI.utils.getTarget(e).className !== 'bottom-border-active') return var This = outline.UserInput var target = UI.utils.getTarget(e) // UI.log.warn(ancestor(target,'TABLE').textContent); var insertTr = myDocument.createElement('tr') UI.utils.ancestor(target, 'DIV').insertBefore(insertTr, UI.utils.ancestor(target, 'TR')) var tempTr = myDocument.createElement('tr') var reqTerm1 = This.generateRequest('(TBD)', tempTr, true) insertTr.appendChild(tempTr.firstChild) var reqTerm2 = This.generateRequest('(Enter text or drag an object onto this field)', tempTr, false) insertTr.appendChild(tempTr.firstChild) // there should be an elegant way of doing this // Take the why of the last TR and write to it. if (UI.utils.ancestor(target, 'TR').previousSibling && // there is a previous predicate/object line UI.utils.ancestor(target, 'TR').previousSibling.AJAR_statement) { let preStat = UI.utils.ancestor(target, 'TR').previousSibling.AJAR_statement // This should always(?) input a non-inverse statement This.formUndetStat(insertTr, preStat.subject, reqTerm1, reqTerm2, preStat.why, false) } else { // no previous row: write to the document defining the subject var subject = UI.utils.getAbout(kb, UI.utils.ancestor(target.parentNode.parentNode, 'TD')) var doc = kb.sym(UI.rdf.Util.uri.docpart(subject.uri)) This.formUndetStat(insertTr, subject, reqTerm1, reqTerm2, doc, false) } outline.walk('moveTo', insertTr.firstChild) UI.log.info('addNewPredicateObject: selection = ' + outline.getSelection().map(function (item) { return item.textContent }).join(', ')) this.startFillInText(outline.getSelection()[0]) }, // Called when a blue cross on a predicate is clicked // tr.AJAR_inverse stores whether the clicked predicate is an inverse one // tr.AJAR_statement (an incomplete statement in TempFormula) stores the destination(why), now // determined by the preceding one (is this good?) addNewObject: function addNewObject (e) { var predicateTd = UI.utils.getTarget(e).parentNode.parentNode // var predicateTerm = UI.utils.getAbout(kb, predicateTd) var isInverse = predicateTd.parentNode.AJAR_inverse // var titleTerm=UI.utils.getAbout(kb,UI.utils.ancestor(predicateTd.parentNode,'TD')); // set pseudo lastModifiedStat here this.lastModifiedStat = predicateTd.parentNode.AJAR_statement var insertTr = this.appendToPredicate(predicateTd) var reqTerm = this.generateRequest(' (Error) ', insertTr, false) let preStat = insertTr.previousSibling.AJAR_statement if (!isInverse) { this.formUndetStat(insertTr, preStat.subject, preStat.predicate, reqTerm, preStat.why, false) } else { this.formUndetStat(insertTr, reqTerm, preStat.predicate, preStat.object, preStat.why, true) } outline.walk('moveTo', insertTr.lastChild) this.startFillInText(insertTr.lastChild) // this.statIsInverse=false; }, // Called when delete is pressed Delete: function Delete (selectedTd) { this.deleteTriple(selectedTd, false) }, // Called when enter is pressed Enter: function Enter (selectedTd) { this.literalModification(selectedTd) }, // Called when a selected cell is clicked again Click: function Click (e) { var target = UI.utils.getTarget(e) if (UI.utils.getTerm(target).termType !== 'Literal') return this.literalModification(target) // this prevents the generated inputbox to be clicked again e.preventDefault() e.stopPropagation() }, // Called when paste is called (Ctrl+v) pasteFromClipboard: function pasteFromClipboard (address, selectedTd) { function termFrom (fromCode) { var term = outline.clipboard[fromCode].shift() if (term === null) { UI.log.warn('no more element in clipboard!') return } switch (fromCode) { case 'predicates': case 'objects': var allArray = outline.clipboard.all for (var i = 0; true; i++) { if (term.sameTerm(allArray[i])) { allArray.splice(i, 1) break } } break case 'all': throw new Error('hostorical code not understood - what is theCollection?') /* var isObject = term.sameTerm(theCollection('objects').elements[0]) isObject ? outline.clipboard.objecs.shift() : outline.clipboard.predicates.shift() // drop the corresponding term return [term, isObject] break */ } return term } var term switch (selectedTd.className) { case 'undetermined selected': term = selectedTd.nextSibling ? termFrom('predicates') : termFrom('objects') if (!term) return break case 'pred selected': // paste objects into this predicate term = termFrom('objects') if (!term) return break case 'selected': // header <TD>, undetermined generated var returnArray = termFrom('all') if (!returnArray) return term = returnArray[0] this.insertTermTo(selectedTd, term, returnArray[1]) return } this.insertTermTo(selectedTd, term) }, /** * Intermediate Processing: */ // a general entry point for any event except Click&Enter(goes to literalModification) // do a little inference to pick the right inputbox startFillInText: function startFillInText (selectedTd) { switch (this.whatSortOfEditCell(selectedTd)) { case 'DatatypeProperty-like': // this.clearMenu(); // selectedTd.className=''; UI.utils.emptyNode(selectedTd) this.lastModified = this.createInputBoxIn(selectedTd, ' (Please Input) ') this.lastModified.isNew = false this.lastModified.select() break case 'predicate': // the goal is to bring back all the menus (with autocomplete functionality // this.performAutoCompleteEdit(selectedTd,['PredicateAutoComplete', // this.choiceQuery('SuggestPredicateByDomain')]); this.performAutoCompleteEdit(selectedTd, 'PredicateAutoComplete') break case 'ObjectProperty-like': case 'no-idea': // menu should be either function that this.performAutoCompleteEdit(selectedTd, 'GeneralAutoComplete') /* //<code time="original"> emptyNode(selectedTd); this.lastModified=this.createInputBoxIn(selectedTd,""); this.lastModified.select(); this.lastModified.addEventListener('keypress',this.AutoComplete,false); //this pops up the autocomplete menu this.AutoComplete(1); //</code> */ } }, literalModification: function literalModification (selectedTd) { UI.log.debug('entering literal Modification with ' + selectedTd + selectedTd.textContent) // var This=outline.UserInput; if (selectedTd.className.indexOf(' pendingedit') !== -1) { UI.log.warn('The node you attempted to edit has a request still pending.\n' + 'Please wait for the request to finish (the text will turn black)\n' + 'before editing this node again.') return true } var target = selectedTd var about = this.getStatementAbout(target) // timbl - to avoid alert from random clicks if (!about) return try { var obj = UI.utils.getTerm(target) var trNode = UI.utils.ancestor(target, 'TR') } catch (e) { UI.log.warn('userinput.js: ' + e + UI.utils.getAbout(kb, selectedTd)) UI.log.error(target + ' getStatement Error:' + e) } try { var tdNode = trNode.lastChild } catch (e) { UI.log.error(e + '@' + target) } // seems to be a event handling problem of firefox3 /* if (e.type!='keypress'&&(selectedTd.className=='undetermined selected'||selectedTd.className=='undetermined')){ this.Refill(e,selectedTd); return; } */ // ignore clicking trNode.firstChild (be careful for <div> or <span>) // if (e.type!='keypress'&&target!=tdNode && UI.utils.ancestor(target,'TD')!=tdNode) return; if (obj.termType === 'Literal') { tdNode.removeChild(tdNode.firstChild) // remove the text if (obj.value.match('\n')) { // match a line feed and require <TEXTAREA> var textBox = myDocument.createElement('textarea') textBox.appendChild(myDocument.createTextNode(obj.value)) textBox.setAttribute('rows', (obj.value.match(/\n/g).length + 1).toString()) // g is for global(??) textBox.setAttribute('cols', '100') // should be the size of <TD> textBox.setAttribute('class', 'textinput') tdNode.appendChild(textBox) this.lastModified = textBox } else { this.lastModified = this.createInputBoxIn(tdNode, obj.value) } this.lastModified.isNew = false // Kenny: What should be expected after you click a editable text element? // Choice 1 this.lastModified.select() // Choice 2 - direct the key cursor to where you click (failed attempt) // -------------------------------------------------------------------------- // duplicate the event so user can edit without clicking twice // var e2=myDocument.createEvent("MouseEvents"); // e2.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null); // inputBox.dispatchEvent(e2); // --------------------------------------------------------------------------- } return true // this is not a valid modification }, /** * UIs: input event handlers, menu generation */ performAutoCompleteEdit: function performAutoCompleteEdit (selectedTd, menu) { UI.utils.emptyNode(selectedTd) qp('perform AutoCompleteEdit. THIS IS=' + this) this.lastModified = this.createInputBoxIn(selectedTd, '') this.lastModified.select() this.lastModified.addEventListener('keypress', this.getAutoCompleteHandler(menu), false) /* keypress!? This is what I hate about UI programming. I shall write something about this but not now. */ // this pops up the autocomplete menu // Pops up the menu even though no keypress has occured // 1 is a dummy variable for the "enterEvent" this.getAutoCompleteHandler(menu)(1) }, backOut: function backOut () { this.deleteTriple(this.lastModified.parentNode, true) this.lastModified = null }, clearMenu: function clearMenu () { var menu = myDocument.getElementById(this.menuID) if (menu) { menu.parentNode.removeChild(menu) // emptyNode(menu); } }, /* goes here when either this is a literal or escape from menu and then input text */ clearInputAndSave: function clearInputAndSave (e) { if (!this.lastModified) return if (!this.lastModified.isNew) { try { var obj = this.getStatementAbout(this.lastModified).object } catch (e) { return } } var s = this.lastModifiedStat // when 'isNew' this is set at addNewObject() if (this.lastModified.value !== this.lastModified.defaultValue) { if (this.lastModified.value === '') { // ToDo: remove this this.lastModified.value = this.lastModified.defaultValue this.clearInputAndSave() return } else if (this.lastModified.isNew) { s = new UI.rdf.Statement(s.subject, s.predicate, kb.literal(this.lastModified.value), s.why) // TODO: DEFINE ERROR CALLBACK var defaultpropview = this.views.defaults[s.predicate.uri] var trCache = UI.utils.ancestor(this.lastModified, 'TR') try { UI.store.updater.update([], [s], function (uri, success, errorBody) { if (!success) { UI.log.error('Error occurs while inserting ' + s + '\n\n' + errorBody + '\n') // UI.log.warn("Error occurs while inserting "+s+'\n\n'+errorBody); outline.UserInput.deleteTriple(trCache.lastChild, true) } }) } catch (e) { UI.log.error('Error inserting fact ' + s + ':\n\t' + e + '\n') return } s = kb.add(s.subject, s.predicate, kb.literal(this.lastModified.value), s.why) } else { if (this.statIsInverse) { UI.log.error("Invalid Input: a literal can't be a subject in RDF/XML") this.backOut() return } var s1, s2, s3 switch (obj.termType) { case 'Literal': // generate path and nailing from current values // TODO: DEFINE ERROR CALLBACK var valueCache = this.lastModified.value trCache = UI.utils.ancestor(this.lastModified, 'TR') var oldValue = this.lastModified.defaultValue s2 = $rdf.st(s.subject, s.predicate, kb.literal(this.lastModified.value), s.why) try { UI.store.updater.update([s], [s2], function (uri, success, errorBody) { if (success) { obj.value = valueCache } else { UI.log.warn('Error occurs while editing ' + s + '\n\n' + errorBody) trCache.lastChild.textContent = oldValue } trCache.lastChild.className = trCache.lastChild.className.replace(/ pendingedit/g, '') }) } catch (e) { UI.log.warn('Error occurs while editing ' + s + ':\n\t' + e) return } // obj.value=this.lastModified.value; // UserInputFormula.statements.push(s); break case 'BlankNode': // a request refill with text // var newStat var textTerm = kb.literal(this.lastModified.value, '') // <Feature about="labelChoice"> if (s.predicate.termType === 'Collection') { // case: add triple ????????? Weird - tbl var selectedPredicate = s.predicate.elements[0] // @@ TBL elements is a list on the predicate?? if (kb.any(undefined, selectedPredicate, textTerm)) { if (!e) { // keyboard var tdNode = this.lastModified.parentNode e = {} e.pageX = UI.utils.findPos(tdNode)[0] e.pageY = UI.utils.findPos(tdNode)[1] + tdNode.clientHeight } this.showMenu(e, 'DidYouMeanDialog', undefined, {'dialogTerm': kb.any(undefined, selectedPredicate, textTerm), 'bnodeTerm': s.subject}) } else { s1 = UI.utils.ancestor(UI.utils.ancestor(this.lastModified, 'TR').parentNode, 'TR').AJAR_statement s2 = $rdf.st(s.subject, selectedPredicate, textTerm, s.why) var type = kb.the(s.subject, rdf('type')) s3 = kb.anyStatementMatching(s.subject, rdf('type'), type, s.why) // TODO: DEFINE ERROR CALLBACK // because the table is repainted, so... trCache = UI.utils.ancestor(UI.utils.ancestor(this.lastModified, 'TR'), 'TD').parentNode try { UI.store.updater.update([], [s1, s2, s3], function (uri, success, errorBody) { if (!success) { console.log('Error occurs while editing ' + s1 + '\n\n' + errorBody) outline.UserInput.deleteTriple(trCache.lastChild, true) // @@@@ This } }) } catch (e) { console.log('Error occurs while editing ' + s1 + ':\n\t' + e) return } kb.remove(s) kb.add(s.subject, selectedPredicate, textTerm, s.why) // was: newStat = // a subtle bug occurs here, if foaf:nick hasn't been dereferneced, // this add will cause a repainting } var enclosingTd = UI.utils.ancestor(this.lastModified.parentNode.parentNode, 'TD') const defaultPane = UI.panes.default // @@ check outline.outlineExpand(enclosingTd, s.subject, {'pane': defaultPane, 'already': true}) outline.walk('right', outline.focusTd) // </Feature> } else { this.fillInRequest('object', this.lastModified.parentNode, kb.literal(this.lastModified.value)) return // The new Td is already generated by fillInRequest, so it's done. } break } } } else if (this.lastModified.isNew) { // generate 'Request', there is no way you can input ' (Please Input) ' var trNode = UI.utils.ancestor(this.lastModified, 'TR') var reqTerm = this.generateRequest('(To be determined. Re-type of drag an object onto this field)') var preStat = trNode.previousSibling.AJAR_statement // the statement of the same predicate this.formUndetStat(trNode, preStat.subject, preStat.predicate, reqTerm, preStat.why, false) // this why being the same as the previous statement this.lastModified = null // UI.log.warn("test .isNew)"); return } else if (s.predicate.termType === 'Collection') { kb.removeMany(s.subject) var upperTr = UI.utils.ancestor(UI.utils.ancestor(this.lastModified, 'TR').parentNode, 'TR') preStat = upperTr.AJAR_statement reqTerm = this.generateRequest('(To be determined. Re-type of drag an object onto this field)') this.formUndetStat(upperTr, preStat.subject, preStat.predicate, reqTerm, preStat.why, false) outline.replaceTD(outline.outlineObjectTD(reqTerm, defaultpropview), upperTr.lastChild) this.lastModified = null return } else /* if ((s.object.termType === 'BlankNode' && !this.statIsInverse) || s.subject.termType === 'BlankNode' && this.statIsInverse) { this.backOut() return */ if (this.statIsInverse) { if (s.subject.termType === 'BlankNode') { this.backOut() return } } else { if (s.object.termType === 'BlankNode') { this.backOut() return } } // case modified - literal modification only(for now). trNode = UI.utils.ancestor(this.lastModified, 'TR') // var defaultpropview = this.views.defaults[s.predicate.uri] if (!this.statIsInverse) { // this is for an old feature // outline.replaceTD(outline.outlineObjectTD(s.object, defaultpropview),trNode.lastChild); outline.replaceTD(outline.outlineObjectTD(kb.literal(this.lastModified.value), defaultpropview), trNode.lastChild) } else { outline.replaceTD(outline.outlineObjectTD(s.subject, defaultpropview), trNode.lastChild) } if (this.lastModified.value !== this.lastModified.defaultValue) { trNode.lastChild.className += ' pendingedit' } // trNode.AJAR_statement=s;//you don't have to set AJAR_inverse because it's not changed // This is going to be painful when predicate-edit allowed this.lastModified = null }, /* deletes the triple corresponding to selectedTd, remove that Td. */ deleteTriple: function deleteTriple (selectedTd, isBackOut) { // ToDo: complete deletion of a node UI.log.debug('deleteTriple entered') // allow a pending node to be deleted if it's a backout sent by SPARQL update callback if (!isBackOut && selectedTd.className.indexOf(' pendingedit') !== -1) { console.log('The node you attempted to edit has a request still pending.\n' + 'Please wait for the request to finish (the text will turn black)\n' + 'before editing this node again.') outline.walk('up') return } var removedTr // var afterTr var s = this.getStatementAbout(selectedTd) if (!isBackOut && !kb.whether(s.object, rdf('type'), UI.ns.link('Request')) && // Better to check whether provenance is internal? !kb.whether(s.predicate, rdf('type'), UI.ns.link('Request')) && !kb.whether(s.subject, rdf('type'), UI.ns.link('Request'))) { UI.log.debug('about to send SPARQLUpdate') try { UI.store.updater.update([s], [], function (uri, success, errorBody) { if (success) { removefromview() } else { // removedTr.AJAR_statement=kb.add(s.subject,s.predicate,s.object,s.why); console.log('Error occurs while deleting ' + s + '\n\n' + errorBody) selectedTd.className = selectedTd.className.replace(/ pendingedit/g, '') } }) selectedTd.className += ' pendingedit' } catch (e) { UI.log.error(e) UI.log.warn('Error deleting statement ' + s + ':\n\t' + e) return } UI.log.debug('SPARQLUpdate sent') } else { // removal of an undetermined statement associated with pending TRs // TempFormula.remove(s); } UI.log.debug('about to remove ' + s) UI.log.debug('removed') outline.walk('up') removedTr = selectedTd.parentNode // afterTr = removedTr.nextSibling function removefromview () { var trIterator for (trIterator = removedTr; trIterator.childNodes.length === 1; trIterator = trIterator.previousSibling); if (trIterator === removedTr) { var theNext = trIterator.nextSibling if (theNext.nextSibling && theNext.childNodes.length === 1) { var predicateTd = trIterator.firstChild predicateTd.setAttribute('rowspan', parseInt(predicateTd.getAttribute('rowspan')) - 1) theNext.insertBefore(trIterator.firstChild, theNext.firstChild) } removedTr.parentNode.removeChild(removedTr) } else { // !DisplayOptions["display:block on"].enabled){ predicateTd = trIterator.firstChild predicateTd.setAttribute('rowspan', parseInt(predicateTd.getAttribute('rowspan')) - 1) removedTr.parentNode.removeChild(removedTr) } } if (isBackOut) removefromview() }, /* clipboard principle: copy wildly, paste carefully ToDoS: 1. register Subcollection? 2. copy from more than one selectedTd: 1.sequece 2.collection 3. make a clipboard class? */ clipboardInit: function clipboardInit () { outline.clipboard = {} outline.clipboard.objects = [] outline.clipboard.predicates = [] outline.clipboard.all = [] }, copyToClipboard: function copyToClipboard (address, selectedTd) { /* var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard); if (!clip) return false; var clipid = Components.interfaces.nsIClipboard; var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); if (!trans) return false; var copytext = "Tabulator!!"; var str = Components.classes["@mozilla.org/supports-string;1"]. createInstance(Components.interfaces.nsISupportsString); if (!str) return false; str.data = copytext; trans.addDataFlavor("text/x-moz-url"); trans.setTransferData("text/x-mox-url", str, copytext.length * 2); clip.setData(trans, null, clipid.kGlobalClipboard); */ var term = UI.utils.getTerm(selectedTd) switch (selectedTd.className) { case 'selected': // table header case 'obj selected': // var objects = outline.clipboard.objects outline.clipboard.objects.unshift(term) break case 'pred selected': case 'pred internal selected': outline.clipboard.predicates.unshift(term) } outline.clipboard.all.unshift(term) }, insertTermTo: function insertTermTo (selectedTd, term, isObject) { switch (selectedTd.className) { case 'undetermined selected': var defaultpropview = this.views.defaults[selectedTd.parentNode.AJAR_statement.predicate.uri] this.fillInRequest(selectedTd.nextSibling ? 'predicate' : 'object', selectedTd, term) break case 'pred selected': // paste objects into this predicate var insertTr = this.appendToPredicate(selectedTd) var preStat = selectedTd.parentNode.AJAR_statement defaultpropview = this.views.defaults[preStat.predicate.uri] insertTr.appendChild(outline.outlineObjectTD(term, defaultpropview)) // modify store and update here var isInverse = selectedTd.parentNode.AJAR_inverse if (!isInverse) { insertTr.AJAR_statement = kb.add(preStat.subject, preStat.predicate, term, preStat.why) } else { insertTr.AJAR_statemnet = kb.add(term, preStat.predicate, preStat.object, preStat.why) } try { UI.store.updater.update([ ], [insertTr.AJAR_statement], function (uri, success, errorBody) { if (!success) { UI.log.error('userinput.js (pred selected): Fail trying to insert statement ' + insertTr.AJAR_statement + ': ' + errorBody) } }) } catch (e) { UI.log.error('Exception trying to insert statement ' + insertTr.AJAR_statement + ': ' + UI.utils.stackString(e)) return } insertTr.AJAR_inverse = isInverse UserInputFormula.statements.push(insertTr.AJAR_statement) break case 'selected': // header <TD>, undetermined generated var paneDiv = UI.utils.ancestor(selectedTd, 'TABLE').lastChild var newTr = paneDiv.insertBefore(myDocument.createElement('tr'), paneDiv.lastChild) // var titleTerm=UI.utils.getAbout(kb,UI.utils.ancestor(newTr,'TD')); preStat = newTr.previousSibling.AJAR_statement if (typeof isObject === 'undefined') isObject = true if (isObject) { // object inserted this.formUndetStat(newTr, preStat.subject, this.generateRequest('(TBD)', newTr, true), term, preStat.why, false) // defaultpropview temporaily not dealt with newTr.appendChild(outline.outlineObjectTD(term)) outline.walk('moveTo', newTr.firstChild) this.startFillInText(newTr.firstChild) } else { // predicate inserted // existing predicate not expected var reqTerm = this.generateRequest('(To be determined. Re-type of drag an object onto this field)', newTr) this.formUndetStat(newTr, preStat.subject, term, reqTerm, preStat.why, false) newTr.insertBefore(outline.outlinePredicateTD(term, newTr, false, false), newTr.firstChild) outline.walk('moveTo', newTr.lastChild) this.startFillInText(newTr.lastChild) } break } }, Refill: function Refill (e, selectedTd) { UI.log.info('Refill' + selectedTd.textContent) var isPredicate = selectedTd.nextSibling var predicateQuery if (isPredicate) { // predicateTd if (selectedTd.nextSibling.className === 'undetermined') { /* Make set of proprties to propose for a predicate. The naive approach is to take those which have a class of the subject as their domain. But in fact we must offer anything which is not explicitly excluded, by having a domain disjointWith a class of the subject. */ /* SELECT ?pred WHERE{ ?pred a rdf:Property. ?pred rdfs:domain subjectClass. } */ /* SELECT ?pred ?class WHERE{ ?pred a rdf:Property. subjectClass owl:subClassOf ?class. ?pred rdfs:domain ?class. } */ /* SELECT ?pred WHERE{ subject a ?subjectClass. ?pred rdfs:domain ?subjectClass. } */ var subject = UI.utils.getAbout(kb, UI.utils.ancestor(selectedTd, 'TABLE').parentNode) var subjectClass = kb.any(subject, rdf('type')) var sparqlText = [] var endl = '.\n' sparqlText[0] = 'SELECT ?pred WHERE{\n?pred ' + rdf('type') + rdf('Property') + '.\n' + '?pred ' + UI.ns.rdfs('domain') + subjectClass + '.}' // \n is required? SPARQL parser bug? sparqlText[1] = 'SELECT ?pred ?class\nWHERE{\n' + '?pred ' + rdf('type') + rdf('Property') + '.\n' + subjectClass + UI.ns.rdfs('subClassOf') + ' ?class.\n' + '?pred ' + UI.ns.rdfs('domain') + ' ?class.\n}' sparqlText[2] = 'SELECT ?pred WHERE{\n' + subject + rdf('type') + kb.variable('subjectClass') + endl + kb.variable('pred') + UI.ns.rdfs('domain') + kb.variable('subjectClass') + endl + '}' predicateQuery = sparqlText.map($rdf.SPARQLToQuery) } else { // ------selector /* SELECT ?pred WHERE{ ?pred a rdf:Property. ?pred rdfs:domain subjectClass. ?pred rdfs:range objectClass. } */ // Candidate /* SELECT ?pred WHERE{ subject a ?subjectClass. object a ?objectClass. ?pred rdfs:domain ?subjectClass. ?pred rdfs:range ?objectClass. */ subject = UI.utils.getAbout(kb, UI.utils.ancestor(selectedTd, 'TABLE').parentNode) subjectClass = kb.any(subject, rdf('type')) var object = selectedTd.parentNode.AJAR_statement.object // var objectClass = (object.termType === 'Literal') ? UI.ns.rdfs('Literal') : kb.any(object, rdf('type')) // var sparqlText="SELECT ?pred WHERE{\n?pred "+rdf('type')+rdf('Property')+".\n"+ // "?pred "+UI.ns.rdfs('domain')+subjectClass+".\n"+ // "?pred "+UI.ns.rdfs('range')+objectClass+".\n}"; // \n is required? SPARQL parser bug? sparqlText = 'SELECT ?pred WHERE{' + subject + rdf('type') + '?subjectClass' + '.\n' + object + rdf('type') + '?objectClass' + '.\n' + '?pred ' + UI.ns.rdfs('domain') + '?subjectClass' + '.\n' + '?pred ' + UI.ns.rdfs('range') + '?objectClass' + '.\n}' // \n is required? SPARQL parser bug? predicateQuery = $rdf.SPARQLToQuery(sparqlText) } // -------presenter // ToDo: how to sort selected predicates? this.showMenu(e, 'GeneralPredicateChoice', predicateQuery, {'isPredicate': isPredicate, 'selectedTd': selectedTd}) } else { // objectTd var predicateTerm = selectedTd.parentNode.AJAR_statement.predicate if (kb.whether(predicateTerm, rdf('type'), UI.ns.owl('DatatypeProperty')) || predicateTerm.termType === 'Collection' || kb.whether(predicateTerm, UI.ns.rdfs('range'), UI.ns.rdfs('Literal'))) { selectedTd.className = '' UI.utils.emptyNode(selectedTd) this.lastModified = this.createInputBoxIn(selectedTd, ' (Please Input) ') this.lastModified.isNew = false this.lastModified.select() } // show menu for rdf:type if (selectedTd.parentNode.AJAR_statement.predicate.sameTerm(rdf('type'))) { let sparqlText = 'SELECT ?class WHERE{?class ' + rdf('type') + UI.ns.rdfs('Class') + '.}' // I should just use kb.each var classQuery = $rdf.SPARQLToQuery(sparqlText) this.showMenu(e, 'TypeChoice', classQuery, {'isPredicate': isPredicate, 'selectedTd': selectedTd}) } } }, // This is where pubsPane.js comes in, with: outline.UserInput.getAutoCompleteHandler("JournalTAC")(e); getAutoCompleteHandler: function getAutoCompleteHandler (mode) { qp('\n\n***** In getAutoCompleteHandler ****** mode = ' + mode) if (mode === 'PredicateAutoComplete') { mode = 'predicate' } else if (mode !== 'JournalTAC') { // hq // why? -tim - not 'predicate' below mode = 'all' } var InputBox if (mode === 'JournalTAC') { // hq // Better to pass in InputBox as a param InputBox = myDocument.getElementById('inpid_journal_title') } else { InputBox = this.lastModified || outline.getSelection()[0].firstChild } qp('InputBox=' + InputBox)// hq qp('InputBox.value=' + InputBox.value)// hq return function (enterEvent) { qp('ENTER EVENT=' + enterEvent) // Firefox 2.0.0.6 makes this not working? 'this' becomes [object HTMLInputElement] // but not [wrapped ...] // var InputBox=(typeof enterEvent=='object')?this:this.lastModified;//'this' is the <input> element qp('1. outside (if eneterEvent)') var e = {} var tdNode = InputBox.parentNode if (!mode) mode = tdNode.nextSibling ? 'predicate' : 'all' e.pageX = UI.utils.findPos(tdNode)[0] e.pageY = UI.utils.findPos(tdNode)[1] + tdNode.clientHeight qp('epX=' + e.pageX + ', epY=' + e.pageY + ', mode=' + mode) var menu = myDocument.getElementById(outline.UserInput.menuID) function setHighlightItem (item) { if (!item) return // do not make changes if (menu.lastHighlight) menu.lastHighlight.className = '' menu.lastHighlight = item menu.lastHighlight.className = 'activeItem' outline.showURI(UI.utils.getAbout(kb, menu.lastHighlight)) } if (enterEvent) { // either the real event of the pseudo number passed by OutlineKeypressPanel qp('2. in (if enterEvent). with type = ' + typeof enterEvent) var newText = InputBox.value if (typeof enterEvent === 'object') { qp('3. in typeof enterEvent is object, will switch to keys, arrows, etc. keycode = ' + enterEvent.keyCode) enterEvent.stopPropagation() if (menu && !menu.lastHighlight) { // this ensures the following operation valid setHighlightItem(menu.firstChild.firstChild) } switch (enterEvent.keyCode) { case 13:// enter case 9:// tab qp('handler: Enter or Tab') if (!menu) { outline.UserInput.clearInputAndSave() return } if (!menu.lastHighlight) { if (mode === 'JournalTAC') { outline.UserInput.clearMenu() qp('no lastH') return 'no lastH' } return } // warning? if (menu.lastHighlight.tagName === 'INPUT') { switch (menu.lastHighlight.value) { case 'New...': qp('subcase New') outline.UserInput.createNew() break case 'GiveURI': qp('subcase GiveURI') outline.UserInput.inputURI() break } } else { // pubsPane Stuff: if (mode === 'JournalTAC') { qp('movedArrow? ' + movedArrow) // Enter only works if arrows have been moved if (movedArrow && menu.lastHighlight) { // Get the title from the DOM // tr, th, div, innerHTML var jtitle = menu.lastHighlight.firstChild.firstChild.innerHTML // tr, th, td, innerHTML var juri = menu.lastHighlight.firstChild.nextSibling.innerHTML // clearing out the &lt; and &gt; from juri juri = juri.slice(4, -4) return ['gotdptitle', jtitle, juri] } // If doesn't qualify to be autocomplete, return this random string, since pubsPane checks for "gotdptitle" return 'asGivenTxt' } var inputTerm = UI.utils.getAbout(kb, menu.lastHighlight) var fillInType = (mode === 'predicate') ? 'predicate' : 'object' outline.UserInput.clearMenu() outline.UserInput.fillInRequest(fillInType, InputBox.parentNode, inputTerm) // if (outline.UserInput.fillInRequest(fillInType,InputBox.parentNode,inputTerm)) // outline.UserInput.clearMenu(); } qp('outside') return case 38:// up qp('handler: Arrow UP') movedArrow = true // hq if (newText === '' && menu.lastHighlight.tagName === 'TR' && !menu.lastHighlight.previousSibling) { setHighlightItem(menu.firstChild.firstChild) } else { setHighlightItem(menu.lastHighlight.previousSibling) } return "I'm a little Arrow Up" case 40:// down qp('handler: Arrow Down') movedArrow = true // hq if (menu.lastHighlight.tagName === 'INPUT') { setHighlightItem(menu.childNodes[1].firstChild) } else { setHighlightItem(menu.lastHighlight.nextSibling) } return "I'm a little Down Arrow" case 37:// left case 39:// right qp('handler: Arrow left, right') if (menu.lastHighlight.tagName === 'INPUT') { if (enterEvent.keyCode === 37) { setHighlightItem(menu.lastHighlight.previousSibling) } else { setHighlightItem(menu.lastHighlight.nextSibling) } } return case 8:// backspace qp('handler: Backspace') newText = newText.slice(0, -1) break case 27:// esc to enter literal qp('handler: Esc') if (!menu) { outline.UserInput.backOut() return } outline.UserInput.clearMenu() // Not working? I don't know. // InputBox.removeEventListener('keypress',outline.UserInput.Autocomplete,false); return // break default: qp('handler: Default') movedArrow = false // hq // we need this because it is keypress, seeAlso performAutoCompleteEdit qp('oldtext=' + newText) newText += String.fromCharCode(enterEvent.charCode) qp('charcodent=' + enterEvent.charCode) qp('strcharcod=' + String.fromCharCode(enterEvent.charCode)) console.log('DEFAULT txtstr=' + newText + '\n') // hq } } // endif typeof(event) === object // UI.log.warn(InputBox.choices.length); // for(i=0;InputBox.choices[i].label<newText;i++); //O(n) ToDo: O(log n) if (mode === 'all') { qp('generalAC after switch, newText=' + newText + 'mode is all') outline.UserInput.clearMenu() // outline.UserInput.showMenu(e,'GeneralAutoComplete',undefined,{'isPredicate':false,'selectedTd':tdNode,'choices':InputBox.choices, 'index':i}); outline.UserInput.showMenu(e, 'GeneralAutoComplete', undefined, {'inputText': newText, 'selectedTd': tdNode}) if (newText.length === 0) outline.UserInput.WildCardButtons() } else if (mode === 'predicate') { qp('predicateAC after switch, newText=' + newText + 'mode is predicate') outline.UserInput.clearMenu() outline.UserInput.showMenu(e, 'PredicateAutoComplete', undefined, {'inputText': newText, 'isPredicate': true, 'selectedTd': tdNode}) } else if (mode === 'JournalTAC') { // hq qp('JouralTAC after switch, newText=' + newText) outline.UserInput.clearMenu() // Goto showMenu outline.UserInput.showMenu(e, 'JournalTitleAutoComplete', undefined, {'inputText': newText}, 'orderisuseless') } menu = myDocument.getElementById(outline.UserInput.menuID) if (!menu) { qp('No menu element. Do not show menu.') return } qp('at end of handler\n^^^^^^^^^^^^^^^^^\n\n') setHighlightItem(menu.firstChild.firstChild) outline.showURI(UI.utils.getAbout(kb, menu.lastHighlight)) return 'nothing to return' } }// end of return function }, // Add the buttons which allow the suer to craete a new object // Or reference an exiting one with a URI. // WildCardButtons: function WildCardButtons () { var menuDiv = myDocument.getElementById(outline.UserInput.menuID) var div = menuDiv.insertBefore(myDocument.createElement('div'), menuDiv.firstChild) var input1 = div.appendChild(myDocument.createElement('input')) var input2 = div.appendChild(myDocument.createElement('input')) input1.type = 'button'; input1.value = 'New...' input2.type = 'button'; input2.value = 'Know its URI' function highlightInput (e) { // same as the one in newMenu() var menu = myDocument.getElementById(outline.UserInput.menuID) if (menu.lastHighlight) menu.lastHighlight.className = '' menu.lastHighlight = UI.utils.ancestor(UI.utils.getTarget(e), 'INPUT') if (!menu.lastHighlight) return // mouseover <TABLE> menu.lastHighlight.className = 'activeItem' } div.addEventListener('mouseover', highlightInput, false) input1.addEventListener('click', this.createNew, false) input2.addEventListener('click', this.inputURI, false) }, // ToDo: shrink rows when \n+backspace Keypress: function (e) { if (e.keyCode === 13) { if (outline.targetOf(e).tagName !== 'TEXTAREA') { this.clearInputAndSave() } else { // <TEXTAREA> var preRows = parseInt(this.lastModified.getAttribute('rows')) this.lastModified.setAttribute('rows', (preRows + 1).toString()) e.stopPropagation() } } // Remark by Kenny: If the user wants to input more lines into an one-line-only blank. // Direct him/her to a new blank (how?) }, Mousedown: function (e) { qp('MOUSING DOWN') // temporary key ctrl+s or q for swiching mode // This was in HCIOptions "right click to switch mode": window.addEventListener('keypress', function (e) { if (e.ctrlKey && (e.charCode === 115 || e.charCode === 113)) UserInput.switchMode() }, false) window.addEventListener('mousedown', UserInput.Mousedown, false) document.getElementById('outline').oncontextmenu = function () { return false } if (e.button === 2) { // right click UserInput.switchMode() if (e) { e.preventDefault() e.stopPropagation() } } }, Mouseover: function Mouseover (e) { this.className = 'bottom-border-active' if (this._tabulatorMode === 1) { switch (UI.utils.getTarget(e).tagName) { case 'TD': var preTd = UI.utils.getTarget(e) if (preTd.className === 'pred') preTd.style.cursor = 'copy' break // Uh...I think I might have to give up this case 'DIV': var border = UI.utils.getTarget(e) if (UI.utils.getTarget(e).className === 'bottom-border') { border.style.borderColor = 'rgb(100%,65%,0%)' border.style.cursor = 'copy' } break default: } } }, Mouseout: function (e) { this.className = 'bottom-border' if (this._tabulatorMode === 1) { var border = UI.utils.getTarget(e) if (UI.utils.getTarget(e).className === 'bottom-border') { border.style.borderColor = 'transparent' border.style.cursor = 'auto' } } }, /** * Utilities */ whatSortOfEditCell: function whatSortOfEditCell (selectedTd) { if (selectedTd.nextSibling) return 'predicate' var predicateTerm = this.getStatementAbout(selectedTd).predicate // var predicateTerm=selectedTd.parentNode.AJAR_statement.predicate; if (kb.whether(predicateTerm, UI.ns.rdf('type'), UI.ns.owl('DatatypeProperty')) || kb.whether(predicateTerm, UI.ns.rdfs('range'), UI.ns.rdfs('Literal')) || predicateTerm.termType === 'Collection') { return 'DatatypeProperty-like' } else if (kb.whether(predicateTerm, rdf('type'), UI.ns.owl('ObjectProperty'))) { return 'ObjectProperty-like' } else { return 'no-idea' } }, getStatementAbout: function getStatementAbout (something) { // var trNode=something.parentNode; var trNode = UI.utils.ancestor(something, 'TR') if (!trNode) throw new Error('No ancestor TR for the TD we clicked on:' + something) try { var statement = trNode.AJAR_statement } catch (e) {