UNPKG

solid-panes

Version:

Solid-compatible Panes: applets and views for the mashlib and databrowser

1,059 lines (1,031 loc) 82.6 kB
"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 &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(_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