solid-panes
Version:
Solid-compatible Panes: applets and views for the mashlib and databrowser
323 lines (306 loc) • 13 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var UI = _interopRequireWildcard(require("solid-ui"));
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); }
/* Financial Period Pane
**
** This outline pane allows a user to interact with a period
** downloaded from a bank statement, annotting it with classes and comments,
** trips, etc
*/
const ns = UI.ns;
var _default = exports.default = {
icon: UI.icons.iconBase + 'noun_142708.svg',
name: 'period',
audience: [ns.solid('PowerUser')],
// Does the subject deserve this pane?
label: function (subject, context) {
const kb = context.session.store;
const t = kb.findTypeURIs(subject);
if (t['http://www.w3.org/2000/10/swap/pim/qif#Period']) return 'period';
return null; // No under other circumstances (while testing at least!)
},
render: function (subject, context) {
const dom = context.dom;
const kb = context.session.store;
const ns = UI.ns;
const div = dom.createElement('div');
div.setAttribute('class', 'periodPane');
const mention = function mention(message, style) {
if (!style) style = 'color: grey;';
const pre = dom.createElement('pre');
pre.setAttribute('style', style);
div.appendChild(pre);
pre.appendChild(dom.createTextNode(message));
};
const happy = function happy(message) {
return mention('✓ ' + message, 'color: #010; background-color: #efe');
};
const complain = function complain(message) {
return mention(message, 'color: #100; background-color: #fee');
};
/*
var rerender = function (div) {
var parent = div.parentNode
var div2 = thisPane.render(subject, dom)
parent.replaceChild(div2, div)
}
*/
const renderPeriod = function () {
const dtstart = kb.any(subject, ns.cal('dtstart'));
if (dtstart === undefined) {
complain('(Error: There is no start date known for this period <' + subject.uri + '>,\n -- every period needs one.)');
}
const dtend = kb.any(subject, ns.cal('dtend'));
if (dtend === undefined) {
complain('(Error: There is no end date known for this period <' + subject.uri + '>,\n -- every period needs one.)');
}
// var store = kb.any(subject, UI.ns.qu('annotationStore')) || null
const predicateURIsDone = {};
const donePredicate = function (pred) {
predicateURIsDone[pred.uri] = true;
};
donePredicate(ns.rdf('type'));
const inPeriod = function (date) {
return !!(date && date >= dtstart && date < dtend);
};
const d2 = function (n) {
const s = '' + n;
if (s.indexOf('.') >= 0) {
return s.split('.')[0] + '.' + (s.split('.')[1] + '00').slice(0, 2);
}
return s + '.00';
};
const transactionInPeriod = function (x) {
return inPeriod(kb.any(x, ns.qu('date')));
};
const oderByDate = function (x, y) {
const dx = kb.any(x, ns.qu('date'));
const dy = kb.any(y, ns.qu('date'));
if (dx !== undefined && dy !== undefined) {
if (dx.value < dy.value) return -1;
if (dx.value > dy.value) return 1;
}
if (x.uri < y.uri) return -1; // Arbitrary but repeatable
if (x.uri > y.uri) return 1;
return 0;
};
/*
var setPaneStyle = function (account) {
var mystyle = 'padding: 0.5em 1.5em 1em 1.5em; '
if (account) {
var backgroundColor = kb.any(account, UI.ns.ui('backgroundColor'))
if (backgroundColor) {
mystyle += 'background-color: ' + backgroundColor.value + '; '
}
}
div.setAttribute('style', mystyle)
}
// setPaneStyle();
*/
const h2 = div.appendChild(dom.createElement('h2'));
h2.textContent = 'Period ' + dtstart.value.slice(0, 10) + ' - ' + dtend.value.slice(0, 10);
const insertedPane = function (context, subject, paneName) {
const p = context.session.paneRegistry.byName(paneName);
const d = p.render(subject, context);
d.setAttribute('style', 'border: 0.1em solid green;');
return d;
};
const expandAfterRow = function (dom, row, subject, paneName, solo) {
const siblings = row.parentNode.children;
if (solo) {
for (let j = siblings.length - 1; j >= 0; j--) {
if (siblings[j].expanded) {
siblings[j].parentNode.removeChild(siblings[j].expanded);
siblings[j].expanded = false;
}
}
}
const tr = dom.createElement('tr');
const td = tr.appendChild(dom.createElement('td'));
td.setAttribute('style', 'width: 98%; padding: 1em; border: 0.1em solid grey;');
const cols = row.children.length;
if (row.nextSibling) {
row.parentNode.insertBefore(tr, row.nextSibling);
} else {
row.parentNode.appendChild(tr);
}
row.expanded = tr;
td.setAttribute('colspan', '' + cols);
td.appendChild(insertedPane(context, subject, paneName));
};
const expandAfterRowOrCollapse = function (dom, row, subject, paneName, solo) {
if (row.expanded) {
row.parentNode.removeChild(row.expanded);
row.expanded = false;
} else {
expandAfterRow(dom, row, subject, paneName, solo);
}
};
const transactionTable = function (dom, list) {
const table = dom.createElement('table');
table.setAttribute('style', 'margin-left: 100; font-size: 9pt; width: 85%;');
const transactionRow = function (dom, x) {
const tr = dom.createElement('tr');
const setTRStyle = function (tr, account) {
// var mystyle = "padding: 0.5em 1.5em 1em 1.5em; ";
let mystyle = 'margin-left: 8em; padding-left: 5em;';
if (account) {
const backgroundColor = kb.any(account, UI.ns.ui('backgroundColor'));
if (backgroundColor) {
mystyle += 'background-color: ' + backgroundColor.value + '; ';
}
}
tr.setAttribute('style', mystyle);
};
const account = kb.any(x, ns.qu('toAccount'));
setTRStyle(tr, account);
const c0 = tr.appendChild(dom.createElement('td'));
const date = kb.any(x, ns.qu('date'));
c0.textContent = date ? date.value.slice(0, 10) : '???';
c0.setAttribute('style', 'width: 7em;');
const c1 = tr.appendChild(dom.createElement('td'));
c1.setAttribute('style', 'width: 36em;');
const payee = kb.any(x, ns.qu('payee'));
c1.textContent = payee ? payee.value : '???';
const a1 = c1.appendChild(dom.createElement('a'));
a1.textContent = ' ➜';
a1.setAttribute('href', x.uri);
const c3 = tr.appendChild(dom.createElement('td'));
const amount = kb.any(x, ns.qu('in_USD'));
c3.textContent = amount ? d2(amount.value) : '???';
c3.setAttribute('style', 'width: 6em; text-align: right; '); // @@ decimal alignment?
tr.addEventListener('click', function (e) {
// solo unless shift key
expandAfterRowOrCollapse(dom, tr, x, 'transaction', !e.shiftKey);
}, false);
return tr;
};
const list2 = list.filter(transactionInPeriod);
list2.sort(oderByDate);
for (let i = 0; i < list2.length; i++) {
table.appendChild(transactionRow(dom, list2[i]));
}
return table;
};
// List unclassified transactions
const dummies = {
'http://www.w3.org/2000/10/swap/pim/qif#Transaction': true,
// (we knew)
'http://www.w3.org/2000/10/swap/pim/qif#Unclassified': true,
// pseudo classifications we may phase out
'http://www.w3.org/2000/10/swap/pim/qif#UnclassifiedOutgoing': true,
'http://www.w3.org/2000/10/swap/pim/qif#UnclassifiedIncome': true
};
const xURIs = kb.findMemberURIs(ns.qu('Transaction'));
const unclassifiedIn = [];
const unclassifiedOut = [];
let usd, z;
for (const y in xURIs) {
// For each thing which can be inferred to be a transaction
// @@ TODO: Write away the need for exception on next line
if (Object.prototype.hasOwnProperty.call(xURIs, y)) {
z = kb.sym(y);
const tt = kb.each(z, ns.rdf('type')); // What EXPLICIT definitions
let classified = false;
for (let j = 0; j < tt.length; j++) {
const t = tt[j];
if (dummies[t.uri] === undefined) {
classified = true;
}
}
if (!classified) {
usd = kb.any(z, ns.qu('in_USD'));
if (usd === undefined) {
usd = kb.any(z, ns.qu('amount'));
}
if (usd && ('' + usd.value).indexOf('-') >= 0) {
unclassifiedOut.push(kb.sym(y));
} else {
unclassifiedIn.push(kb.sym(y));
}
}
}
}
let tab, count;
if (unclassifiedIn.length) {
tab = transactionTable(dom, unclassifiedIn);
count = tab.children.length;
div.appendChild(dom.createElement('h3')).textContent = 'Unclassified Income' + (count < 4 ? '' : ' (' + count + ')');
div.appendChild(tab);
} else {
happy('No unclassified income');
}
if (unclassifiedOut.length) {
tab = transactionTable(dom, unclassifiedOut);
count = tab.children.length;
div.appendChild(dom.createElement('h3')).textContent = 'Unclassified Outgoings' + (count < 4 ? '' : ' (' + count + ')');
div.appendChild(tab);
} else {
happy('No unclassified outgoings ');
}
// /////////////// Check some categories of transaction for having given fields
const catSymbol = function (catTail) {
const cats = kb.findSubClassesNT(ns.qu('Transaction'));
for (const cat in cats) {
// @@ TODO: Write away the need for exception on next line
if (Object.prototype.hasOwnProperty.call(cats, cat)) {
if (cat.slice(1, -1).split('#')[1] === catTail) {
return kb.sym(cat.slice(1, -1));
}
}
}
return null;
};
const checkCatHasField = function (catTail, pred) {
const cat = catSymbol(catTail);
let tab;
const guilty = [];
let count = 0;
if (!cat) {
complain('Error: No category correspnding to ' + catTail);
return null;
}
const list = kb.each(undefined, ns.rdf('type'), cat);
for (let i = 0; i < list.length; i++) {
if (!kb.any(list[i], pred)) {
guilty.push(list[i]);
}
}
if (guilty.length) {
tab = transactionTable(dom, guilty);
count = tab.children.length;
div.appendChild(dom.createElement('h3')).textContent = UI.utils.label(cat) + ' with no ' + UI.utils.label(pred) + (count < 4 ? '' : ' (' + count + ')');
div.appendChild(tab);
}
return count;
};
// Load dynamically as properties of period
if (checkCatHasField('Reimbursables', ns.trip('trip')) === 0) {
happy('Reimbursables all have trips');
}
if (checkCatHasField('Other_Inc_Speaking', ns.trip('trip')) === 0) {
happy('Speaking income all has trips');
}
// end of render period instance
}; // renderPeriod
// //////////////////////////////////////////////////////////////////////////////
// var me = authn.currentUser()
// Render a single Period
// This works only if enough metadata about the properties can drive the RDFS
// (or actual type statements whichtypically are NOT there on)
const t = kb.findTypeURIs(subject);
if (t['http://www.w3.org/2000/10/swap/pim/qif#Period']) {
const needed = kb.each(subject, ns.rdfs('seeAlso'));
console.log('Loading before render: ' + needed.length);
kb.fetcher.load(needed).then(function () {
renderPeriod();
});
}
// if (!me) complain("You do not have your Web Id set. Set your Web ID to make changes.");
return div;
}
}; // ends