solid-panes
Version:
Solid-compatible Panes: applets and views for the mashlib and databrowser
1,359 lines (1,290 loc) • 85.9 kB
JavaScript
/* istanbul ignore file */
// 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'
*/
import * as UI from 'solid-ui'
import { store } from 'solid-logic'
import * as panes from 'pane-registry'
const $rdf = UI.rdf
let UserInputFormula // Formula to store references of user's work
let TempFormula // Formula to store incomplete triples (Requests),
// temporarily disjoint with kb to avoid bugs
export function UserInput (outline) {
const 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
const 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
const bibo = UI.rdf.Namespace('http://purl.org/ontology/bibo/') // hql for pubsPane
// var dcterms = UI.rdf.Namespace('http://purl.org/dc/terms/')
const dcelems = UI.rdf.Namespace('http://purl.org/dc/elements/1.1/')
let movedArrow = false // hq
// var updateService=new updateCenter(kb);
if (!UserInputFormula) {
UserInputFormula = new UI.rdf.Formula()
UserInputFormula.superFormula = store
// UserInputFormula.registerFormula("Your Work");
}
if (!TempFormula) TempFormula = new UI.rdf.IndexedFormula()
// Use RDFIndexedFormula so add returns the statement
TempFormula.name = 'TempFormula'
if (!store.updater) store.updater = new UI.rdf.UpdateManager(store)
return {
// updateService: updateService,
sparqler: 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
const This = outline.UserInput
const target = UI.utils.getTarget(e)
// UI.log.warn(ancestor(target,'TABLE').textContent);
const insertTr = myDocument.createElement('tr')
UI.utils
.ancestor(target, 'DIV')
.insertBefore(insertTr, UI.utils.ancestor(target, 'TR'))
const tempTr = myDocument.createElement('tr')
const reqTerm1 = This.generateRequest('(TBD)', tempTr, true)
insertTr.appendChild(tempTr.firstChild)
const 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
) {
const 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
const subject = UI.utils.getAbout(
store,
UI.utils.ancestor(target.parentNode.parentNode, 'TD')
)
const doc = store.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) {
const predicateTd = UI.utils.getTarget(e).parentNode.parentNode
// var predicateTerm = UI.utils.getAbout(kb, predicateTd)
const 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
const insertTr = this.appendToPredicate(predicateTd)
const reqTerm = this.generateRequest(' (Error) ', insertTr, false)
const 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) {
const 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) {
const term = outline.clipboard[fromCode].shift()
if (term === null) {
UI.log.warn('no more element in clipboard!')
return
}
switch (fromCode) {
case 'predicates':
case 'objects': {
const allArray = outline.clipboard.all
for (let 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
}
let 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
const 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 input box
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
}
const target = selectedTd
const about = this.getStatementAbout(target) // timbl - to avoid alert from random clicks
if (!about) return
let obj
let trNode
try {
obj = UI.utils.getTerm(target)
trNode = UI.utils.ancestor(target, 'TR')
} catch (e) {
UI.log.warn('userinput.js: ' + e + UI.utils.getAbout(store, selectedTd))
UI.log.error(target + ' getStatement Error:' + e)
}
let tdNode
try {
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>
const 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 occurred
// 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 () {
const 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) {
let obj
if (!this.lastModified) return
if (!this.lastModified.isNew) {
try {
obj = this.getStatementAbout(this.lastModified).object
} catch (e) {
return
}
}
let s = this.lastModifiedStat // when 'isNew' this is set at addNewObject()
let defaultpropview
let trNode
let reqTerm
let preStat
if (this.lastModified.value !== this.lastModified.defaultValue) {
let trCache
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,
store.literal(this.lastModified.value),
s.why
)
// TODO: DEFINE ERROR CALLBACK
defaultpropview = this.views.defaults[s.predicate.uri]
trCache = UI.utils.ancestor(this.lastModified, 'TR')
try {
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 = store.add(
s.subject,
s.predicate,
store.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
}
let s1, s2, s3
switch (obj.termType) {
case 'Literal': {
// generate path and nailing from current values
// TODO: DEFINE ERROR CALLBACK
const valueCache = this.lastModified.value
trCache = UI.utils.ancestor(this.lastModified, 'TR')
const oldValue = this.lastModified.defaultValue
s2 = $rdf.st(
s.subject,
s.predicate,
store.literal(this.lastModified.value),
s.why
)
try {
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
const textTerm = store.literal(this.lastModified.value, '')
// <Feature about="labelChoice">
if (s.predicate.termType === 'Collection') {
// case: add triple ????????? Weird - tbl
const selectedPredicate = s.predicate.elements[0] // @@ TBL elements is a list on the predicate??
if (store.any(undefined, selectedPredicate, textTerm)) {
if (!e) {
// keyboard
const 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: store.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)
const type = store.the(s.subject, rdf('type'))
s3 = store.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 {
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
}
store.remove(s)
store.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
}
const enclosingTd = UI.utils.ancestor(
this.lastModified.parentNode.parentNode,
'TD'
)
const defaultPane = panes.byName('default') // @@ check
outline.outlineExpand(enclosingTd, s.subject, {
pane: defaultPane,
already: true
})
outline.walk('right', outline.focusTd)
// </Feature>
} else {
this.fillInRequest(
'object',
this.lastModified.parentNode,
store.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) '
trNode = UI.utils.ancestor(this.lastModified, 'TR')
reqTerm = this.generateRequest(
'(To be determined. Re-type of drag an object onto this field)'
)
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') {
store.removeMany(s.subject)
const 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 (this.statIsInverse) {
/*
if ((s.object.termType === 'BlankNode' && !this.statIsInverse) ||
s.subject.termType === 'BlankNode' && this.statIsInverse) {
this.backOut()
return
*/
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(
store.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
}
let removedTr
// var afterTr
const s = this.getStatementAbout(selectedTd)
if (
!isBackOut &&
!store.whether(s.object, rdf('type'), UI.ns.link('Request')) &&
// Better to check whether provenance is internal?
!store.whether(s.predicate, rdf('type'), UI.ns.link('Request')) &&
!store.whether(s.subject, rdf('type'), UI.ns.link('Request'))
) {
UI.log.debug('about to send SPARQLUpdate')
try {
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 () {
let trIterator
for (
trIterator = removedTr;
trIterator.childNodes.length === 1;
trIterator = trIterator.previousSibling
);
let predicateTd
if (trIterator === removedTr) {
const theNext = trIterator.nextSibling
if (theNext.nextSibling && theNext.childNodes.length === 1) {
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);
*/
const 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) {
let defaultpropview
let preStat
switch (selectedTd.className) {
case 'undetermined selected':
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
const insertTr = this.appendToPredicate(selectedTd)
preStat = selectedTd.parentNode.AJAR_statement
defaultpropview = this.views.defaults[preStat.predicate.uri]
insertTr.appendChild(outline.outlineObjectTD(term, defaultpropview))
// modify store and update here
const isInverse = selectedTd.parentNode.AJAR_inverse
if (!isInverse) {
insertTr.AJAR_statement = store.add(
preStat.subject,
preStat.predicate,
term,
preStat.why
)
} else {
insertTr.AJAR_statemnet = store.add(
term,
preStat.predicate,
preStat.object,
preStat.why
)
}
try {
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
const paneDiv = UI.utils.ancestor(selectedTd, 'TABLE').lastChild
const 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
const 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)
const isPredicate = selectedTd.nextSibling
let predicateQuery
if (isPredicate) {
// predicateTd
let subject
let subjectClass
let sparqlText
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.
}
*/
subject = UI.utils.getAbout(
store,
UI.utils.ancestor(selectedTd, 'TABLE').parentNode
)
subjectClass = store.any(subject, rdf('type'))
sparqlText = []
const 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') +
store.variable('subjectClass') +
endl +
store.variable('pred') +
UI.ns.rdfs('domain') +
store.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(
store,
UI.utils.ancestor(selectedTd, 'TABLE').parentNode
)
subjectClass = store.any(subject, rdf('type'))
const 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
const predicateTerm = selectedTd.parentNode.AJAR_statement.predicate
if (
store.whether(
predicateTerm,
rdf('type'),
UI.ns.owl('DatatypeProperty')
) ||
predicateTerm.termType === 'Collection' ||
store.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'))
) {
const sparqlText =
'SELECT ?class WHERE{?class ' +
rdf('type') +
UI.ns.rdfs('Class') +
'.}'
// I should just use kb.each
const 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'
}
let 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)')
const e = {}
const 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)
let 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(store, menu.lastHighlight))
}
if (enterEvent) {
// either the real event of the pseudo number passed by OutlineKeypressPanel
qp('2. in (if enterEvent). with type = ' + typeof enterEvent)
let 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
const jtitle =
menu.lastHighlight.firstChild.firstChild.innerHTML
// tr, th, td, innerHTML
let juri =
menu.lastHighlight.firstChild.nextSibling.innerHTML
// clearing out the < and > 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'
}
const inputTerm = UI.utils.getAbout(store, menu.lastHighlight)
const 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)
outl