solid-panes
Version:
Solid-compatible Panes: applets and views for the mashlib and databrowser
1,059 lines (1,031 loc) • 82.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UserInput = UserInput;
var UI = _interopRequireWildcard(require("solid-ui"));
var _solidLogic = require("solid-logic");
var panes = _interopRequireWildcard(require("pane-registry"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } /* 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'
*/
var $rdf = UI.rdf;
var UserInputFormula; // Formula to store references of user's work
var TempFormula; // Formula to store incomplete triples (Requests),
// temporarily disjoint with kb to avoid bugs
function UserInput(outline) {
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
var 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 = _solidLogic.store;
// UserInputFormula.registerFormula("Your Work");
}
if (!TempFormula) TempFormula = new UI.rdf.IndexedFormula();
// Use RDFIndexedFormula so add returns the statement
TempFormula.name = 'TempFormula';
if (!_solidLogic.store.updater) _solidLogic.store.updater = new UI.rdf.UpdateManager(_solidLogic.store);
return {
// updateService: updateService,
sparqler: _solidLogic.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) {
var 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(_solidLogic.store, UI.utils.ancestor(target.parentNode.parentNode, 'TD'));
var doc = _solidLogic.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) {
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);
var 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 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;
}
var target = selectedTd;
var about = this.getStatementAbout(target); // timbl - to avoid alert from random clicks
if (!about) return;
var obj;
var trNode;
try {
obj = UI.utils.getTerm(target);
trNode = UI.utils.ancestor(target, 'TR');
} catch (e) {
UI.log.warn('userinput.js: ' + e + UI.utils.getAbout(_solidLogic.store, selectedTd));
UI.log.error(target + ' getStatement Error:' + e);
}
var 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>
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 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() {
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) {
var obj;
if (!this.lastModified) return;
if (!this.lastModified.isNew) {
try {
obj = this.getStatementAbout(this.lastModified).object;
} catch (e) {
return;
}
}
var s = this.lastModifiedStat; // when 'isNew' this is set at addNewObject()
var defaultpropview;
var trNode;
var reqTerm;
var preStat;
if (this.lastModified.value !== this.lastModified.defaultValue) {
var 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, _solidLogic.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 {
_solidLogic.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 = _solidLogic.store.add(s.subject, s.predicate, _solidLogic.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;
}
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, _solidLogic.store.literal(this.lastModified.value), s.why);
try {
_solidLogic.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 = _solidLogic.store.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 (_solidLogic.store.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: _solidLogic.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);
var type = _solidLogic.store.the(s.subject, rdf('type'));
s3 = _solidLogic.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 {
_solidLogic.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;
}
_solidLogic.store.remove(s);
_solidLogic.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
}
var enclosingTd = UI.utils.ancestor(this.lastModified.parentNode.parentNode, 'TD');
var 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, _solidLogic.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') {
_solidLogic.store.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 (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(_solidLogic.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;
}
var removedTr;
// var afterTr
var s = this.getStatementAbout(selectedTd);
if (!isBackOut && !_solidLogic.store.whether(s.object, rdf('type'), UI.ns.link('Request')) &&
// Better to check whether provenance is internal?
!_solidLogic.store.whether(s.predicate, rdf('type'), UI.ns.link('Request')) && !_solidLogic.store.whether(s.subject, rdf('type'), UI.ns.link('Request'))) {
UI.log.debug('about to send SPARQLUpdate');
try {
_solidLogic.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);
var predicateTd;
if (trIterator === removedTr) {
var 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);
*/
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) {
var defaultpropview;
var 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
var 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
var isInverse = selectedTd.parentNode.AJAR_inverse;
if (!isInverse) {
insertTr.AJAR_statement = _solidLogic.store.add(preStat.subject, preStat.predicate, term, preStat.why);
} else {
insertTr.AJAR_statemnet = _solidLogic.store.add(term, preStat.predicate, preStat.object, preStat.why);
}
try {
_solidLogic.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
var subject;
var subjectClass;
var 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(_solidLogic.store, UI.utils.ancestor(selectedTd, 'TABLE').parentNode);
subjectClass = _solidLogic.store.any(subject, rdf('type'));
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') + _solidLogic.store.variable('subjectClass') + endl + _solidLogic.store.variable('pred') + UI.ns.rdfs('domain') + _solidLogic.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(_solidLogic.store, UI.utils.ancestor(selectedTd, 'TABLE').parentNode);
subjectClass = _solidLogic.store.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 (_solidLogic.store.whether(predicateTerm, rdf('type'), UI.ns.owl('DatatypeProperty')) || predicateTerm.termType === 'Collection' || _solidLogic.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'))) {
var _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(_solidLogic.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));
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 < 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';
}
var inputTerm = UI.utils.getAbout(_solidLogic.store, 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(_solidLogic.store, 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 Keypress(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