UNPKG

solid-panes

Version:

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

259 lines (250 loc) • 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dataContentPane = void 0; var UI = _interopRequireWildcard(require("solid-ui")); var $rdf = _interopRequireWildcard(require("rdflib")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (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 (const 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); } /* 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 ns = UI.ns; const dataContentPane = exports.dataContentPane = { 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; } const n = context.session.store.statementsMatching(undefined, undefined, undefined, subject).length; if (n === 0) return null; return 'Data (' + n + ')'; }, /* shouldGetFocus: function(subject) { return store.whether(subject, UI.ns.rdf('type'), UI.ns.link('RDFDocument')) }, */ statementsAsTables: function statementsAsTables(sts, context, initialRoots) { const myDocument = context.dom; // const outliner = context.getOutliner(myDocument) const rep = myDocument.createElement('table'); const sz = $rdf.Serializer(context.session.store); const res = sz.rootSubjects(sts); let roots = res.roots; const subjects = res.subjects; const loopBreakers = res.loopBreakers; for (const x in loopBreakers) { console.log('\tdataContentPane: loopbreaker:' + x); } const doneBnodes = {}; // For preventing looping const 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) const rep = myDocument.createElement('table'); let lastPred = null; const 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(); let same = 0; let predicateTD; // The cell which holds the predicate for (let i = 0; i < sts.length; i++) { const st = sts[i]; const 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'); const 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++; const 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) { let 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 const 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 (let i = 0; i < obj.elements.length; i++) { const 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 (let i = 0; i < initialRoots.length; i++) { // Max 2 if (x.sameTerm(initialRoots[i])) return false; } return true; })); } for (let i = 0; i < roots.length; i++) { const tr = myDocument.createElement('tr'); tr.setAttribute('style', `background-color: ${i % 2 === 0 ? '#f0f0f0' : 'white'};`); rep.appendChild(tr); const subjectTD = myDocument.createElement('td'); tr.appendChild(subjectTD); const TDTree = myDocument.createElement('td'); tr.appendChild(TDTree); const 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 (const bNT in referencedBnodes) { // Add number to refer to const table = doneBnodes[bNT]; // let tr = myDocument.createElement('tr') const 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) { const myDocument = context.dom; function alternativeRendering() { const sz = $rdf.Serializer(context.session.store); const res = sz.rootSubjects(sts); const roots = res.roots; const p = {}; p.render = function (s2) { const div = myDocument.createElement('div'); div.setAttribute('class', 'withinDocumentPane'); const plist = kb.statementsMatching(s2, undefined, undefined, subject); outliner.appendPropertyTRs(div, plist, false, function (_pred, _inverse) { return true; }); return div; }; for (let i = 0; i < roots.length; i++) { const tr = myDocument.createElement('TR'); const root = roots[i]; tr.style.verticalAlign = 'top'; const td = outliner.outlineObjectTD(root, undefined, tr); tr.appendChild(td); div.appendChild(tr); outliner.outlineExpand(td, root, { pane: p }); } } function mainRendering() { const 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 const 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)); } const outliner = context.getOutliner(myDocument); const kb = context.session.store; const 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. const sts = kb.statementsMatching(undefined, undefined, undefined, subject); // @@ slow with current store! // eslint-disable-next-line no-constant-condition if (false) { // keep code alternativeRendering(); } else { mainRendering(); } return div; } };