solid-ui
Version:
UI library for writing Solid read-write-web applications
805 lines (786 loc) • 30 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getChunks = getChunks;
exports.lightColorHash = lightColorHash;
Object.defineProperty(exports, "manageParticipation", {
enumerable: true,
get: function get() {
return _participation.manageParticipation;
}
});
exports.notepad = notepad;
exports.notepadToHTML = notepadToHTML;
Object.defineProperty(exports, "participationObject", {
enumerable: true,
get: function get() {
return _participation.participationObject;
}
});
Object.defineProperty(exports, "recordParticipation", {
enumerable: true,
get: function get() {
return _participation.recordParticipation;
}
});
Object.defineProperty(exports, "renderParticipants", {
enumerable: true,
get: function get() {
return _participation.renderParticipants;
}
});
exports.xmlEncode = xmlEncode;
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/wrapNativeSuper"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var ns = _interopRequireWildcard(require("./ns"));
var _rdflib = require("rdflib");
var _widgets = require("./widgets");
var _utils = require("./utils");
var _debug = require("./debug");
var _solidLogic = require("solid-logic");
var style = _interopRequireWildcard(require("./style"));
var _participation = require("./participation");
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 _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /** **************
* Notepad Widget
*/ /** @module pad
*/
var store = _solidLogic.solidLogicSingleton.store;
var PAD = (0, _rdflib.Namespace)('http://www.w3.org/ns/pim/pad#');
/**
* @ignore
*/
var NotepadElement = /*#__PURE__*/function (_HTMLElement) {
function NotepadElement() {
var _this;
(0, _classCallCheck2["default"])(this, NotepadElement);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _callSuper(this, NotepadElement, [].concat(args));
(0, _defineProperty2["default"])(_this, "subject", void 0);
return _this;
}
(0, _inherits2["default"])(NotepadElement, _HTMLElement);
return (0, _createClass2["default"])(NotepadElement);
}(/*#__PURE__*/(0, _wrapNativeSuper2["default"])(HTMLElement));
/**
* @ignore
*/
var NotepadPart = /*#__PURE__*/function (_HTMLElement2) {
function NotepadPart() {
var _this2;
(0, _classCallCheck2["default"])(this, NotepadPart);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
_this2 = _callSuper(this, NotepadPart, [].concat(args));
(0, _defineProperty2["default"])(_this2, "subject", void 0);
(0, _defineProperty2["default"])(_this2, "value", void 0);
(0, _defineProperty2["default"])(_this2, "state", void 0);
(0, _defineProperty2["default"])(_this2, "lastSent", void 0);
return _this2;
}
(0, _inherits2["default"])(NotepadPart, _HTMLElement2);
return (0, _createClass2["default"])(NotepadPart);
}(/*#__PURE__*/(0, _wrapNativeSuper2["default"])(HTMLElement));
/** Figure out a random color from my webid
*
* @param {NamedNode} author - The author of text being displayed
* @returns {String} The CSS color generated, constrained to be light for a background color
*/
function lightColorHash(author) {
var hash = function hash(x) {
return x.split('').reduce(function (a, b) {
a = (a << 5) - a + b.charCodeAt(0);
return a & a;
}, 0);
};
return author && author.uri ? '#' + (hash(author.uri) & 0xffffff | 0xc0c0c0).toString(16) : '#ffffff'; // c0c0c0 forces pale
} // no id -> white
/** notepad
*
* @param {HTMLDocument} dom - the web page of the browser
* @param {NamedNode} padDoc - the document in which the participation should be shown
* @param {NamedNode} subject - the thing in which participation is happening
* @param {NamedNode} me - person who is logged into the pod
* @param {notepadOptions} options - the options that can be passed in consist of statusArea, exists
*/
function notepad(dom, padDoc, subject, me, options) {
options = options || {};
var exists = options.exists;
var table = dom.createElement('table');
var kb = store;
if (me && !me.uri) throw new Error('UI.pad.notepad: Invalid userid');
var updater = store.updater;
var PAD = (0, _rdflib.Namespace)('http://www.w3.org/ns/pim/pad#');
table.setAttribute('style', style.notepadStyle);
var upstreamStatus = null;
var downstreamStatus = null;
if (options.statusArea) {
var t = options.statusArea.appendChild(dom.createElement('table'));
var tr = t.appendChild(dom.createElement('tr'));
upstreamStatus = tr.appendChild(dom.createElement('td'));
downstreamStatus = tr.appendChild(dom.createElement('td'));
if (upstreamStatus) {
upstreamStatus.setAttribute('style', style.upstreamStatus);
}
if (downstreamStatus) {
downstreamStatus.setAttribute('style', style.downstreamStatus);
}
}
/* @@ TODO want to look into this, it seems upstream should be a boolean and default to false ?
*
*/
var complain = function complain(message) {
var upstream = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
(0, _debug.log)(message);
if (options.statusArea) {
;
(upstream ? upstreamStatus : downstreamStatus).appendChild((0, _widgets.errorMessageBlock)(dom, message, 'pink'));
}
};
// @@ TODO need to refactor so that we don't have to type cast
var clearStatus = function clearStatus(_upsteam) {
if (options.statusArea) {
options.statusArea.innerHTML = '';
}
};
var setPartStyle = function setPartStyle(part, colors, pending) {
var chunk = part.subject;
colors = colors || '';
var baseStyle = style.baseStyle;
var headingCore = style.headingCore;
var headingStyle = style.headingStyle;
var author = kb.any(chunk, ns.dc('author'));
if (!colors && author) {
// Hash the user webid for now -- later allow user selection!
var bgcolor = lightColorHash(author);
colors = 'color: ' + (pending ? '#888' : 'black') + '; background-color: ' + bgcolor + ';';
}
// @@ TODO Need to research when this can be an object with the indent stored in value
// and when the indent is stored as a Number itself, not in an object.
var indent = kb.any(chunk, PAD('indent'));
indent = indent ? indent.value : 0;
var localStyle = indent >= 0 ? baseStyle + 'text-indent: ' + indent * 3 + 'em;' : headingCore + headingStyle[-1 - indent];
// ? baseStyle + 'padding-left: ' + (indent * 3) + 'em;'
part.setAttribute('style', localStyle + colors);
};
var removePart = function removePart(part) {
var chunk = part.subject;
if (!chunk) throw new Error('No chunk for line to be deleted!'); // just in case
var prev = kb.any(undefined, PAD('next'), chunk);
var next = kb.any(chunk, PAD('next'));
if (prev.sameTerm(subject) && next.sameTerm(subject)) {
// Last one
(0, _debug.log)("You can't delete the only line.");
return;
}
var del = kb.statementsMatching(chunk, undefined, undefined, padDoc).concat(kb.statementsMatching(undefined, undefined, chunk, padDoc));
var ins = [(0, _rdflib.st)(prev, PAD('next'), next, padDoc)];
// @@ TODO what should we do if chunk is not a NamedNode should we
// assume then it is a string?
if (chunk instanceof _rdflib.NamedNode) {
var label = chunk.uri.slice(-4);
(0, _debug.log)('Deleting line ' + label);
}
if (!updater) {
throw new Error('have no updater');
}
// @@ TODO below you can see that before is redefined and not a boolean
updater.update(del, ins, function (uri, ok, errorMessage, response) {
if (ok) {
var row = part.parentNode;
if (row) {
var before = row.previousSibling;
if (row.parentNode) {
row.parentNode.removeChild(row);
}
// console.log(' deleted line ' + label + ' ok ' + part.value)
if (before && before.firstChild) {
// @@ TODO IMPORTANT FOCUS ISN'T A PROPERTY ON A CHILDNODE
before.firstChild.focus();
}
}
} else if (response && response.status === 409) {
// Conflict
setPartStyle(part, 'color: black; background-color: #ffd;'); // yellow
part.state = 0; // Needs downstream refresh
(0, _utils.beep)(0.5, 512); // Ooops clash with other person
setTimeout(function () {
// Ideally, beep! @@
reloadAndSync(); // Throw away our changes and
// updater.requestDownstreamAction(padDoc, reloadAndSync)
}, 1000);
} else {
(0, _debug.log)(' removePart FAILED ' + chunk + ': ' + errorMessage);
(0, _debug.log)(" removePart was deleteing :'" + del);
setPartStyle(part, 'color: black; background-color: #fdd;'); // failed
var res = response ? response.status : ' [no response field] ';
complain('Error ' + res + ' saving changes: ' + errorMessage["true"]); // upstream,
// updater.requestDownstreamAction(padDoc, reloadAndSync);
}
});
}; // removePart
var changeIndent = function changeIndent(part, chunk, delta) {
var del = kb.statementsMatching(chunk, PAD('indent'));
var current = del.length ? Number(del[0].object.value) : 0;
if (current + delta < -3) return; // limit negative indent
var newIndent = current + delta;
var ins = (0, _rdflib.st)(chunk, PAD('indent'), newIndent, padDoc);
if (!updater) {
throw new Error('no updater');
}
updater.update(del, ins, function (uri, ok, errorBody) {
if (!ok) {
(0, _debug.log)("Indent change FAILED '" + newIndent + "' for " + padDoc + ': ' + errorBody);
setPartStyle(part, 'color: black; background-color: #fdd;'); // failed
updater.requestDownstreamAction(padDoc, reloadAndSync);
} else {
setPartStyle(part); // Implement the indent
}
});
};
var addListeners = function addListeners(part, chunk) {
part.addEventListener('keydown', function (event) {
if (!updater) {
throw new Error('no updater');
}
var queueProperty, queue;
// up 38; down 40; left 37; right 39 tab 9; shift 16; escape 27
switch (event.keyCode) {
case 13:
// Return
{
var before = event.shiftKey;
(0, _debug.log)('enter'); // Shift-return inserts before -- only way to add to top of pad.
if (before) {
queue = kb.any(undefined, PAD('next'), chunk);
queueProperty = 'newlinesAfter';
} else {
queue = kb.any(chunk, PAD('next'));
queueProperty = 'newlinesBefore';
}
queue[queueProperty] = queue[queueProperty] || 0;
queue[queueProperty] += 1;
if (queue[queueProperty] > 1) {
(0, _debug.log)(' queueing newline queue = ' + queue[queueProperty]);
return;
}
(0, _debug.log)(' go ahead line before ' + queue[queueProperty]);
_newChunk(part, before); // was document.activeElement
break;
}
case 8:
// Delete
if (part.value.length === 0) {
(0, _debug.log)('Delete key line ' + chunk.uri.slice(-4) + ' state ' + part.state);
switch (part.state) {
case 1: // contents being sent
case 2:
// contents need to be sent again
part.state = 4; // delete me
return;
case 3: // already being deleted
case 4:
// already deleted state
return;
case undefined:
case 0:
part.state = 3; // being deleted
removePart(part);
event.preventDefault();
break;
// continue
default:
throw new Error('pad: Unexpected state ' + part);
}
}
break;
case 9:
// Tab
{
var delta = event.shiftKey ? -1 : 1;
changeIndent(part, chunk, delta);
event.preventDefault(); // default is to highlight next field
break;
}
case 27:
// ESC
(0, _debug.log)('escape');
updater.requestDownstreamAction(padDoc, reloadAndSync);
event.preventDefault();
break;
case 38:
// Up
if (part.parentNode.previousSibling) {
part.parentNode.previousSibling.firstChild.focus();
event.preventDefault();
}
break;
case 40:
// Down
if (part.parentNode.nextSibling) {
part.parentNode.nextSibling.firstChild.focus();
event.preventDefault();
}
break;
default:
}
});
var _updateStore = function updateStore(part) {
var chunk = part.subject;
setPartStyle(part, undefined, true);
var old = kb.any(chunk, ns.sioc('content')).value;
var del = [(0, _rdflib.st)(chunk, ns.sioc('content'), old, padDoc)];
var ins;
if (part.value) {
ins = [(0, _rdflib.st)(chunk, ns.sioc('content'), part.value, padDoc)];
}
var newOne = part.value;
// DEBUGGING ONLY
if (part.lastSent) {
if (old !== part.lastSent) {
throw new Error("Out of order, last sent expected '" + old + "' but found '" + part.lastSent + "'");
}
}
part.lastSent = newOne;
/* console.log(
' Patch proposed to ' +
chunk.uri.slice(-4) +
" '" +
old +
"' -> '" +
newOne +
"' "
) */
if (!updater) {
throw new Error('no updater');
}
updater.update(del, ins, function (uri, ok, errorBody, xhr) {
if (!ok) {
// alert("clash " + errorBody);
(0, _debug.log)(' patch FAILED ' + xhr.status + " for '" + old + "' -> '" + newOne + "': " + errorBody);
if (xhr.status === 409) {
// Conflict - @@ we assume someone else
setPartStyle(part, 'color: black; background-color: #fdd;');
part.state = 0; // Needs downstream refresh
(0, _utils.beep)(0.5, 512); // Ooops clash with other person
setTimeout(function () {
updater.requestDownstreamAction(padDoc, reloadAndSync);
}, 1000);
} else {
setPartStyle(part, 'color: black; background-color: #fdd;'); // failed pink
part.state = 0;
complain(' Error ' + xhr.status + ' sending data: ' + errorBody, true);
(0, _utils.beep)(1.0, 128); // Other
// @@@ Do soemthing more serious with other errors eg auth, etc
}
} else {
clearStatus(true); // upstream
setPartStyle(part); // synced
(0, _debug.log)(" Patch ok '" + old + "' -> '" + newOne + "' ");
if (part.state === 4) {
// delete me
part.state = 3;
removePart(part);
} else if (part.state === 3) {
// being deleted
// pass
} else if (part.state === 2) {
part.state = 1; // pending: lock
_updateStore(part);
} else {
part.state = 0; // clear lock
}
}
});
};
part.addEventListener('input', function inputChangeListener(_event) {
// debug.log("input changed "+part.value);
setPartStyle(part, undefined, true); // grey out - not synced
(0, _debug.log)('Input event state ' + part.state + " value '" + part.value + "'");
switch (part.state) {
case 3:
// being deleted
return;
case 4:
// needs to be deleted
return;
case 2:
// needs content updating, we know
return;
case 1:
part.state = 2; // lag we need another patch
return;
case 0:
case undefined:
part.state = 1; // being upadted
_updateStore(part);
}
}); // listener
}; // addlisteners
// @@ TODO Need to research before as it appears to be used as an Element and a boolean
var newPartAfter = function newPartAfter(tr1, chunk, before) {
// @@ take chunk and add listeners
var text = kb.any(chunk, ns.sioc('content'));
text = text ? text.value : '';
var tr = dom.createElement('tr');
if (before) {
table.insertBefore(tr, tr1);
} else {
// after
if (tr1 && tr1.nextSibling) {
table.insertBefore(tr, tr1.nextSibling);
} else {
table.appendChild(tr);
}
}
var part = tr.appendChild(dom.createElement('input'));
part.subject = chunk;
part.setAttribute('type', 'text');
part.value = text;
if (me) {
setPartStyle(part, '');
addListeners(part, chunk);
} else {
setPartStyle(part, 'color: #222; background-color: #fff');
(0, _debug.log)("Note can't add listeners - not logged in");
}
return part;
};
/* @@ TODO we need to look at indent, it can be a Number or an Object this doesn't seem correct.
*/
var _newChunk = function newChunk(ele, before) {
// element of chunk being split
var kb = store;
var indent = 0;
var queueProperty = null;
var here, prev, next, queue, tr1;
if (ele) {
if (ele.tagName.toLowerCase() !== 'input') {
(0, _debug.log)('return pressed when current document is: ' + ele.tagName);
}
here = ele.subject;
indent = kb.any(here, PAD('indent'));
indent = indent ? Number(indent.value) : 0;
if (before) {
prev = kb.any(undefined, PAD('next'), here);
next = here;
queue = prev;
queueProperty = 'newlinesAfter';
} else {
prev = here;
next = kb.any(here, PAD('next'));
queue = next;
queueProperty = 'newlinesBefore';
}
tr1 = ele.parentNode;
} else {
prev = subject;
next = subject;
tr1 = undefined;
}
var chunk = (0, _widgets.newThing)(padDoc);
var label = chunk.uri.slice(-4);
var del = [(0, _rdflib.st)(prev, PAD('next'), next, padDoc)];
var ins = [(0, _rdflib.st)(prev, PAD('next'), chunk, padDoc), (0, _rdflib.st)(chunk, PAD('next'), next, padDoc), (0, _rdflib.st)(chunk, ns.dc('author'), me, padDoc), (0, _rdflib.st)(chunk, ns.sioc('content'), '', padDoc)];
if (indent > 0) {
// Do not inherit
ins.push((0, _rdflib.st)(chunk, PAD('indent'), indent, padDoc));
}
(0, _debug.log)(' Fresh chunk ' + label + ' proposed');
if (!updater) {
throw new Error('no updater');
}
updater.update(del, ins, function (uri, ok, errorBody, _xhr) {
if (!ok) {
// alert("Error writing new line " + label + ": " + errorBody);
(0, _debug.log)(' ERROR writing new line ' + label + ': ' + errorBody);
} else {
var newPart = newPartAfter(tr1, chunk, before);
setPartStyle(newPart);
newPart.focus(); // Note this is delayed
if (queueProperty) {
(0, _debug.log)(' Fresh chunk ' + label + ' updated, queue = ' + queue[queueProperty]);
queue[queueProperty] -= 1;
if (queue[queueProperty] > 0) {
(0, _debug.log)(' Implementing queued newlines = ' + next.newLinesBefore);
_newChunk(newPart, before);
}
}
}
});
};
var consistencyCheck = function consistencyCheck() {
var found = {};
var failed = 0;
function complain2(msg) {
complain(msg);
failed++;
}
if (!kb.the(subject, PAD('next'))) {
complain2('No initial next pointer');
return false; // can't do linked list
}
// var chunk = kb.the(subject, PAD('next'))
var prev = subject;
var chunk;
for (;;) {
chunk = kb.the(prev, PAD('next'));
if (!chunk) {
complain2('No next pointer from ' + prev);
}
if (chunk.sameTerm(subject)) {
break;
}
prev = chunk;
var label = chunk.uri.split('#')[1];
if (found[chunk.uri]) {
complain2('Loop!');
return false;
}
found[chunk.uri] = true;
var k = kb.each(chunk, PAD('next')).length;
if (k !== 1) {
complain2('Should be 1 not ' + k + ' next pointer for ' + label);
}
k = kb.each(chunk, PAD('indent')).length;
if (k > 1) {
complain2('Should be 0 or 1 not ' + k + ' indent for ' + label);
}
k = kb.each(chunk, ns.sioc('content')).length;
if (k !== 1) {
complain2('Should be 1 not ' + k + ' contents for ' + label);
}
k = kb.each(chunk, ns.dc('author')).length;
if (k !== 1) {
complain2('Should be 1 not ' + k + ' author for ' + label);
}
var sts = kb.statementsMatching(undefined, ns.sioc('contents'));
sts.forEach(function (st) {
if (!found[st.subject.value]) {
complain2('Loose chunk! ' + st.subject.value);
}
});
}
return !failed;
};
// Ensure that the display matches the current state of the
// @@ TODO really need to refactor this so that we don't need to cast types
var sync = function sync() {
// var first = kb.the(subject, PAD('next'))
if (kb.each(subject, PAD('next')).length !== 1) {
var msg = 'Pad: Inconsistent data - NEXT pointers: ' + kb.each(subject, PAD('next')).length;
(0, _debug.log)(msg);
if (options.statusArea) {
options.statusArea.textContent += msg;
}
return;
}
var row;
// First see which of the logical chunks have existing physical manifestations
var manif = [];
// Find which lines correspond to existing chunks
for (var chunk = kb.the(subject, PAD('next')); !chunk.sameTerm(subject); chunk = kb.the(chunk, PAD('next'))) {
for (var i = 0; i < table.children.length; i++) {
var _tr = table.children[i];
if (_tr.firstChild) {
if (_tr.firstChild.subject.sameTerm(chunk)) {
manif[chunk.uri] = _tr.firstChild;
}
}
}
}
// Remove any deleted lines
for (var _i = table.children.length - 1; _i >= 0; _i--) {
row = table.children[_i];
if (!manif[row.firstChild.subject.uri]) {
table.removeChild(row);
}
}
// Insert any new lines and update old ones
row = table.firstChild; // might be null
for (var _chunk = kb.the(subject, PAD('next')); !_chunk.sameTerm(subject); _chunk = kb.the(_chunk, PAD('next'))) {
var text = kb.any(_chunk, ns.sioc('content')).value;
// superstitious -- don't mess with unchanged input fields
// which may be selected by the user
if (row && manif[_chunk.uri]) {
var part = row.firstChild;
if (text !== part.value) {
part.value = text;
}
setPartStyle(part);
part.state = 0; // Clear the state machine
delete part.lastSent; // DEBUG ONLY
row = row.nextSibling;
} else {
newPartAfter(row, _chunk, true); // actually before
}
}
};
// Refresh the DOM tree
var _refreshTree = function refreshTree(root) {
if (root.refresh) {
root.refresh();
return;
}
for (var i = 0; i < root.children.length; i++) {
_refreshTree(root.children[i]);
}
};
var reloading = false;
var checkAndSync = function checkAndSync() {
(0, _debug.log)(' reloaded OK');
clearStatus();
if (!consistencyCheck()) {
complain('CONSISTENCY CHECK FAILED');
} else {
_refreshTree(table);
}
};
var reloadAndSync = function reloadAndSync() {
if (reloading) {
(0, _debug.log)(' Already reloading - stop');
return; // once only needed
}
reloading = true;
var retryTimeout = 1000; // ms
var _tryReload = function tryReload() {
(0, _debug.log)('try reload - timeout = ' + retryTimeout);
if (!updater) {
throw new Error('no updater');
}
updater.reload(updater.store, padDoc, function (ok, message, xhr) {
reloading = false;
if (ok) {
checkAndSync();
} else {
if (xhr.status === 0) {
complain('Network error refreshing the pad. Retrying in ' + retryTimeout / 1000);
reloading = true;
retryTimeout = retryTimeout * 2;
setTimeout(_tryReload, retryTimeout);
} else {
complain('Error ' + xhr.status + 'refreshing the pad:' + message + '. Stopped. ' + padDoc);
}
}
});
};
_tryReload();
};
table.refresh = sync; // Catch downward propagating refresh events
table.reloadAndSync = reloadAndSync;
if (!me) (0, _debug.log)('Warning: must be logged in for pad to be edited');
if (exists) {
(0, _debug.log)('Existing pad.');
if (consistencyCheck()) {
sync();
if (kb.holds(subject, PAD('next'), subject)) {
// Empty list untenable
_newChunk(); // require at least one line
}
} else {
(0, _debug.log)(table.textContent = 'Inconsistent data. Abort');
}
} else {
// Make new pad
(0, _debug.log)('No pad exists - making new one.');
var insertables = [(0, _rdflib.st)(subject, ns.rdf('type'), PAD('Notepad'), padDoc), (0, _rdflib.st)(subject, ns.dc('author'), me, padDoc), (0, _rdflib.st)(subject, ns.dc('created'), new Date(), padDoc), (0, _rdflib.st)(subject, PAD('next'), subject, padDoc)];
if (!updater) {
throw new Error('no updater');
}
updater.update([], insertables, function (uri, ok, errorBody) {
if (!ok) {
complain(errorBody || '');
} else {
(0, _debug.log)('Initial pad created');
_newChunk(); // Add a first chunck
// getResults();
}
});
}
return table;
}
/**
* Get the chunks of the notepad
* They are stored in a RDF linked list
*/
// @ignore exporting this only for the unit test
function getChunks(subject, kb) {
var chunks = [];
for (var chunk = kb.the(subject, PAD('next')); !chunk.sameTerm(subject); chunk = kb.the(chunk, PAD('next'))) {
chunks.push(chunk);
}
return chunks;
}
/**
* Encode content to be put in XML or HTML elements
*/
// @ignore exporting this only for the unit test
function xmlEncode(str) {
return str.replace('&', '&').replace('<', '<').replace('>', '>');
}
/**
* Convert a notepad to HTML
* @param { } pad - the notepad
* @param {store} pad - the data store
*/
function notepadToHTML(pad, kb) {
var chunks = getChunks(pad, kb);
var html = '<html>\n <head>\n';
var title = kb.anyValue(pad, ns.dct('title'));
if (title) {
html += " <title>".concat(xmlEncode(title), "</title>\n");
}
html += ' </head>\n <body>\n';
var level = 0;
function increaseLevel(indent) {
for (; level < indent; level++) {
html += '<ul>\n';
}
}
function decreaseLevel(indent) {
for (; level > indent; level--) {
html += '</ul>\n';
}
}
chunks.forEach(function (chunk) {
var indent = kb.anyJS(chunk, PAD('indent'));
var rawContent = kb.anyJS(chunk, ns.sioc('content'));
if (!rawContent) return; // seed chunk is dummy
var content = xmlEncode(rawContent);
if (indent < 0) {
// negative indent levels represent heading levels
decreaseLevel(0);
var h = indent >= -3 ? 4 + indent : 1; // -1 -> h4, -2 -> h3
html += "\n<h".concat(h, ">").concat(content, "</h").concat(h, ">\n");
} else {
// >= 0
if (indent > 0) {
// Lists
decreaseLevel(indent);
increaseLevel(indent);
html += "<li>".concat(content, "</li>\n");
} else {
// indent 0
decreaseLevel(indent);
html += "<p>".concat(content, "</p>\n");
}
}
}); // foreach chunk
// At the end decreaseLevel any open ULs
decreaseLevel(0);
html += ' </body>\n</html>\n';
return html;
}
//# sourceMappingURL=pad.js.map