UNPKG

solid-ui

Version:

UI library for writing Solid read-write-web applications

1,515 lines (1,235 loc) • 63.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.findOriginOwner = findOriginOwner; exports.saveUser = saveUser; exports.defaultTestUser = defaultTestUser; exports.currentUser = currentUser; exports.logIn = logIn; exports.logInLoadProfile = logInLoadProfile; exports.logInLoadPreferences = logInLoadPreferences; exports.loadTypeIndexes = loadTypeIndexes; exports.findAppInstances = findAppInstances; exports.registerInTypeIndex = registerInTypeIndex; exports.registrationControl = registrationControl; exports.registrationList = registrationList; exports.setACLUserPublic = setACLUserPublic; exports.offlineTestID = offlineTestID; exports.checkUser = checkUser; exports.loginStatusBox = loginStatusBox; exports.selectWorkspace = selectWorkspace; exports.newAppInstance = newAppInstance; exports.getUserRoles = getUserRoles; exports.filterAvailablePanes = filterAvailablePanes; Object.defineProperty(exports, "solidAuthClient", { enumerable: true, get: function get() { return _solidAuthClient["default"]; } }); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _rdflib = require("rdflib"); var _solidAuthClient = _interopRequireDefault(require("solid-auth-client")); var _signup = require("./signup"); var widgets = _interopRequireWildcard(require("../widgets")); var ns = _interopRequireWildcard(require("../ns.js")); var utils = _interopRequireWildcard(require("../utils")); var _log = require("../log"); var debug = _interopRequireWildcard(require("../debug")); var _style = require("../style"); var _logic = require("../logic"); var _solidLogic = require("solid-logic"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * Signing in, signing up, profile and preferences reloading * Type index management * * Many functions in this module take a context object which * holds various RDF symbols, add to it, and return a promise of it. * * * `me` RDF symbol for the user's WebID * * `publicProfile` The user's public profile, iff loaded * * `preferencesFile` The user's personal preference file, iff loaded * * `index.public` The user's public type index file * * `index.private` The user's private type index file * * Not RDF symbols: * * `noun` A string in english for the type of thing -- like "address book" * * `instance` An array of nodes which are existing instances * * `containers` An array of nodes of containers of instances * * `div` A DOM element where UI can be displayed * * `statusArea` A DOM element (opt) progress stuff can be displayed, or error messages * @packageDocumentation */ // const userCheckSite = 'https://databox.me/' /** * Look for and load the User who has control over it */ function findOriginOwner(doc) { var uri = typeof doc === 'string' ? doc : doc.uri; var i = uri.indexOf('://'); if (i < 0) return false; var j = uri.indexOf('/', i + 3); if (j < 0) return false; var origin = uri.slice(0, j + 1); // @@ TBC return origin; } /** * Saves `webId` in `context.me` * @param webId * @param context * * @returns Returns the WebID, after setting it */ function saveUser(webId, context) { // @@ TODO Remove the need for having context as output argument var webIdUri; if (webId) { webIdUri = typeof webId === 'string' ? webId : webId.uri; var me = (0, _rdflib.namedNode)(webIdUri); if (context) { context.me = me; } return me; } return null; } /** * Wrapper around [[offlineTestID]] * @returns {NamedNode|null} */ function defaultTestUser() { // Check for offline override var offlineId = offlineTestID(); if (offlineId) { return offlineId; } return null; } /** * Checks synchronously whether user is logged in * * @returns Named Node or null */ function currentUser() { var str = localStorage['solid-auth-client']; if (str) { var da = JSON.parse(str); if (da.session && da.session.webId) { // @@ TODO check has not expired return (0, _rdflib.sym)(da.session.webId); } } return offlineTestID(); // null unless testing // JSON.parse(localStorage['solid-auth-client']).session.webId } /** * Resolves with the logged in user's WebID * * @param context */ function logIn(context) { var me = defaultTestUser(); // me is a NamedNode or null if (me) { context.me = me; return Promise.resolve(context); } return new Promise(function (resolve) { checkUser().then(function (webId) { // Already logged in? if (webId) { context.me = (0, _rdflib.sym)(webId); debug.log("logIn: Already logged in as ".concat(context.me)); return resolve(context); } if (!context.div || !context.dom) { return resolve(context); } var box = loginStatusBox(context.dom, function (webIdUri) { saveUser(webIdUri, context); resolve(context); // always pass growing context }); context.div.appendChild(box); }); }); } /** * Logs the user in and loads their WebID profile document into the store * * @param context * * @returns Resolves with the context after login / fetch */ function logInLoadProfile(_x2) { return _logInLoadProfile.apply(this, arguments); } /** * Loads preference file * Do this after having done log in and load profile * * @private * * @param context */ function _logInLoadProfile() { _logInLoadProfile = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(context) { var loggedInContext; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!context.publicProfile) { _context2.next = 2; break; } return _context2.abrupt("return", context); case 2: _context2.prev = 2; _context2.next = 5; return logIn(context); case 5: loggedInContext = _context2.sent; if (loggedInContext.me) { _context2.next = 8; break; } throw new Error('Could not log in'); case 8: _context2.next = 10; return _logic.solidLogicSingleton.loadProfile(loggedInContext.me); case 10: context.publicProfile = _context2.sent; _context2.next = 17; break; case 13: _context2.prev = 13; _context2.t0 = _context2["catch"](2); if (context.div && context.dom) { context.div.appendChild(widgets.errorMessageBlock(context.dom, _context2.t0.message)); } throw new Error("Can't log in: ".concat(_context2.t0)); case 17: return _context2.abrupt("return", context); case 18: case "end": return _context2.stop(); } } }, _callee2, null, [[2, 13]]); })); return _logInLoadProfile.apply(this, arguments); } function logInLoadPreferences(_x3) { return _logInLoadPreferences.apply(this, arguments); } /** * Resolves with the same context, outputting * output: index.public, index.private * * @see https://github.com/solid/solid/blob/main/proposals/data-discovery.md#discoverability */ function _logInLoadPreferences() { _logInLoadPreferences = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(context) { var statusArea, progressDisplay, complain, preferencesFile, m2; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: complain = function _complain(message) { message = "logInLoadPreferences: ".concat(message); if (statusArea) { // statusArea.innerHTML = '' statusArea.appendChild(widgets.errorMessageBlock(context.dom, message)); } debug.log(message); // reject(new Error(message)) }; if (!context.preferencesFile) { _context3.next = 3; break; } return _context3.abrupt("return", Promise.resolve(context)); case 3: // already done statusArea = context.statusArea || context.div || null; _context3.prev = 4; _context3.next = 7; return logInLoadProfile(context); case 7: context = _context3.sent; _context3.next = 10; return _logic.solidLogicSingleton.loadPreferences(context.me); case 10: preferencesFile = _context3.sent; if (progressDisplay) { progressDisplay.parentNode.removeChild(progressDisplay); } context.preferencesFile = preferencesFile; _context3.next = 48; break; case 15: _context3.prev = 15; _context3.t0 = _context3["catch"](4); if (!(_context3.t0 instanceof _solidLogic.UnauthorizedError)) { _context3.next = 22; break; } m2 = 'Ooops - you are not authenticated (properly logged in) to for me to read your preference file. Try loggin out and logging in?'; (0, _log.alert)(m2); _context3.next = 48; break; case 22: if (!(_context3.t0 instanceof _solidLogic.CrossOriginForbiddenError)) { _context3.next = 28; break; } m2 = "Unauthorized: Assuming preference file blocked for origin ".concat(window.location.origin); context.preferencesFileError = m2; return _context3.abrupt("return", context); case 28: if (!(_context3.t0 instanceof _solidLogic.SameOriginForbiddenError)) { _context3.next = 33; break; } m2 = 'You are not authorized to read your preference file. This may be because you are using an untrusted web app.'; debug.warn(m2); _context3.next = 48; break; case 33: if (!(_context3.t0 instanceof _solidLogic.NotFoundError)) { _context3.next = 42; break; } if (!confirm("You do not currently have a preference file. OK for me to create an empty one? ".concat(_context3.t0.preferencesFile || ''))) { _context3.next = 39; break; } // @@@ code me ... weird to have a name of the file but no file (0, _log.alert)("Sorry; I am not prepared to do this. Please create an empty file at ".concat(_context3.t0.preferencesFile || '(?)')); complain(new Error('Sorry; no code yet to create a preference file at ')); _context3.next = 40; break; case 39: throw new Error("User declined to create a preference file at ".concat(_context3.t0.preferencesFile || '(?)')); case 40: _context3.next = 48; break; case 42: if (!(_context3.t0 instanceof _solidLogic.FetchError)) { _context3.next = 47; break; } m2 = "Strange: Error ".concat(_context3.t0.status, " trying to read your preference file.").concat(_context3.t0.message); (0, _log.alert)(m2); _context3.next = 48; break; case 47: throw new Error("(via loadPrefs) ".concat(_context3.t0)); case 48: return _context3.abrupt("return", context); case 49: case "end": return _context3.stop(); } } }, _callee3, null, [[4, 15]]); })); return _logInLoadPreferences.apply(this, arguments); } function loadIndex(_x4, _x5) { return _loadIndex.apply(this, arguments); } function _loadIndex() { _loadIndex = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(context, isPublic) { var indexes; return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: _context5.next = 2; return _logic.solidLogicSingleton.loadIndexes(context.me, isPublic ? context.publicProfile || null : null, isPublic ? null : context.preferencesFile || null, /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(err) { return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: return _context4.abrupt("return", widgets.complain(context, err.message)); case 1: case "end": return _context4.stop(); } } }, _callee4); })); return function (_x19) { return _ref.apply(this, arguments); }; }()); case 2: indexes = _context5.sent; context.index = context.index || {}; context.index["private"] = indexes["private"] || context.index["private"]; context.index["public"] = indexes["public"] || context.index["public"]; return _context5.abrupt("return", context); case 7: case "end": return _context5.stop(); } } }, _callee5); })); return _loadIndex.apply(this, arguments); } function loadTypeIndexes(_x6) { return _loadTypeIndexes.apply(this, arguments); } /** * Resolves with the same context, outputting * @see https://github.com/solid/solid/blob/main/proposals/data-discovery.md#discoverability */ function _loadTypeIndexes() { _loadTypeIndexes = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(context) { var indexes; return _regenerator["default"].wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _context7.next = 2; return _logic.solidLogicSingleton.loadIndexes(context.me, context.publicProfile || null, context.preferencesFile || null, /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(err) { return _regenerator["default"].wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: return _context6.abrupt("return", widgets.complain(context, err.message)); case 1: case "end": return _context6.stop(); } } }, _callee6); })); return function (_x20) { return _ref2.apply(this, arguments); }; }()); case 2: indexes = _context7.sent; context.index = context.index || {}; context.index["private"] = indexes["private"] || context.index["private"]; context.index["public"] = indexes["public"] || context.index["public"]; return _context7.abrupt("return", context); case 7: case "end": return _context7.stop(); } } }, _callee7); })); return _loadTypeIndexes.apply(this, arguments); } function ensureTypeIndexes(_x7) { return _ensureTypeIndexes.apply(this, arguments); } /** * Load or create ONE type index * Find one or make one or fail * Many reasons for failing including script not having permission etc * * Adds its output to the context * @see https://github.com/solid/solid/blob/main/proposals/data-discovery.md#discoverability */ function _ensureTypeIndexes() { _ensureTypeIndexes = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(context) { return _regenerator["default"].wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: _context8.next = 2; return ensureOneTypeIndex(context, true); case 2: _context8.next = 4; return ensureOneTypeIndex(context, false); case 4: return _context8.abrupt("return", context); case 5: case "end": return _context8.stop(); } } }, _callee8); })); return _ensureTypeIndexes.apply(this, arguments); } function ensureOneTypeIndex(_x8, _x9) { return _ensureOneTypeIndex.apply(this, arguments); } /** * Returns promise of context with arrays of symbols * * 2016-12-11 change to include forClass arc a la * https://github.com/solid/solid/blob/main/proposals/data-discovery.md */ function _ensureOneTypeIndex() { _ensureOneTypeIndex = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11(context, isPublic) { var makeIndexIfNecessary, _makeIndexIfNecessary; return _regenerator["default"].wrap(function _callee11$(_context11) { while (1) { switch (_context11.prev = _context11.next) { case 0: _makeIndexIfNecessary = function _makeIndexIfNecessary3() { _makeIndexIfNecessary = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(context, isPublic) { var relevant, visibility, putIndex, _putIndex, newIndex, addMe, msg, ixs; return _regenerator["default"].wrap(function _callee10$(_context10) { while (1) { switch (_context10.prev = _context10.next) { case 0: _putIndex = function _putIndex3() { _putIndex = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9(newIndex) { var _msg; return _regenerator["default"].wrap(function _callee9$(_context9) { while (1) { switch (_context9.prev = _context9.next) { case 0: _context9.prev = 0; _context9.next = 3; return _logic.solidLogicSingleton.createEmptyRdfDoc(newIndex, 'Blank initial Type index'); case 3: return _context9.abrupt("return", context); case 6: _context9.prev = 6; _context9.t0 = _context9["catch"](0); _msg = "Error creating new index ".concat(_context9.t0); widgets.complain(context, _msg); case 10: case "end": return _context9.stop(); } } }, _callee9, null, [[0, 6]]); })); return _putIndex.apply(this, arguments); }; putIndex = function _putIndex2(_x23) { return _putIndex.apply(this, arguments); }; relevant = isPublic ? context.publicProfile : context.preferencesFile; visibility = isPublic ? 'public' : 'private'; // putIndex context.index = context.index || {}; context.index[visibility] = context.index[visibility] || []; if (!(context.index[visibility].length === 0)) { _context10.next = 29; break; } newIndex = (0, _rdflib.sym)("".concat(relevant.dir().uri + visibility, "TypeIndex.ttl")); debug.log("Linking to new fresh type index ".concat(newIndex)); if (confirm("OK to create a new empty index file at ".concat(newIndex, ", overwriting anything that is now there?"))) { _context10.next = 11; break; } throw new Error('cancelled by user'); case 11: debug.log("Linking to new fresh type index ".concat(newIndex)); addMe = [(0, _rdflib.st)(context.me, ns.solid("".concat(visibility, "TypeIndex")), newIndex, relevant)]; _context10.prev = 13; _context10.next = 16; return _logic.solidLogicSingleton.updatePromise([], addMe); case 16: _context10.next = 23; break; case 18: _context10.prev = 18; _context10.t0 = _context10["catch"](13); msg = "Error saving type index link saving back ".concat(newIndex, ": ").concat(_context10.t0); widgets.complain(context, msg); return _context10.abrupt("return", context); case 23: debug.log("Creating new fresh type index file".concat(newIndex)); _context10.next = 26; return putIndex(newIndex); case 26: context.index[visibility].push(newIndex); // @@ wait _context10.next = 38; break; case 29: // officially exists ixs = context.index[visibility]; _context10.prev = 30; _context10.next = 33; return _logic.solidLogicSingleton.load(ixs); case 33: _context10.next = 38; break; case 35: _context10.prev = 35; _context10.t1 = _context10["catch"](30); widgets.complain(context, "ensureOneTypeIndex: loading indexes ".concat(_context10.t1)); case 38: case "end": return _context10.stop(); } } }, _callee10, null, [[13, 18], [30, 35]]); })); return _makeIndexIfNecessary.apply(this, arguments); }; makeIndexIfNecessary = function _makeIndexIfNecessary2(_x21, _x22) { return _makeIndexIfNecessary.apply(this, arguments); }; _context11.prev = 2; _context11.next = 5; return loadIndex(context, isPublic); case 5: if (context.index) { debug.log("ensureOneTypeIndex: Type index exists already ".concat(isPublic ? context.index["public"][0] : context.index["private"][0])); } return _context11.abrupt("return", context); case 9: _context11.prev = 9; _context11.t0 = _context11["catch"](2); _context11.next = 13; return makeIndexIfNecessary(context, isPublic); case 13: case "end": return _context11.stop(); } } }, _callee11, null, [[2, 9]]); })); return _ensureOneTypeIndex.apply(this, arguments); } function findAppInstances(_x10, _x11, _x12) { return _findAppInstances.apply(this, arguments); } /** * Register a new app in a type index */ function _findAppInstances() { _findAppInstances = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12(context, theClass, isPublic) { var visibility, index, thisIndex, registrations, instances, containers, unique, e, i, cont; return _regenerator["default"].wrap(function _callee12$(_context12) { while (1) { switch (_context12.prev = _context12.next) { case 0: unique = function _unique(arr) { return Array.from(new Set(arr)); }; if (!(isPublic === undefined)) { _context12.next = 7; break; } _context12.next = 4; return findAppInstances(context, theClass, true); case 4: _context12.next = 6; return findAppInstances(context, theClass, false); case 6: return _context12.abrupt("return", context); case 7: _context12.prev = 7; _context12.next = 10; return isPublic ? logInLoadProfile(context) : logInLoadPreferences(context); case 10: _context12.next = 15; break; case 12: _context12.prev = 12; _context12.t0 = _context12["catch"](7); widgets.complain(context, "loadIndex: login and load problem ".concat(_context12.t0)); case 15: // console.log('awaited LogInLoad!', context) visibility = isPublic ? 'public' : 'private'; _context12.prev = 16; _context12.next = 19; return loadIndex(context, isPublic); case 19: _context12.next = 23; break; case 21: _context12.prev = 21; _context12.t1 = _context12["catch"](16); case 23: index = context.index; // eslint-disable-next-line no-console console.log({ index: index, visibility: visibility }); thisIndex = index[visibility]; // eslint-disable-next-line no-console console.log('Failing test?', thisIndex.map(function (ix) { return _logic.solidLogicSingleton.store.each(undefined, ns.solid('forClass'), theClass, ix); })); registrations = thisIndex.map(function (ix) { return _logic.solidLogicSingleton.store.each(undefined, ns.solid('forClass'), theClass, ix); }).flat(); instances = registrations.map(function (reg) { return _logic.solidLogicSingleton.store.each(reg, ns.solid('instance')); }).flat(); containers = registrations.map(function (reg) { return _logic.solidLogicSingleton.store.each(reg, ns.solid('instanceContainer')); }).flat(); context.instances = context.instances || []; context.instances = unique(context.instances.concat(instances)); context.containers = context.containers || []; context.containers = unique(context.containers.concat(containers)); if (containers.length) { _context12.next = 36; break; } return _context12.abrupt("return", context); case 36: _context12.prev = 36; _context12.next = 39; return _logic.solidLogicSingleton.load(containers); case 39: _context12.next = 46; break; case 41: _context12.prev = 41; _context12.t2 = _context12["catch"](36); e = new Error("[FAI] Unable to load containers".concat(_context12.t2)); debug.log(e); // complain widgets.complain(context, "Error looking for ".concat(utils.label(theClass), ": ").concat(_context12.t2)); // but then ignore it // throw new Error(e) case 46: i = 0; case 47: if (!(i < containers.length)) { _context12.next = 57; break; } cont = containers[i]; _context12.t3 = context.instances; _context12.next = 52; return _logic.solidLogicSingleton.getContainerMembers(cont.value); case 52: _context12.t4 = _context12.sent.map(function (uri) { return _logic.solidLogicSingleton.store.sym(uri); }); context.instances = _context12.t3.concat.call(_context12.t3, _context12.t4); case 54: i++; _context12.next = 47; break; case 57: return _context12.abrupt("return", context); case 58: case "end": return _context12.stop(); } } }, _callee12, null, [[7, 12], [16, 21], [36, 41]]); })); return _findAppInstances.apply(this, arguments); } function registerInTypeIndex(_x13, _x14, _x15, _x16) { return _registerInTypeIndex.apply(this, arguments); } /** * UI to control registration of instance */ function _registerInTypeIndex() { _registerInTypeIndex = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(context, instance, theClass, isPublic) { var indexes, index, registration, ins; return _regenerator["default"].wrap(function _callee13$(_context13) { while (1) { switch (_context13.prev = _context13.next) { case 0: _context13.next = 2; return ensureOneTypeIndex(context, isPublic); case 2: if (context.index) { _context13.next = 4; break; } throw new Error('registerInTypeIndex: No type index found'); case 4: indexes = isPublic ? context.index["public"] : context.index["private"]; if (indexes.length) { _context13.next = 7; break; } throw new Error('registerInTypeIndex: What no type index?'); case 7: index = indexes[0]; registration = widgets.newThing(index); ins = [// See https://github.com/solid/solid/blob/main/proposals/data-discovery.md (0, _rdflib.st)(registration, ns.rdf('type'), ns.solid('TypeRegistration'), index), (0, _rdflib.st)(registration, ns.solid('forClass'), theClass, index), (0, _rdflib.st)(registration, ns.solid('instance'), instance, index)]; _context13.prev = 10; _context13.next = 13; return _logic.solidLogicSingleton.updatePromise([], ins); case 13: _context13.next = 19; break; case 15: _context13.prev = 15; _context13.t0 = _context13["catch"](10); debug.log(_context13.t0); (0, _log.alert)(_context13.t0); case 19: return _context13.abrupt("return", context); case 20: case "end": return _context13.stop(); } } }, _callee13, null, [[10, 15]]); })); return _registerInTypeIndex.apply(this, arguments); } function registrationControl(context, instance, theClass) { var dom = context.dom; if (!dom || !context.div) { return Promise.resolve(); } var box = dom.createElement('div'); context.div.appendChild(box); return ensureTypeIndexes(context).then(function () { box.innerHTML = '<table><tbody><tr></tr><tr></tr></tbody></table>'; // tbody will be inserted anyway box.setAttribute('style', 'font-size: 120%; text-align: right; padding: 1em; border: solid gray 0.05em;'); var tbody = box.children[0].children[0]; var form = new _rdflib.BlankNode(); // @@ say for now var registrationStatements = function registrationStatements(index) { var registrations = _logic.solidLogicSingleton.getRegistrations(instance, theClass); var reg = registrations.length ? registrations[0] : widgets.newThing(index); return [(0, _rdflib.st)(reg, ns.solid('instance'), instance, index), (0, _rdflib.st)(reg, ns.solid('forClass'), theClass, index)]; }; var index, statements; if (context.index && context.index["public"] && context.index["public"].length > 0) { index = context.index["public"][0]; statements = registrationStatements(index); tbody.children[0].appendChild(widgets.buildCheckBoxForm(context.dom, _logic.solidLogicSingleton.store, "Public link to this ".concat(context.noun), null, statements, form, index)); } if (context.index && context.index["private"] && context.index["private"].length > 0) { index = context.index["private"][0]; statements = registrationStatements(index); tbody.children[1].appendChild(widgets.buildCheckBoxForm(context.dom, _logic.solidLogicSingleton.store, "Personal note of this ".concat(context.noun), null, statements, form, index)); } return context; }, function (e) { var msg; if (context.div && context.preferencesFileError) { msg = '(Preferences not available)'; context.div.appendChild(dom.createElement('p')).textContent = msg; } else if (context.div) { msg = "registrationControl: Type indexes not available: ".concat(e); context.div.appendChild(widgets.errorMessageBlock(context.dom, e)); } debug.log(msg); })["catch"](function (e) { var msg = "registrationControl: Error making panel: ".concat(e); if (context.div) { context.div.appendChild(widgets.errorMessageBlock(context.dom, e)); } debug.log(msg); }); } /** * UI to List at all registered things */ function registrationList(context, options) { var dom = context.dom; var div = context.div; var box = dom.createElement('div'); div.appendChild(box); return ensureTypeIndexes(context).then(function (_indexes) { box.innerHTML = '<table><tbody></tbody></table>'; // tbody will be inserted anyway box.setAttribute('style', 'font-size: 120%; text-align: right; padding: 1em; border: solid #eee 0.5em;'); var table = box.firstChild; var ix = []; var sts = []; var vs = ['private', 'public']; vs.forEach(function (visibility) { if (context.index && options[visibility]) { ix = ix.concat(context.index[visibility][0]); sts = sts.concat(_logic.solidLogicSingleton.store.statementsMatching(undefined, ns.solid('instance'), undefined, context.index[visibility][0])); } }); var _loop = function _loop(i) { var statement = sts[i]; if (options.type) { // now check terms:forClass if (!_logic.solidLogicSingleton.store.holds(statement.subject, ns.solid('forClass'), options.type, statement.why)) { return "continue"; // skip irrelevant ones } } // const cla = statement.subject var inst = statement.object; table.appendChild(widgets.personTR(dom, ns.solid('instance'), inst, { deleteFunction: function deleteFunction(_x) { if (!_logic.solidLogicSingleton.store.updater) { throw new Error('Cannot delete this, store has no updater'); } _logic.solidLogicSingleton.store.updater.update([statement], [], function (uri, ok, errorBody) { if (ok) { debug.log("Removed from index: ".concat(statement.subject)); } else { debug.log("Error: Cannot delete ".concat(statement, ": ").concat(errorBody)); } }); } })); }; for (var i = 0; i < sts.length; i++) { var _ret = _loop(i); if (_ret === "continue") continue; } // registrationList /* //const containers = solidLogicSingleton.store.each(theClass, ns.solid('instanceContainer')); if (containers.length) { fetcher.load(containers).then(function(xhrs){ for (const i=0; i<containers.length; i++) { const cont = containers[i]; instances = instances.concat(solidLogicSingleton.store.each(cont, ns.ldp('contains'))); } }); } */ return context; }); } /** * Simple Access Control * * This function sets up a simple default ACL for a resource, with * RWC for the owner, and a specified access (default none) for the public. * In all cases owner has read write control. * Parameter lists modes allowed to public * * @param options * @param options.public eg ['Read', 'Write'] * * @returns Resolves with aclDoc uri on successful write */ function setACLUserPublic(docURI, me, options) { var aclDoc = _logic.solidLogicSingleton.store.any(_logic.solidLogicSingleton.store.sym(docURI), _solidLogic.ACL_LINK); return Promise.resolve().then(function () { if (aclDoc) { return aclDoc; } return fetchACLRel(docURI)["catch"](function (err) { throw new Error("Error fetching rel=ACL header for ".concat(docURI, ": ").concat(err)); }); }).then(function (aclDoc) { var aclText = genACLText(docURI, me, aclDoc.uri, options); if (!_logic.solidLogicSingleton.store.fetcher) { throw new Error('Cannot PUT this, store has no fetcher'); } return _logic.solidLogicSingleton.store.fetcher.webOperation('PUT', aclDoc.uri, { data: aclText, contentType: 'text/turtle' }).then(function (result) { if (!result.ok) { throw new Error('Error writing ACL text: ' + result.error); } return aclDoc; }); }); } /** * @param docURI * @returns */ function fetchACLRel(docURI) { var fetcher = _logic.solidLogicSingleton.store.fetcher; if (!fetcher) { throw new Error('Cannot fetch ACL rel, store has no fetcher'); } return fetcher.load(docURI).then(function (result) { if (!result.ok) { throw new Error('fetchACLRel: While loading:' + result.error); } var aclDoc = _logic.solidLogicSingleton.store.any(_logic.solidLogicSingleton.store.sym(docURI), _solidLogic.ACL_LINK); if (!aclDoc) { throw new Error('fetchACLRel: No Link rel=ACL header for ' + docURI); } return aclDoc; }); } /** * @param docURI * @param me * @param aclURI * @param options * * @returns Serialized ACL */ function genACLText(docURI, me, aclURI) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var optPublic = options["public"] || []; var g = (0, _rdflib.graph)(); var auth = (0, _rdflib.Namespace)('http://www.w3.org/ns/auth/acl#'); var a = g.sym("".concat(aclURI, "#a1")); var acl = g.sym(aclURI); var doc = g.sym(docURI); g.add(a, ns.rdf('type'), auth('Authorization'), acl); g.add(a, auth('accessTo'), doc, acl); if (options.defaultForNew) { // TODO: Should this be auth('default') instead? g.add(a, auth('defaultForNew'), doc, acl); } g.add(a, auth('agent'), me, acl); g.add(a, auth('mode'), auth('Read'), acl); g.add(a, auth('mode'), auth('Write'), acl); g.add(a, auth('mode'), auth('Control'), acl); if (optPublic.length) { a = g.sym("".concat(aclURI, "#a2")); g.add(a, ns.rdf('type'), auth('Authorization'), acl); g.add(a, auth('accessTo'), doc, acl); g.add(a, auth('agentClass'), ns.foaf('Agent'), acl); for (var p = 0; p < optPublic.length; p++) { g.add(a, auth('mode'), auth(optPublic[p]), acl); // Like 'Read' etc } } return (0, _rdflib.serialize)(acl, g, aclURI); } /** * Returns `sym($SolidTestEnvironment.username)` if * `$SolidTestEnvironment.username` is defined as a global * @returns {NamedNode|null} */ function offlineTestID() { var _window = window, $SolidTestEnvironment = _window.$SolidTestEnvironment; if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.username) { // Test setup debug.log('Assuming the user is ' + $SolidTestEnvironment.username); return (0, _rdflib.sym)($SolidTestEnvironment.username); } if (typeof document !== 'undefined' && document.location && ('' + document.location).slice(0, 16) === 'http://localhost') { var div = document.getElementById('appTarget'); if (!div) return null; var id = div.getAttribute('testID'); if (!id) return null; /* me = solidLogicSingleton.store.any(subject, ns.acl('owner')); // when testing on plane with no WebID */ debug.log('Assuming user is ' + id); return (0, _rdflib.sym)(id); } return null; } function getDefaultSignInButtonStyle() { return 'padding: 1em; border-radius:0.5em; margin: 2em; font-size: 100%;'; } /** * Bootstrapping identity * (Called by `loginStatusBox()`) * * @param dom * @param setUserCallback * * @returns */ function signInOrSignUpBox(dom, setUserCallback) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; options = options || {}; var signInButtonStyle = options.buttonStyle || getDefaultSignInButtonStyle(); // @@ TODO Remove the need to cast HTML element to any var box = dom.createElement('div'); var magicClassName = 'SolidSignInOrSignUpBox'; debug.log('widgets.signInOrSignUpBox'); box.setUserCallback = setUserCallback; box.setAttribute('class', magicClassName); box.style = 'display:flex;'; // @@ fix all typecasts like this // Sign in button with PopUP var signInPopUpButton = dom.createElement('input'); // multi box.appendChild(signInPopUpButton); signInPopUpButton.setAttribute('type', 'button'); signInPopUpButton.setAttribute('value', 'Log in'); signInPopUpButton.setAttribute('style', "".concat(signInButtonStyle, "background-color: #eef;")); signInPopUpButton.addEventListener('click', function () { var offline = offlineTestID(); if (offline) return setUserCallback(offline.uri); return _solidAuthClient["default"].popupLogin().then(function (session) { var webIdURI = session.webId; // setUserCallback(webIdURI) var divs = dom.getElementsByClassName(magicClassName); debug.log("Logged in, ".concat(divs.length, " panels to be serviced")); // At the same time, satisfy all the other login boxes for (var i = 0; i < divs.length; i++) { var div = divs[i]; // @@ TODO Remove the need to manipulate HTML elements if (div.setUserCallback) { try { div.setUserCallback(webIdURI); var parent = div.parentNode; if (parent) { parent.removeChild(div); } } catch (e) { debug.log("## Error satisfying login box: ".concat(e)); div.appendChild(widgets.errorMessageBlock(dom, e)); } } } }); }, false); // Sign up button var signupButton = dom.createElement('input'); box.appendChild(signupButton); signupButton.setAttribute('type', 'button'); signupButton.setAttribute('value', 'Sign Up for Solid'); signupButton.setAttribute('style', "".concat(signInButtonStyle, "background-color: #efe;")); signupButton.addEventListener('click', function (_event) { var signupMgr = new _signup.Signup(); signupMgr.signup().then(function (uri) { debug.log('signInOrSignUpBox signed up ' + uri); setUserCallback(uri); }); }, false); return box; } /** * @returns {Promise<string|null>} Resolves with WebID URI or null */ function webIdFromSession(session) { var webId = session ? session.webId : null; if (webId) { saveUser(webId); } return webId; } /** * @returns {Promise<string|null>} Resolves with WebID URI or null */ /* function checkCurrentUser () { return checkUser() } */ /** * Retrieves currently logged in webId from either * defaultTestUser or SolidAuthClient * @param [setUserCallback] Optional callback * * @returns Resolves with webId uri, if no callback provided */ function checkUser(setUserCallback) { // Check to see if already logged in / have the WebID var me = defaultTestUser(); if (me) { return Promise.resolve(setUserCallback ? setUserCallback(me) : me); } // doc = solidLogicSingleton.store.any(doc, ns.link('userMirror')) || doc return _solidAuthClient["default"].currentSession().then(webIdFromSession)["catch"](function (err) { debug.log('Error fetching currentSession:', err); }).then(function (webId) { // if (webId.startsWith('dns:')) { // legacy rww.io pseudo-users // webId = null // } var me = saveUser(webId); if (me) { debug.log("(Logged in as ".concat(me, " by authentication)")); } return setUserCallback ? setUserCallback(me) : me; }); } /** * Login status box * * A big sign-up/sign in box or a logout box depending on the state * * @param dom * @param listener * * @returns */ function loginStatusBox(dom) { var listener = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; // 20190630 var me = defaultTestUser(); // @@ TODO Remove the need to cast HTML element to any var box = dom.createElement('div'); function setIt(newidURI) { if (!newidURI) { return; } var uri = newidURI.uri || newidURI; // UI.preferences.set('me', uri) me = (0, _rdflib.sym)(uri); box.refresh(); if (listener) listener(me.uri); } function logoutButtonHandler(_event) { // UI.preferences.set('me', '') _solidAuthClient["default"].logout().then(function () { var message = "Your WebID was ".concat(me, ". It has been forgotten."); me = null; try { (0, _log.alert)(message); } catch (e) { window.alert(message); } box.refresh(); if (listener) listener(null); }, function (err) { (0, _log.alert)('Fail to log out:' + err); }); } function logoutButton(me, options) { var signInButtonStyle = options.buttonStyle || getDefaultSignInButtonStyle(); var logoutLabel = 'WebID logout'; if (me) { var nick = _logic.solidLogicSingleton.store.any(me, ns.foaf('nick')) || _logic.solidLogicSingleton.store.any(me, ns.foaf('name')); if (nick) { logoutLabel = 'Logout ' + nick.value; } } var signOutButton = dom.createElement('input'); // signOutButton.className = 'WebIDCancelButton' signOutButton.setAttribute('type', 'button'); signOutButton.setAttribute('value', logoutLabel); signOutButton.setAttribute('style', "".concat(signInButtonStyle, "background-color: #eee;")); signOutButton.addEventListener('click', logoutButtonHandler, false); return signOutButton; } box.refresh = function () { _solidAuthClient["default"].currentSession().then(function (session) { if (session && session.webId) { // offline me = (0, _rdflib.sym)(session.webId); } else { me = offlineTestID(); // null unless testing } if (me && box.me !== me.uri || !me && box.me) { widgets.clearElement(box); if (me) { box.appendChild(logoutButton(me, options)); } else { box.appendChild(signInOrSignUpBox(dom, setIt, options)); } } box.me = me ? me.uri : null; }, function (err) { (0, _log.alert)("loginStatusBox: ".concat(err)); }); }; if (_solidAuthClient["default"].trackSession) { _solidAuthClient["default"].trackSession(function (session) { if (session && session.webId) { me = (0, _rdflib.sym)(session.webId); } else { me = null; } box.refresh(); }); } box.me = '99999'; // Force refresh box.refresh(); return box; } /** * Workspace selection etc * See https://github.com/solid/userguide/issues/16 */ /** * Returns a UI object which, if it selects a workspace, * will callback(workspace, newBase). * See https://github.com/solid/userguide/issues/16 for more info on workspaces. * * If necessary, will get an account, preference file, etc. In sequence: * * - If not logged in, log in. * - Load preference file * - Prompt user for workspaces * - Allows the user to just type in a URI by hand * * Calls back with the workspace and the base URI * * @param dom * @param appDetails