UNPKG

solid-panes

Version:

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

291 lines (273 loc) • 10 kB
/* Data content Pane ** ** This pane shows the content of a particular RDF resource ** or at least the RDF semantics we attribute to that resource. */ // To do: - Only take data from one graph // - Only do forwards not backward? // - Expand automatically all the way down // - original source view? Use ffox view source const UI = require('solid-ui') const $rdf = require('rdflib') const ns = UI.ns module.exports = { icon: UI.icons.originalIconBase + 'rdf_flyer.24.gif', name: 'dataContents', audience: [ns.solid('Developer')], label: function (subject, context) { if ( 'http://www.w3.org/2007/ont/link#ProtocolEvent' in context.session.store.findTypeURIs(subject) ) { return null } var n = context.session.store.statementsMatching( undefined, undefined, undefined, subject ).length if (n === 0) return null return 'Data (' + n + ')' }, /* shouldGetFocus: function(subject) { return UI.store.whether(subject, UI.ns.rdf('type'), UI.ns.link('RDFDocument')) }, */ statementsAsTables: function statementsAsTables (sts, context, initialRoots) { var myDocument = context.dom // var outliner = context.getOutliner(myDocument) var rep = myDocument.createElement('table') var sz = UI.rdf.Serializer(context.session.store) var res = sz.rootSubjects(sts) var roots = res.roots var subjects = res.subjects var loopBreakers = res.loopBreakers for (var x in loopBreakers) { console.log('\tdataContentPane: loopbreaker:' + x) } var doneBnodes = {} // For preventing looping var referencedBnodes = {} // Bnodes which need to be named alas // The property tree for a single subject or anonymous node function propertyTree (subject) { // print('Proprty tree for '+subject) var rep = myDocument.createElement('table') var lastPred = null var sts = subjects[sz.toStr(subject)] // relevant statements if (!sts) { // No statements in tree rep.appendChild(myDocument.createTextNode('...')) // just empty bnode as object return rep } sts.sort() var same = 0 var predicateTD // The cell which holds the predicate for (var i = 0; i < sts.length; i++) { var st = sts[i] var tr = myDocument.createElement('tr') if (st.predicate.uri !== lastPred) { if (lastPred && same > 1) { predicateTD.setAttribute('rowspan', '' + same) } predicateTD = myDocument.createElement('td') predicateTD.setAttribute('class', 'pred') var anchor = myDocument.createElement('a') anchor.setAttribute('href', st.predicate.uri) anchor.addEventListener( 'click', UI.widgets.openHrefInOutlineMode, true ) anchor.appendChild( myDocument.createTextNode( UI.utils.predicateLabelForXML(st.predicate) ) ) predicateTD.appendChild(anchor) tr.appendChild(predicateTD) lastPred = st.predicate.uri same = 0 } same++ var objectTD = myDocument.createElement('td') objectTD.appendChild(objectTree(st.object)) tr.appendChild(objectTD) rep.appendChild(tr) } if (lastPred && same > 1) predicateTD.setAttribute('rowspan', '' + same) return rep } // Convert a set of statements into a nested tree of tables function objectTree (obj) { var res, anchor switch (obj.termType) { case 'NamedNode': anchor = myDocument.createElement('a') anchor.setAttribute('href', obj.uri) anchor.addEventListener( 'click', UI.widgets.openHrefInOutlineMode, true ) anchor.appendChild(myDocument.createTextNode(UI.utils.label(obj))) return anchor case 'Literal': if (!obj.datatype || !obj.datatype.uri) { res = myDocument.createElement('div') res.setAttribute('style', 'white-space: pre-wrap;') res.textContent = obj.value return res } else if ( obj.datatype.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' ) { res = myDocument.createElement('div') res.setAttribute('class', 'embeddedXHTML') res.innerHTML = obj.value // Try that @@@ beware embedded dangerous code return res } return myDocument.createTextNode(obj.value) // placeholder - could be smarter, case 'BlankNode': if (obj.toNT() in doneBnodes) { // Break infinite recursion referencedBnodes[obj.toNT()] = true const anchor = myDocument.createElement('a') anchor.setAttribute('href', '#' + obj.toNT().slice(2)) anchor.setAttribute('class', 'bnodeRef') anchor.textContent = '*' + obj.toNT().slice(3) return anchor } doneBnodes[obj.toNT()] = true // Flag to prevent infinite recursion in propertyTree var newTable = propertyTree(obj) doneBnodes[obj.toNT()] = newTable // Track where we mentioned it first if ( UI.utils.ancestor(newTable, 'TABLE') && UI.utils.ancestor(newTable, 'TABLE').style.backgroundColor === 'white' ) { newTable.style.backgroundColor = '#eee' } else { newTable.style.backgroundColor = 'white' } return newTable case 'Collection': res = myDocument.createElement('table') res.setAttribute('class', 'collectionAsTables') for (var i = 0; i < obj.elements.length; i++) { var tr = myDocument.createElement('tr') res.appendChild(tr) tr.appendChild(objectTree(obj.elements[i])) } return res case 'Graph': res = context.session.paneRegistry .byName('dataContents') .statementsAsTables(obj.statements, context) res.setAttribute('class', 'nestedFormula') return res case 'Variable': res = myDocument.createTextNode('?' + obj.uri) return res } throw new Error('Unhandled node type: ' + obj.termType) } // roots.sort() if (initialRoots) { roots = initialRoots.concat( roots.filter(function (x) { for (var i = 0; i < initialRoots.length; i++) { // Max 2 if (x.sameTerm(initialRoots[i])) return false } return true }) ) } for (var i = 0; i < roots.length; i++) { var tr = myDocument.createElement('tr') rep.appendChild(tr) var subjectTD = myDocument.createElement('td') tr.appendChild(subjectTD) var TDTree = myDocument.createElement('td') tr.appendChild(TDTree) var root = roots[i] if (root.termType === 'BlankNode') { subjectTD.appendChild(myDocument.createTextNode(UI.utils.label(root))) // Don't recurse! } else { subjectTD.appendChild(objectTree(root)) // won't have tree } TDTree.appendChild(propertyTree(root)) } for (var bNT in referencedBnodes) { // Add number to refer to const table = doneBnodes[bNT] // let tr = myDocument.createElement('tr') var anchor = myDocument.createElement('a') anchor.setAttribute('id', bNT.slice(2)) anchor.setAttribute('class', 'bnodeDef') anchor.textContent = bNT.slice(3) + ')' table.insertBefore(anchor, table.firstChild) } return rep }, // statementsAsTables // View the data in a file in user-friendly way render: function (subject, context) { var myDocument = context.dom function alternativeRendering () { var sz = UI.rdf.Serializer(context.session.store) var res = sz.rootSubjects(sts) var roots = res.roots var p = {} p.render = function (s2) { var div = myDocument.createElement('div') div.setAttribute('class', 'withinDocumentPane') var plist = kb.statementsMatching(s2, undefined, undefined, subject) outliner.appendPropertyTRs(div, plist, false, function ( _pred, _inverse ) { return true }) return div } for (var i = 0; i < roots.length; i++) { var tr = myDocument.createElement('TR') var root = roots[i] tr.style.verticalAlign = 'top' var td = outliner.outlineObjectTD(root, undefined, tr) tr.appendChild(td) div.appendChild(tr) outliner.outlineExpand(td, root, { pane: p }) } } function mainRendering () { var initialRoots = [] // Ordering: start with stuff about this doc if (kb.holds(subject, undefined, undefined, subject)) { initialRoots.push(subject) } // Then about the primary topic of the document if any var ps = kb.any(subject, UI.ns.foaf('primaryTopic'), undefined, subject) if (ps) initialRoots.push(ps) div.appendChild( context.session.paneRegistry .byName('dataContents') .statementsAsTables(sts, context, initialRoots) ) } var outliner = context.getOutliner(myDocument) var kb = context.session.store var div = myDocument.createElement('div') div.setAttribute('class', 'dataContentPane') // Because of smushing etc, this will not be a copy of the original source // We could instead either fetch and re-parse the source, // or we could keep all the pre-smushed triples. var sts = kb.statementsMatching(undefined, undefined, undefined, subject) // @@ slow with current store! if ($rdf.keepThisCodeForLaterButDisableFerossConstantConditionPolice) { alternativeRendering() } else { mainRendering() } return div } }