UNPKG

solid-panes

Version:

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

302 lines (276 loc) • 8.79 kB
// The query-by-example functionality in the tabulator // was the ability to expore a bit of the web in outline mode, // select a ceratain set of fields in the tree, // then pres "find all" which would then generte a SPARQL query // to find all other places which had the same pattern. // Fields could be optional by pressing th ewhite optoional button var UI = require('solid-ui') module.exports = { makeQueryRow, QuerySource, viewAndSaveQuery // Main function to generate and use the query } var optionalSubqueriesIndex = [] function predParentOf (node) { var n = node while (true) { if (n.getAttribute('predTR')) { return n } else if (n.previousSibling && n.previousSibling.nodeName === 'TR') { n = n.previousSibling } else { console.log('Could not find predParent') return node } } } function makeQueryRow (q, tr, constraint) { var kb = UI.store // predtr = predParentOf(tr) // var nodes = tr.childNodes // var n = tr.childNodes.length var inverse = tr.AJAR_inverse // var hasVar = 0 let parentVar, level, pat function makeRDFStatement (freeVar, parent) { if (inverse) { return new UI.rdf.Statement(freeVar, st.predicate, parent) } else { return new UI.rdf.Statement(parent, st.predicate, freeVar) } } var optionalSubqueryIndex = null for (level = tr.parentNode; level; level = level.parentNode) { if (typeof level.AJAR_statement !== 'undefined') { // level.AJAR_statement level.setAttribute('bla', level.AJAR_statement) // @@? -timbl // UI.log.debug("Parent TR statement="+level.AJAR_statement + ", var=" + level.AJAR_variable) /* for(let c=0;c<level.parentNode.childNodes.length;c++) //This makes sure the same variable is used for a subject if(level.parentNode.childNodes[c].AJAR_variable) level.AJAR_variable = level.parentNode.childNodes[c].AJAR_variable; */ if (!level.AJAR_variable) { makeQueryRow(q, level) } parentVar = level.AJAR_variable var predLevel = predParentOf(level) if (predLevel.getAttribute('optionalSubqueriesIndex')) { optionalSubqueryIndex = predLevel.getAttribute( 'optionalSubqueriesIndex' ) pat = optionalSubqueriesIndex[optionalSubqueryIndex] } break } } if (!pat) { pat = q.pat } var predtr = predParentOf(tr) // /////OPTIONAL KLUDGE/////////// var opt = predtr.getAttribute('optional') if (!opt) { if (optionalSubqueryIndex) { predtr.setAttribute('optionalSubqueriesIndex', optionalSubqueryIndex) } else { predtr.removeAttribute('optionalSubqueriesIndex') } } if (opt) { var optForm = kb.formula() optionalSubqueriesIndex.push(optForm) predtr.setAttribute( 'optionalSubqueriesIndex', optionalSubqueriesIndex.length - 1 ) pat.optional.push(optForm) pat = optForm } // ////////////////////////////// var st = tr.AJAR_statement var constraintVar = tr.AJAR_inverse ? st.subject : st.object // this is only used for constraints var hasParent = true if (constraintVar.isBlank && constraint) { window.alert( 'You cannot constrain a query with a blank node. No constraint will be added.' ) } if (!parentVar) { hasParent = false parentVar = inverse ? st.object : st.subject // if there is no parents, uses the sub/obj } // UI.log.debug('Initial variable: '+tr.AJAR_variable) const v = tr.AJAR_variable ? tr.AJAR_variable : kb.variable(UI.utils.newVariableName()) q.vars.push(v) v.label = hasParent ? parentVar.label : UI.utils.label(parentVar) v.label += ' ' + UI.utils.predicateLabelForXML(st.predicate, inverse) const pattern = makeRDFStatement(v, parentVar) // alert(pattern) v.label = v.label.slice(0, 1).toUpperCase() + v.label.slice(1) // init cap // See ../rdf/sparql.js // This should only work on literals but doesn't. function ConstraintEqualTo (value) { this.describe = function (varstr) { return varstr + ' = ' + value.toNT() } this.test = function (term) { return value.sameTerm(term) } return this } if (constraint) { // binds the constrained variable to its selected value pat.constraints[v] = new ConstraintEqualTo(constraintVar) } UI.log.info('Pattern: ' + pattern) pattern.tr = tr tr.AJAR_pattern = pattern // Cross-link UI and query line tr.AJAR_variable = v // UI.log.debug('Final variable: '+tr.AJAR_variable) UI.log.debug('Query pattern: ' + pattern) pat.statements.push(pattern) return v } // makeQueryRow function saveQuery (selection, qs) { // var qs = outline.qs // @@ var q = new UI.rdf.Query() var n = selection.length var i, sel, st, tr for (i = 0; i < n; i++) { sel = selection[i] tr = sel.parentNode st = tr.AJAR_statement UI.log.debug('Statement ' + st) if (sel.getAttribute('class').indexOf('pred') >= 0) { UI.log.info(' We have a predicate') makeQueryRow(q, tr) } if (sel.getAttribute('class').indexOf('obj') >= 0) { UI.log.info(' We have an object') makeQueryRow(q, tr, true) } } qs.addQuery(q) function resetOutliner (pat) { var n = pat.statements.length var pattern, tr for (let i = 0; i < n; i++) { pattern = pat.statements[i] tr = pattern.tr // UI.log.debug('tr: ' + tr.AJAR_statement); if (typeof tr !== 'undefined') { tr.AJAR_pattern = null // TODO: is this == to whats in current version? tr.AJAR_variable = null } } for (const x in pat.optional) { resetOutliner(pat.optional[x]) } } resetOutliner(q.pat) // NextVariable=0; return q } // saveQuery // When the user asks for all list of all matching parts of the data // function viewAndSaveQuery (outline, selection) { var qs = outline.qs UI.log.info('outline.doucment is now ' + outline.document.location) var q = saveQuery(selection, qs) /* if (tabulator.isExtension) { // tabulator.drawInBestView(q) } else */ for (let i = 0; i < qs.listeners.length; i++) { qs.listeners[i].getActiveView().view.drawQuery(q) qs.listeners[i].updateQueryControls(qs.listeners[i].getActiveView()) } } /** * The QuerySource object stores a set of listeners and a set of queries. * It keeps the listeners aware of those queries that the source currently * contains, and it is then up to the listeners to decide what to do with * those queries in terms of displays. * Not used 2010-08 -- TimBL * @class QuerySource * @author jambo */ function QuerySource () { /** * stores all of the queries currently held by this source, * indexed by ID number. */ this.queries = [] /** * stores the listeners for a query object. * @see TabbedContainer */ this.listeners = [] /** * add a Query object to the query source--It will be given an ID number * and a name, if it doesn't already have one. This subsequently adds the * query to all of the listeners the QuerySource knows about. */ this.addQuery = function (q) { var i if (q.name === null || q.name === '') { q.name = 'Query #' + (this.queries.length + 1) } q.id = this.queries.length this.queries.push(q) for (i = 0; i < this.listeners.length; i++) { if (this.listeners[i] !== null) { this.listeners[i].addQuery(q) } } } /** * Remove a Query object from the source. Tells all listeners to also * remove the query. */ this.removeQuery = function (q) { var i for (i = 0; i < this.listeners.length; i++) { if (this.listeners[i] !== null) { this.listeners[i].removeQuery(q) } } if (this.queries[q.id] !== null) { delete this.queries[q.id] } } /** * adds a "Listener" to this QuerySource - that is, an object * which is capable of both adding and removing queries. * Currently, only the TabbedContainer class is added. * also puts all current queries into the listener to be used. */ this.addListener = function (listener) { var i this.listeners.push(listener) for (i = 0; i < this.queries.length; i++) { if (this.queries[i] !== null) { listener.addQuery(this.queries[i]) } } } /** * removes listener from the array of listeners, if it exists! Also takes * all of the queries from this source out of the listener. */ this.removeListener = function (listener) { var i for (i = 0; i < this.queries.length; i++) { if (this.queries[i] !== null) { listener.removeQuery(this.queries[i]) } } for (i = 0; i < this.listeners.length; i++) { if (this.listeners[i] === listener) { delete this.listeners[i] } } } }