diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..a65b41774 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +lib diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..f51aa813a --- /dev/null +++ b/.eslintrc @@ -0,0 +1,29 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true + }, + "extends": "standard", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "no-unused-vars": ["warn", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + }], + "@typescript-eslint/no-unused-vars": ["warn", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + }] + } +} diff --git a/.travis.yml b/.travis.yml index d0f8b376f..ed4d0b585 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ deploy: provider: npm # Do not throw away the updated package.json we generated in `before_deploy`: skip_cleanup: true - email: "$NPM_EMAIL" - api_key: "$NPM_TOKEN" + email: '$NPM_EMAIL' + api_key: '$NPM_TOKEN' # Note: do not deploy on pull request, because $TRAVIS_BRANCH will be the target branch. - tag: "$TRAVIS_BRANCH" + tag: '$TRAVIS_BRANCH' on: all_branches: true diff --git a/package-lock.json b/package-lock.json index 107a52887..abc137f06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2126,6 +2126,41 @@ } } }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, "@solid/cli": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@solid/cli/-/cli-0.1.1.tgz", @@ -2204,35 +2239,168 @@ "text-encoding": "^0.6.1" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.12.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.6.tgz", + "integrity": "sha512-FjsYUPzEJdGXjwKqSpE0/9QEh6kzhTAeObA54rn6j3rR4C/mzpI9L0KNfoeASSPMMdxIsoJuCLDWcM/rVjIsSA==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, "@types/rdflib": { "version": "0.20.1", "resolved": "https://registry.npmjs.org/@types/rdflib/-/rdflib-0.20.1.tgz", "integrity": "sha512-Lrsjxe5b+uhhsskwIbNJPGiOndI1UeZbAgrwnomSqqiR1ImrhWKUctkEZUu5aWJr+thBk5LADoFLYrX21dTSTQ==", "dev": true }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true + "@typescript-eslint/eslint-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.6.1.tgz", + "integrity": "sha512-Z0rddsGqioKbvqfohg7BwkFC3PuNLsB+GE9QkFza7tiDzuHoy0y823Y+oGNDzxNZrYyLjqkZtCTl4vCqOmEN4g==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.6.1", + "eslint-utils": "^1.4.2", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "tsutils": "^3.17.1" + } }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "@typescript-eslint/experimental-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.6.1.tgz", + "integrity": "sha512-EVrrUhl5yBt7fC7c62lWmriq4MIc49zpN3JmrKqfiFXPXCM5ErfEcZYfKOhZXkW6MBjFcJ5kGZqu1b+lyyExUw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.6.1", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.6.1.tgz", + "integrity": "sha512-PDPkUkZ4c7yA+FWqigjwf3ngPUgoLaGjMlFh6TRtbjhqxFBnkElDfckSjm98q9cMr4xRzZ15VrS/xKm6QHYf0w==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.6.1", + "@typescript-eslint/typescript-estree": "2.6.1", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.6.1.tgz", + "integrity": "sha512-+sTnssW6bcbDZKE8Ce7VV6LdzkQz2Bxk7jzk1J8H1rovoTxnm6iXvYIyncvNsaB/kBCOM63j/LNJfm27bNdUoA==", "dev": true, "requires": { - "acorn": "^3.0.4" + "debug": "^4.1.1", + "glob": "^7.1.4", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" }, "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", @@ -2244,16 +2412,10 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", - "dev": true - }, "ansi-escapes": { - "version": "1.4.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { @@ -2268,6 +2430,12 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2291,16 +2459,40 @@ "dev": true, "optional": true }, - "array.prototype.find": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", - "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "array-differ": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-2.1.0.tgz", + "integrity": "sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w==", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.7.0" } }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -2331,6 +2523,12 @@ "dev": true, "optional": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", @@ -2370,17 +2568,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", @@ -2505,6 +2692,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -2515,12 +2711,6 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -2548,21 +2738,23 @@ } } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "dev": true, "requires": { - "callsites": "^0.2.0" + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } } }, - "callsites": { - "version": "0.2.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, "canonicalize": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.1.tgz", @@ -2586,10 +2778,16 @@ "supports-color": "^2.0.0" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "class-utils": { @@ -2624,13 +2822,29 @@ } } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", "dev": true, "requires": { - "restore-cursor": "^1.0.1" + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" } }, "cli-width": { @@ -2639,12 +2853,6 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -2703,18 +2911,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", @@ -2783,13 +2979,29 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "d": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "es5-ext": "^0.10.9" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "dashdash": { @@ -2800,6 +3012,12 @@ "assert-plus": "^1.0.0" } }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2811,7 +3029,7 @@ }, "debug-log": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, @@ -2822,6 +3040,12 @@ "dev": true, "optional": true }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -2897,17 +3121,58 @@ } }, "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-4.0.1.tgz", + "integrity": "sha512-/g+RDZ7yf2HvoW+E5Cy+K94YhgcFgr6C8LuHZD1O5HoNPkf3KY6RfXJ0DBGlB/NkLi5gml+G9zqRzk9S0mHZCg==", "dev": true, "requires": { "find-root": "^1.0.0", "glob": "^7.0.5", - "ignore": "^3.0.9", + "ignore": "^5.0.0", "pkg-config": "^1.1.0", "run-parallel": "^1.1.2", "uniq": "^1.0.1" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + } + } + }, + "del": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", + "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "dev": true, + "requires": { + "globby": "^10.0.1", + "graceful-fs": "^4.2.2", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.1", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "delayed-stream": { @@ -2915,10 +3180,25 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -2933,6 +3213,12 @@ "safer-buffer": "^2.1.0" } }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "elliptic": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", @@ -2947,6 +3233,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", @@ -2955,6 +3247,15 @@ "iconv-lite": "~0.4.13" } }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2965,16 +3266,29 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "es-to-primitive": { @@ -2988,77 +3302,6 @@ "is-symbol": "^1.0.2" } }, - "es5-ext": { - "version": "0.10.46", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", - "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "1" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3070,201 +3313,344 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true, - "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, "eslint": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", - "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz", + "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==", "dev": true, "requires": { - "babel-code-frame": "^6.16.0", - "chalk": "^1.1.3", - "concat-stream": "^1.5.2", - "debug": "^2.1.1", - "doctrine": "^2.0.0", - "escope": "^3.6.0", - "espree": "^3.4.0", - "esquery": "^1.0.0", - "estraverse": "^4.2.0", + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "esquery": "^1.0.1", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "glob": "^7.0.3", - "globals": "^9.14.0", - "ignore": "^3.2.0", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^0.12.0", - "is-my-json-valid": "^2.10.0", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.5.1", - "json-stable-stringify": "^1.0.0", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.0.0", - "mkdirp": "^0.5.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.1", - "pluralize": "^1.2.1", - "progress": "^1.1.8", - "require-uncached": "^1.0.2", - "shelljs": "^0.7.5", - "strip-bom": "^3.0.0", - "strip-json-comments": "~2.0.1", - "table": "^3.7.8", - "text-table": "~0.2.0", - "user-home": "^2.0.0" + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "os-homedir": "^1.0.0" + "color-convert": "^1.9.0" } - } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz", + "integrity": "sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==", "dev": true }, "eslint-config-standard-jsx": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz", - "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-8.1.0.tgz", + "integrity": "sha512-ULVC8qH8qCqbU792ZOO6DaiaZyHNS/5CZt3hKqHkEhVlhPEPN3nfBqqxJCyp59XrjIBZPu1chMYe9T2DXZ7TMw==", "dev": true }, "eslint-import-resolver-node": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", - "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "dev": true, "requires": { - "debug": "^2.2.0", - "object-assign": "^4.0.1", - "resolve": "^1.1.6" + "debug": "^2.6.9", + "resolve": "^1.5.0" } }, "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", "dev": true, "requires": { "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", + "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", + "dev": true, + "requires": { + "eslint-utils": "^1.4.2", + "regexpp": "^3.0.0" + }, + "dependencies": { + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } } }, "eslint-plugin-import": { - "version": "2.2.0", - "resolved": "http://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", - "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=", + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", "dev": true, "requires": { - "builtin-modules": "^1.1.1", + "array-includes": "^3.0.3", "contains-path": "^0.1.0", - "debug": "^2.2.0", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.2.0", - "eslint-module-utils": "^2.0.0", - "has": "^1.0.1", - "lodash.cond": "^4.3.0", - "minimatch": "^3.0.3", - "pkg-up": "^1.0.0" + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" }, "dependencies": { "doctrine": { "version": "1.5.0", - "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { "esutils": "^2.0.2", "isarray": "^1.0.0" } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } } } }, "eslint-plugin-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", - "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", + "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", "dev": true, "requires": { - "ignore": "^3.0.11", - "minimatch": "^3.0.2", - "object-assign": "^4.0.1", - "resolve": "^1.1.7", - "semver": "5.3.0" + "eslint-plugin-es": "^2.0.0", + "eslint-utils": "^1.4.2", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "semver": { - "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "eslint-plugin-promise": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", - "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", "dev": true }, "eslint-plugin-react": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", - "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", - "dev": true, - "requires": { - "array.prototype.find": "^2.0.1", - "doctrine": "^1.2.2", - "has": "^1.0.1", - "jsx-ast-utils": "^1.3.4", - "object.assign": "^4.0.4" + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", + "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.1.0", + "object.entries": "^1.1.0", + "object.fromentries": "^2.0.0", + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "resolve": "^1.10.1" }, "dependencies": { "doctrine": { - "version": "1.5.0", - "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" } } } }, "eslint-plugin-standard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", - "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", + "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", + "dev": true + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "3.5.4", - "resolved": "http://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" } }, "esprima": { @@ -3303,22 +3689,21 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3347,6 +3732,17 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -3357,6 +3753,19 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, + "fast-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz", + "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2" + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -3368,6 +3777,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -3379,13 +3797,32 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + }, + "dependencies": { + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } } }, "find-root": { @@ -3395,27 +3832,31 @@ "dev": true }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^2.0.0" } }, "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" } }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3483,30 +3924,33 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "requires": { - "is-property": "^1.0.2" - } + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } + "get-own-enumerable-property-symbols": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", + "dev": true }, "get-stdin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", - "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", "dev": true }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -3536,12 +3980,45 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + } + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -3676,6 +4153,12 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3686,6 +4169,120 @@ "sshpk": "^1.7.0" } }, + "husky": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz", + "integrity": "sha512-Yolhupm7le2/MqC1VYLk/cNmYxsSsqKkTyBhzQHhPK1jFnC89mmmNVuGtLNabjDI6Aj8UNIr0KpRNuBkiC4+sg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "ci-info": "^2.0.0", + "cosmiconfig": "^5.2.1", + "execa": "^1.0.0", + "get-stdin": "^7.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.2.0", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3700,12 +4297,45 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3722,32 +4352,116 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "inquirer": { - "version": "0.12.0", - "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { - "ansi-escapes": "^1.1.0", - "ansi-regex": "^2.0.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "readline2": "^1.0.1", - "run-async": "^0.1.0", - "rx-lite": "^3.1.2", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true - }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -3833,6 +4547,12 @@ } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -3840,6 +4560,12 @@ "dev": true, "optional": true }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -3849,25 +4575,48 @@ "number-is-nan": "^1.0.0" } }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-my-json-valid": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", - "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", "dev": true, "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" + "symbol-observable": "^1.1.0" } }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true + }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -3893,10 +4642,10 @@ } } }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, "is-regex": { @@ -3908,10 +4657,10 @@ "has": "^1.0.1" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, "is-stream": { @@ -3946,6 +4695,12 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "isomorphic-fetch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", @@ -4014,14 +4769,11 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stable-stringify": { + "json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", @@ -4036,12 +4788,6 @@ "graceful-fs": "^4.1.6" } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "jsonld": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-1.8.0.tgz", @@ -4061,12 +4807,6 @@ } } }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4079,10 +4819,14 @@ } }, "jsx-ast-utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", - "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", - "dev": true + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", + "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" + } }, "kind-of": { "version": "3.2.2", @@ -4104,52 +4848,474 @@ "type-check": "~0.3.2" } }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "lint-staged": { + "version": "10.0.0-1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.0-1.tgz", + "integrity": "sha512-9aGMF56huVzVksN/sFiP9VLBJY78QbZ1F+CxItH2kMBQq+8aa7OCiux0qUtzhG3vqC3m+fBSzVzyj1gxrHnmHA==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "commander": "^2.20.0", + "cosmiconfig": "^5.2.1", + "debug": "^4.1.1", + "dedent": "^0.7.0", + "del": "^5.0.0", + "execa": "^2.0.3", + "listr": "^0.14.3", + "log-symbols": "^3.0.0", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "stringify-object": "^3.3.0" }, "dependencies": { - "path-exists": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "execa": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true + }, + "path-key": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", + "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", + "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, - "lodash.cond": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", - "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", - "dev": true - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + } + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4176,6 +5342,28 @@ "object-visit": "^1.0.0" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", @@ -4189,6 +5377,12 @@ "mime-db": "1.40.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -4246,16 +5440,45 @@ "minimist": "0.0.8" } }, + "mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "multimatch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-3.0.0.tgz", + "integrity": "sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA==", + "dev": true, + "requires": { + "array-differ": "^2.0.3", + "array-union": "^1.0.2", + "arrify": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + } + } + }, "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "n3": { @@ -4312,10 +5535,10 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "next-tick": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-fetch": { @@ -4357,6 +5580,44 @@ "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -4398,6 +5659,12 @@ } } }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", @@ -4435,6 +5702,30 @@ "object-keys": "^1.0.11" } }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz", + "integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.15.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -4454,6 +5745,18 @@ } } }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4464,29 +5767,52 @@ } }, "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "wordwrap": "~1.0.0" } }, - "os-homedir": { + "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { @@ -4507,12 +5833,38 @@ "p-limit": "^1.1.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -4538,13 +5890,10 @@ "optional": true }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -4552,10 +5901,10 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-parse": { @@ -4564,15 +5913,27 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", + "dev": true + }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { @@ -4591,23 +5952,82 @@ } }, "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", "dev": true, "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" }, "dependencies": { "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "p-try": "^2.0.0" } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true } } }, @@ -4623,40 +6043,646 @@ } }, "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^1.0.0" + "find-up": "^2.1.0" } }, - "pkg-up": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", - "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, "requires": { - "find-up": "^1.0.0" + "semver-compare": "^1.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "optional": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prettier-standard": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-standard/-/prettier-standard-15.0.1.tgz", + "integrity": "sha512-uT/+SeoioaGh1+pyY28P5mYJTlhzdPRScYJ1SlrhLwuB6ejP06h1SaBpCLae35zoIP7Tf4YM/px8b3bClWwVrg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "diff": "^4.0.1", + "eslint": "^6.4.0", + "execa": "^2.0.4", + "find-up": "^4.1.0", + "get-stdin": "^7.0.0", + "globby": "^6.1.0", + "ignore": "^3.3.7", + "lint-staged": "9.4.0", + "mri": "^1.1.4", + "multimatch": "^3.0.0", + "prettierx": "0.7.1" + }, + "dependencies": { + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "dev": true, + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz", + "integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "execa": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + } + } + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inquirer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "lint-staged": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.0.tgz", + "integrity": "sha512-jTu1KoGiGTSffM539wK+3igVqDGVsby3KwDBaXL471YndahkjnavLX+R5Nsk49JwklyMo0ZAXay1BaoyA6d2Jw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "commander": "^2.20.0", + "cosmiconfig": "^5.2.1", + "debug": "^4.1.1", + "dedent": "^0.7.0", + "del": "^5.0.0", + "execa": "^2.0.3", + "listr": "^0.14.3", + "log-symbols": "^3.0.0", + "micromatch": "^4.0.2", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "string-argv": "^0.3.0", + "stringify-object": "^3.3.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", + "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "dev": true + }, + "which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", + "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } } }, - "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "optional": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "prettierx": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/prettierx/-/prettierx-0.7.1.tgz", + "integrity": "sha512-6snEPDLZ3iyfoX+DCsQzeFBpi8PDqSfq77Pt9e0H2R/jTG2FJfq/bjYlUqmdonLHEcIgKdHemm7pk/4ydLwcgw==", "dev": true }, "private": { @@ -4669,19 +6695,41 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "dev": true, + "optional": true }, "progress": { - "version": "1.1.8", - "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "psl": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -4715,11 +6763,76 @@ "xmldom": "^0.1.27" } }, + "react-is": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz", + "integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + } + } + }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5044,26 +7157,6 @@ } } }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "mute-stream": "0.0.5" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -5095,6 +7188,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -5150,16 +7249,6 @@ } } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -5170,9 +7259,9 @@ } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { @@ -5183,13 +7272,13 @@ "optional": true }, "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "ret": { @@ -5199,35 +7288,50 @@ "dev": true, "optional": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "once": "^1.3.0" + "is-promise": "^2.1.0" } }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, - "rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", - "dev": true + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } }, "safe-buffer": { "version": "5.1.2", @@ -5254,6 +7358,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -5279,17 +7389,33 @@ } } }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "shebang-regex": "^1.0.0" } }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "slice-ansi": { "version": "0.0.4", "resolved": "http://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", @@ -5526,6 +7652,38 @@ "dev": true, "optional": true }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -5559,37 +7717,37 @@ } }, "standard": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz", - "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==", + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/standard/-/standard-14.3.1.tgz", + "integrity": "sha512-TUQwU7znlZLfgKH1Zwn/D84FitWZkUTfbxSiz/vFx+4c9GV+clSfG/qLiLZOlcdyzhw3oF5/pZydNjbNDfHPEw==", "dev": true, "requires": { - "eslint": "~3.19.0", - "eslint-config-standard": "10.2.1", - "eslint-config-standard-jsx": "4.0.2", - "eslint-plugin-import": "~2.2.0", - "eslint-plugin-node": "~4.2.2", - "eslint-plugin-promise": "~3.5.0", - "eslint-plugin-react": "~6.10.0", - "eslint-plugin-standard": "~3.0.1", - "standard-engine": "~7.0.0" + "eslint": "~6.4.0", + "eslint-config-standard": "14.1.0", + "eslint-config-standard-jsx": "8.1.0", + "eslint-plugin-import": "~2.18.0", + "eslint-plugin-node": "~10.0.0", + "eslint-plugin-promise": "~4.2.1", + "eslint-plugin-react": "~7.14.2", + "eslint-plugin-standard": "~4.0.0", + "standard-engine": "^12.0.0" } }, "standard-engine": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", - "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-12.0.0.tgz", + "integrity": "sha512-gJIIRb0LpL7AHyGbN9+hJ4UJns37lxmNTnMGRLC8CFrzQ+oB/K60IQjKNgPBCB2VP60Ypm6f8DFXvhVWdBOO+g==", "dev": true, "requires": { - "deglob": "^2.1.0", - "get-stdin": "^5.0.1", + "deglob": "^4.0.0", + "get-stdin": "^7.0.0", "minimist": "^1.1.0", - "pkg-conf": "^2.0.0" + "pkg-conf": "^3.1.0" }, "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -5631,6 +7789,12 @@ } } }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -5642,6 +7806,26 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -5650,6 +7834,17 @@ "safe-buffer": "~5.1.0" } }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -5665,10 +7860,22 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -5677,34 +7884,43 @@ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "table": { - "version": "3.8.3", - "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^4.7.0", - "ajv-keywords": "^1.0.0", - "chalk": "^1.1.1", - "lodash": "^4.0.0", - "slice-ansi": "0.0.4", - "string-width": "^2.0.0" + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" + "color-convert": "^1.9.0" } }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "is-fullwidth-code-point": { @@ -5713,23 +7929,35 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } @@ -5751,6 +7979,15 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -5821,6 +8058,21 @@ "punycode": "^2.1.0" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5843,6 +8095,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -5991,6 +8249,22 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -6021,12 +8295,64 @@ "webidl-conversions": "^4.0.2" } }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6034,9 +8360,9 @@ "dev": true }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -6048,9 +8374,9 @@ "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true } } diff --git a/package.json b/package.json index 1ad712b35..7f069b2ca 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "build-types": "tsc --emitDeclarationOnly", "postversion": "git push origin master --follow-tags", "prepublishOnly": "npm run build", - "standard": "standard src", - "test": "npm run standard", + "lint": "prettier-standard --lint 'src/**/*.js' 'src/**/*.ts'", + "test": "npm run lint", "watch": "babel src --out-dir lib --watch --source-maps --extensions '.ts,.js'" }, "repository": { @@ -60,16 +60,23 @@ "@babel/preset-env": "^7.6.2", "@babel/preset-typescript": "^7.6.0", "@types/rdflib": "^0.20.1", - "standard": "^10.0.2", + "@typescript-eslint/eslint-plugin": "^2.6.1", + "@typescript-eslint/parser": "^2.6.1", + "husky": "^3.0.9", + "lint-staged": "^10.0.0-1", + "prettier-standard": "^15.0.1", + "standard": "^14.3.1", "typescript": "^3.6.3" }, - "standard": { - "globals": [ - "$rdf", - "tabulator", - "QUnit", - "$SolidTestEnvironment", - "AudioContext" + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*": [ + "prettier-standard --lint", + "git add" ] } } diff --git a/src/acl-control.js b/src/acl-control.js index 6944159d7..e44e5b152 100644 --- a/src/acl-control.js +++ b/src/acl-control.js @@ -1,4 +1,4 @@ -/* global confirm */ +/* global confirm $rdf */ // ///////////////////////////// ACL User Interface // See https://www.coshx.com/blog/2014/04/11/preventing-drag-and-drop-disasters-with-a-chrome-userscript/ @@ -35,11 +35,17 @@ UI.aclControl.preventBrowserDropEvents = function (document) { function handleDrop (e) { if (e.dataTransfer.files.length > 0) { - if (!confirm('Are you sure you want to drop this file here? ' + - '(Cancel opens it in a new tab)')) { + if ( + !confirm( + 'Are you sure you want to drop this file here? ' + + '(Cancel opens it in a new tab)' + ) + ) { e.stopPropagation() e.preventDefault() - console.log('@@@@ document-level DROP suppressed: ' + e.dataTransfer.dropEffect) + console.log( + '@@@@ document-level DROP suppressed: ' + e.dataTransfer.dropEffect + ) } } } @@ -69,7 +75,10 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { table.setAttribute('style', 'margin: 1em; border: 0.1em #ccc ;') var headerRow = table.appendChild(dom.createElement('tr')) headerRow.textContent = 'Sharing for ' + noun + ' ' + UI.utils.label(subject) - headerRow.setAttribute('style', 'min-width: 20em; padding: 1em; font-size: 120%; border-bottom: 0.1em solid red; margin-bottom: 2em;') + headerRow.setAttribute( + 'style', + 'min-width: 20em; padding: 1em; font-size: 120%; border-bottom: 0.1em solid red; margin-bottom: 2em;' + ) var statusRow = table.appendChild(dom.createElement('tr')) @@ -88,7 +97,8 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { // var publicAccessButton = bottomLeftCell.appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_98053.svg', 'Public')) - const bigButtonStyle = 'border-radius: 0.3em; background-color: white; border: 0.1em solid #888;' + const bigButtonStyle = + 'border-radius: 0.3em; background-color: white; border: 0.1em solid #888;' // This is the main function which produces an editable access control. // There are two of these in all iff the defaults are separate @@ -110,8 +120,15 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { return combo } - var colloquial = {13: 'Owners', 9: 'Owners (write locked)', 5: 'Editors', 3: 'Posters', 2: 'Submitters', 1: 'Viewers'} - var recommended = {13: true, 5: true, 3: true, 2: true, 1: true} + var colloquial = { + 13: 'Owners', + 9: 'Owners (write locked)', + 5: 'Editors', + 3: 'Posters', + 2: 'Submitters', + 1: 'Viewers' + } + var recommended = { 13: true, 5: true, 3: true, 2: true, 1: true } var explanation = { 13: 'can read, write, and control sharing.', 9: 'can read and control sharing, currently write-locked.', @@ -121,7 +138,14 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { 1: 'can read but not change information' } - var kToColor = {13: 'purple', 9: 'blue', 5: 'red', 3: 'orange', 2: '#cc0', 1: 'green'} + var kToColor = { + 13: 'purple', + 9: 'blue', + 5: 'red', + 3: 'orange', + 2: '#cc0', + 1: 'green' + } function ktToList (k) { var list = '' @@ -155,34 +179,50 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { console.log(' drop object type includes: ' + ty) } // An Origin URI is one like https://fred.github.io eith no trailing slash - if (uri.startsWith('http') && uri.split('/').length === 3) { // there is no third slash - return {pred: 'origin', obj: obj} // The only way to know an origin alas + if (uri.startsWith('http') && uri.split('/').length === 3) { + // there is no third slash + return { pred: 'origin', obj: obj } // The only way to know an origin alas } // @@ This is an almighty kludge needed because drag and drop adds extra slashes to origins - if (uri.startsWith('http') && uri.split('/').length === 4 && uri.endsWith('/')) { // there IS third slash - console.log('Assuming final slash on dragged origin URI was unintended!') - return {pred: 'origin', obj: $rdf.sym(uri.slice(0, -1))} // Fix a URI where the drag and drop system has added a spurious slash + if ( + uri.startsWith('http') && + uri.split('/').length === 4 && + uri.endsWith('/') + ) { + // there IS third slash + console.log( + 'Assuming final slash on dragged origin URI was unintended!' + ) + return { pred: 'origin', obj: $rdf.sym(uri.slice(0, -1)) } // Fix a URI where the drag and drop system has added a spurious slash } - if (ns.vcard('WebID').uri in types) return {pred: 'agent', obj: obj} + if (ns.vcard('WebID').uri in types) return { pred: 'agent', obj: obj } if (ns.vcard('Group').uri in types) { - return {pred: 'agentGroup', obj: obj} // @@ note vcard membership not RDFs + return { pred: 'agentGroup', obj: obj } // @@ note vcard membership not RDFs } - if (obj.sameTerm(ns.foaf('Agent')) || obj.sameTerm(ns.acl('AuthenticatedAgent')) || // AuthenticatedAgent - obj.sameTerm(ns.rdf('Resource')) || obj.sameTerm(ns.owl('Thing'))) { - return {pred: 'agentClass', obj: obj} + if ( + obj.sameTerm(ns.foaf('Agent')) || + obj.sameTerm(ns.acl('AuthenticatedAgent')) || // AuthenticatedAgent + obj.sameTerm(ns.rdf('Resource')) || + obj.sameTerm(ns.owl('Thing')) + ) { + return { pred: 'agentClass', obj: obj } } - if (ns.vcard('Individual').uri in types || ns.foaf('Person').uri in types || ns.foaf('Agent').uri in types) { + if ( + ns.vcard('Individual').uri in types || + ns.foaf('Person').uri in types || + ns.foaf('Agent').uri in types + ) { var pref = kb.any(obj, ns.foaf('preferredURI')) - if (pref) return {pred: 'agent', obj: $rdf.sym(pref)} - return {pred: 'agent', obj: obj} + if (pref) return { pred: 'agent', obj: $rdf.sym(pref) } + return { pred: 'agent', obj: obj } } if (ns.solid('AppProvider').uri in types) { - return {pred: 'origin', obj: obj} + return { pred: 'origin', obj: obj } } if (ns.solid('AppProviderClass').uri in types) { - return {pred: 'originClass', obj: obj} + return { pred: 'originClass', obj: obj } } console.log(' Triage fails for ' + uri) } @@ -191,15 +231,34 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { var kb2 = $rdf.graph() if (!box.isContainer) { UI.acl.makeACLGraphbyCombo(kb2, doc, box.mainByCombo, aclDoc, true) - } else if (box.defaultsDiffer) { // Pair of controls + } else if (box.defaultsDiffer) { + // Pair of controls UI.acl.makeACLGraphbyCombo(kb2, doc, box.mainByCombo, aclDoc, true) - UI.acl.makeACLGraphbyCombo(kb2, doc, box.defByCombo, aclDoc, false, true) - } else { // Linked controls - UI.acl.makeACLGraphbyCombo(kb2, doc, box.mainByCombo, aclDoc, true, true) + UI.acl.makeACLGraphbyCombo( + kb2, + doc, + box.defByCombo, + aclDoc, + false, + true + ) + } else { + // Linked controls + UI.acl.makeACLGraphbyCombo( + kb2, + doc, + box.mainByCombo, + aclDoc, + true, + true + ) } var updater = kb2.updater || new $rdf.UpdateManager(kb2) - updater.put(aclDoc, kb2.statementsMatching(undefined, undefined, undefined, aclDoc), - 'text/turtle', function (uri, ok, message) { + updater.put( + aclDoc, + kb2.statementsMatching(undefined, undefined, undefined, aclDoc), + 'text/turtle', + function (uri, ok, message) { var error = null if (!ok) { error = 'ACL file save failed: ' + message @@ -211,14 +270,17 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { console.log('ACL modification: success!') } callback(ok, error) - }) + } + ) } function renderCombo (byCombo, combo) { var row = box.appendChild(dom.createElement('tr')) row.combo = combo - row.setAttribute('style', 'color: ' + - (options.modify ? (kToColor[k] || 'black') : '#888') + ';') + row.setAttribute( + 'style', + 'color: ' + (options.modify ? kToColor[k] || 'black' : '#888') + ';' + ) var left = row.appendChild(dom.createElement('td')) @@ -258,7 +320,8 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { } } var tr = middleTable.appendChild( - UI.widgets.personTR(dom, ACL(pred), $rdf.sym(obj), opt)) + UI.widgets.personTR(dom, ACL(pred), $rdf.sym(obj), opt) + ) tr.predObj = [pred.uri, obj.uri] } @@ -274,9 +337,11 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { for (var a = 0; a < arr.length; a++) { var found = false for (i = 0; i < already.length; i++) { - if (already[i].predObj && // skip NoneTR + if ( + already[i].predObj && // skip NoneTR already[i].predObj[0] === arr[a][0] && - already[i].predObj[1] === arr[a][1]) { + already[i].predObj[1] === arr[a][1] + ) { found = true delete already[i].trashme break @@ -317,9 +382,11 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { } function handleManyDroppedURIs (uris) { - Promise.all(uris.map(function (u) { - return handleOneDroppedURI(u) // can add to meetingDoc but must be sync - })).then(function (a) { + Promise.all( + uris.map(function (u) { + return handleOneDroppedURI(u) // can add to meetingDoc but must be sync + }) + ).then(function (a) { saveAndRestoreUI() }) } @@ -331,7 +398,14 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { } removeAgentFromCombos(u) // Combos are mutually distinct byCombo[combo].push([res.pred, res.obj.uri]) - console.log('ACL: setting access to ' + subject + ' by ' + res.pred + ': ' + res.obj) + console.log( + 'ACL: setting access to ' + + subject + + ' by ' + + res.pred + + ': ' + + res.obj + ) } var res = agentTriage(u) // eg 'agent', 'origin', agentClass' @@ -352,7 +426,7 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { } else { setACLCombo() } - }// handleOneDroppedURI + } // handleOneDroppedURI async function addNewUIRI (uri) { await handleOneDroppedURI(uri) @@ -391,130 +465,232 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { ele.removeChild(ele.bar) ele.bar = null } - if (ele.bar) { // toggle + if (ele.bar) { + // toggle return removeBar() } const bar = ele.appendChild(dom.createElement('div')) ele.bar = bar /** Buttons to add different types of theings to have access - */ + */ // Person - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + UI.widgets.iconForClass['vcard:Individual'], 'Add Person', async event => { - removeOthers(event.target) - let name = await UI.widgets.askName(dom, kb, bar, ns.vcard('URI'), ns.vcard('Individual'), 'person') - if (!name) return removeBar() // user cancelled - const domainNameRegexp = /^https?:/i - if (!name.match(domainNameRegexp)) { // @@ enforce in user input live like a form element - return alert('Not a http URI') - } - // @@ check it actually is a person and has an owner who agrees they own it - console.log('Adding to ACL person: ' + name) - await lastRow.addNewURI(name) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + UI.widgets.iconForClass['vcard:Individual'], + 'Add Person', + async event => { + removeOthers(event.target) + const name = await UI.widgets.askName( + dom, + kb, + bar, + ns.vcard('URI'), + ns.vcard('Individual'), + 'person' + ) + if (!name) return removeBar() // user cancelled + const domainNameRegexp = /^https?:/i + if (!name.match(domainNameRegexp)) { + // @@ enforce in user input live like a form element + return alert('Not a http URI') + } + // @@ check it actually is a person and has an owner who agrees they own it + console.log('Adding to ACL person: ' + name) + await lastRow.addNewURI(name) + removeBar() + } + ) + ) // Group - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + UI.widgets.iconForClass['vcard:Group'], 'Add Group', async event => { - removeOthers(event.target) - let name = await UI.widgets.askName(dom, kb, bar, ns.vcard('URI'), ns.vcard('Group'), 'group') - if (!name) return removeBar() // user cancelled - const domainNameRegexp = /^https?:/i - if (!name.match(domainNameRegexp)) { // @@ enforce in user input live like a form element - return alert('Not a http URI') - } - // @@ check it actually is a group and has an owner who agrees they own it - console.log('Adding to ACL group: ' + name) - await lastRow.addNewURI(name) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + UI.widgets.iconForClass['vcard:Group'], + 'Add Group', + async event => { + removeOthers(event.target) + const name = await UI.widgets.askName( + dom, + kb, + bar, + ns.vcard('URI'), + ns.vcard('Group'), + 'group' + ) + if (!name) return removeBar() // user cancelled + const domainNameRegexp = /^https?:/i + if (!name.match(domainNameRegexp)) { + // @@ enforce in user input live like a form element + return alert('Not a http URI') + } + // @@ check it actually is a group and has an owner who agrees they own it + console.log('Adding to ACL group: ' + name) + await lastRow.addNewURI(name) + removeBar() + } + ) + ) // General public - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + UI.widgets.iconForClass['foaf:Agent'], 'Add Everyone', async event => { - statusBlock.textContent = 'Adding the general public to those who can read. Drag the globe to a different level to give them more access.' - await lastRow.addNewURI(ns.foaf('Agent').uri) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + UI.widgets.iconForClass['foaf:Agent'], + 'Add Everyone', + async event => { + statusBlock.textContent = + 'Adding the general public to those who can read. Drag the globe to a different level to give them more access.' + await lastRow.addNewURI(ns.foaf('Agent').uri) + removeBar() + } + ) + ) // AuthenticatedAgent - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_99101.svg', 'Anyone logged In', async event => { - statusBlock.textContent = 'Adding the anyone logged in to those who can read. Drag the ID icon to a different level to give them more access.' - await lastRow.addNewURI(ns.acl('AuthenticatedAgent').uri) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_99101.svg', + 'Anyone logged In', + async event => { + statusBlock.textContent = + 'Adding the anyone logged in to those who can read. Drag the ID icon to a different level to give them more access.' + await lastRow.addNewURI(ns.acl('AuthenticatedAgent').uri) + removeBar() + } + ) + ) // Bots - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_Robot_849764.svg', 'A Software Agent (bot)', async event => { - removeOthers(event.target) - let name = await UI.widgets.askName(dom, kb, bar, ns.vcard('URI'), ns.schema('Application'), 'bot') - if (!name) return removeBar() // user cancelled - const domainNameRegexp = /^https?:/i - if (!name.match(domainNameRegexp)) { // @@ enforce in user input live like a form element - return alert('Not a http URI') - } - // @@ check it actually is a bot and has an owner who agrees they own it - console.log('Adding to ACL bot: ' + name) - await lastRow.addNewURI(name) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_Robot_849764.svg', + 'A Software Agent (bot)', + async event => { + removeOthers(event.target) + const name = await UI.widgets.askName( + dom, + kb, + bar, + ns.vcard('URI'), + ns.schema('Application'), + 'bot' + ) + if (!name) return removeBar() // user cancelled + const domainNameRegexp = /^https?:/i + if (!name.match(domainNameRegexp)) { + // @@ enforce in user input live like a form element + return alert('Not a http URI') + } + // @@ check it actually is a bot and has an owner who agrees they own it + console.log('Adding to ACL bot: ' + name) + await lastRow.addNewURI(name) + removeBar() + } + ) + ) // Web Apps - bar.appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_15177.svg', 'A Web App (origin)', async event => { - removeOthers(event.target) - var context = {div: bar, dom} - await UI.authn.logInLoadProfile(context) - var trustedApps = kb.each(context.me, ns.acl('trustedApp')) - var trustedOrigins = trustedApps.flatMap(app => kb.each(app, ns.acl('origin'))) - - bar.appendChild(dom.createElement('p')).textContent = `You have ${trustedOrigins.length} selected web apps.` - var table = bar.appendChild(dom.createElement('table')) - trustedApps.forEach(app => { - const origin = kb.any(app, ns.acl('origin')) - var thingTR = UI.widgets.personTR(dom, ns.acl('origin'), origin, {}) - var innerTable = dom.createElement('table') - var innerRow = innerTable.appendChild(dom.createElement('tr')) - var innerLeft = innerRow.appendChild(dom.createElement('td')) - var innerMiddle = innerRow.appendChild(dom.createElement('td')) - var innerRight = innerRow.appendChild(dom.createElement('td')) - innerLeft.appendChild(thingTR) - innerMiddle.textContent = 'Give access to ' + noun + ' ' + UI.utils.label(subject) + '?' - innerRight.appendChild(UI.widgets.continueButton(dom, async event => { - await lastRow.addNewURI(origin.uri) - })) - table.appendChild(innerTable) - }) - table.style = 'margin: em; background-color: #eee;' - - // Add the Trusted App pane for managing you set of apps - var trustedAppControl = window.panes.trustedApplications.render(context.me, dom, {}) - trustedAppControl.style.borderColor = 'orange' - trustedAppControl.style.borderWidth = '0.1em' - trustedAppControl.style.borderRadius = '1em' - bar.appendChild(trustedAppControl) - const cancel = UI.widgets.cancelButton(dom, () => bar.removeChild(trustedAppControl)) - trustedAppControl.insertBefore(cancel, trustedAppControl.firstChild) - cancel.style.float = 'right' - - let name = await UI.widgets.askName(dom, kb, bar, null, ns.schema('WebApplication'), 'webapp domain') // @@ hack - if (!name) return removeBar() // user cancelled - const domainNameRegexp = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i - // https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch08s15.html - if (!name.match(domainNameRegexp)) { // @@ enforce in user input live like a form element - return alert('Not a domain name') - } - const origin = 'https://' + name - console.log('Adding to ACL origin: ' + origin) - await lastRow.addNewURI(origin) - removeBar() - })) + bar.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_15177.svg', + 'A Web App (origin)', + async event => { + removeOthers(event.target) + var context = { div: bar, dom } + await UI.authn.logInLoadProfile(context) + var trustedApps = kb.each(context.me, ns.acl('trustedApp')) + var trustedOrigins = trustedApps.flatMap(app => + kb.each(app, ns.acl('origin')) + ) + + bar.appendChild(dom.createElement('p')).textContent = `You have ${ + trustedOrigins.length + } selected web apps.` + var table = bar.appendChild(dom.createElement('table')) + trustedApps.forEach(app => { + const origin = kb.any(app, ns.acl('origin')) + var thingTR = UI.widgets.personTR( + dom, + ns.acl('origin'), + origin, + {} + ) + var innerTable = dom.createElement('table') + var innerRow = innerTable.appendChild(dom.createElement('tr')) + var innerLeft = innerRow.appendChild(dom.createElement('td')) + var innerMiddle = innerRow.appendChild(dom.createElement('td')) + var innerRight = innerRow.appendChild(dom.createElement('td')) + innerLeft.appendChild(thingTR) + innerMiddle.textContent = + 'Give access to ' + noun + ' ' + UI.utils.label(subject) + '?' + innerRight.appendChild( + UI.widgets.continueButton(dom, async event => { + await lastRow.addNewURI(origin.uri) + }) + ) + table.appendChild(innerTable) + }) + table.style = 'margin: em; background-color: #eee;' + + // Add the Trusted App pane for managing you set of apps + var trustedAppControl = window.panes.trustedApplications.render( + context.me, + dom, + {} + ) + trustedAppControl.style.borderColor = 'orange' + trustedAppControl.style.borderWidth = '0.1em' + trustedAppControl.style.borderRadius = '1em' + bar.appendChild(trustedAppControl) + const cancel = UI.widgets.cancelButton(dom, () => + bar.removeChild(trustedAppControl) + ) + trustedAppControl.insertBefore(cancel, trustedAppControl.firstChild) + cancel.style.float = 'right' + + const name = await UI.widgets.askName( + dom, + kb, + bar, + null, + ns.schema('WebApplication'), + 'webapp domain' + ) // @@ hack + if (!name) return removeBar() // user cancelled + const domainNameRegexp = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i + // https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch08s15.html + if (!name.match(domainNameRegexp)) { + // @@ enforce in user input live like a form element + return alert('Not a domain name') + } + const origin = 'https://' + name + console.log('Adding to ACL origin: ' + origin) + await lastRow.addNewURI(origin) + removeBar() + } + ) + ) } function renderAddToolBar (box, lastRow) { // const toolRow = box.appendChild(dom.createElement('tr')) - bottomLeftCell.appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_34653_green.svg', 'Add ...', event => { - renderAdditionTool(bottomLeftCell, lastRow) - })) + bottomLeftCell.appendChild( + UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_34653_green.svg', + 'Add ...', + event => { + renderAdditionTool(bottomLeftCell, lastRow) + } + ) + ) } var k, combo, lastRow @@ -534,30 +710,59 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { var renderBox = function () { box.innerHTML = '' - UI.acl.getACLorDefault(doc, function (ok, p2, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc) { + UI.acl.getACLorDefault(doc, function ( + ok, + p2, + targetDoc, + targetACLDoc, + defaultHolder, + defaultACLDoc + ) { var defa = !p2 // @@ Could also set from classes ldp:Container etc etc if (!ok) { - statusBlock.textContent += 'Error reading ' + (defa ? ' default ' : '') + 'ACL.' + - ' status ' + targetDoc + ': ' + targetACLDoc + statusBlock.textContent += + 'Error reading ' + + (defa ? ' default ' : '') + + 'ACL.' + + ' status ' + + targetDoc + + ': ' + + targetACLDoc } else { box.isContainer = targetDoc.uri.slice(-1) === '/' // Give default for all directories if (defa) { - var defaults = kb.each(undefined, ACL('default'), defaultHolder, defaultACLDoc) - .concat(kb.each(undefined, ACL('defaultForNew'), defaultHolder, defaultACLDoc)) + var defaults = kb + .each(undefined, ACL('default'), defaultHolder, defaultACLDoc) + .concat( + kb.each( + undefined, + ACL('defaultForNew'), + defaultHolder, + defaultACLDoc + ) + ) if (!defaults.length) { statusBlock.textContent += ' (No defaults given.)' } else { statusBlock.innerHTML = '' - statusBlock.textContent = 'The sharing for this ' + noun + ' is the default for folder ' + statusBlock.textContent = + 'The sharing for this ' + noun + ' is the default for folder ' var a = statusBlock.appendChild(dom.createElement('a')) a.setAttribute('href', defaultHolder.uri) a.textContent = UI.aclControl.shortNameForFolder(defaultHolder) - var kb2 = UI.acl.adoptACLDefault(doc, targetACLDoc, defaultHolder, defaultACLDoc) - ACLControlEditable(box, doc, targetACLDoc, kb2, {modify: false}) // Add btton to save them as actual + var kb2 = UI.acl.adoptACLDefault( + doc, + targetACLDoc, + defaultHolder, + defaultACLDoc + ) + ACLControlEditable(box, doc, targetACLDoc, kb2, { modify: false }) // Add btton to save them as actual box.style.cssText = 'color: #777;' - var editPlease = bottomRightCell.appendChild(dom.createElement('button')) + var editPlease = bottomRightCell.appendChild( + dom.createElement('button') + ) editPlease.textContent = 'Set specific sharing\nfor this ' + noun editPlease.style.cssText = bigButtonStyle editPlease.addEventListener('click', async function (event) { @@ -565,42 +770,52 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { kb.add(st.subject, st.predicate, st.object, targetACLDoc) }) try { - kb.fetcher.putBack(targetACLDoc) - .then(function () { - statusBlock.textContent = ' (Now editing specific access for this ' + noun + ')' - bottomRightCell.removeChild(editPlease) - renderBox() - }) + kb.fetcher.putBack(targetACLDoc).then(function () { + statusBlock.textContent = + ' (Now editing specific access for this ' + noun + ')' + bottomRightCell.removeChild(editPlease) + renderBox() + }) } catch (e) { - let msg = ' Error writing back access control file! ' + e + const msg = ' Error writing back access control file! ' + e console.error(msg) statusBlock.textContent += msg - return } // kb.fetcher.requested[targetACLDoc.uri] = 'done' // cheat - say cache is now in sync }) } // defaults.length - } else { // Not using defaults + } else { + // Not using defaults var useDefault var addDefaultButton = function (prospectiveDefaultHolder) { - useDefault = bottomRightCell.appendChild(dom.createElement('button')) - useDefault.textContent = 'Stop specific sharing for this ' + noun + - ' -- just use default' // + UI.utils.label(thisDefaultHolder) + useDefault = bottomRightCell.appendChild( + dom.createElement('button') + ) + useDefault.textContent = + 'Stop specific sharing for this ' + noun + ' -- just use default' // + UI.utils.label(thisDefaultHolder) if (prospectiveDefaultHolder) { - useDefault.textContent += ' for ' + UI.utils.label(prospectiveDefaultHolder) + useDefault.textContent += + ' for ' + UI.utils.label(prospectiveDefaultHolder) } useDefault.style.cssText = bigButtonStyle useDefault.addEventListener('click', function (event) { - kb.fetcher.delete(targetACLDoc.uri) + kb.fetcher + .delete(targetACLDoc.uri) .then(function () { - statusBlock.textContent = ' The sharing for this ' + noun + ' is now the default.' + statusBlock.textContent = + ' The sharing for this ' + noun + ' is now the default.' bottomRightCell.removeChild(useDefault) box.style.cssText = 'color: #777;' bottomLeftCell.innerHTML = '' renderBox() }) .catch(function (e) { - statusBlock.textContent += ' (Error deleting access control file: ' + targetACLDoc + ': ' + e + ')' + statusBlock.textContent += + ' (Error deleting access control file: ' + + targetACLDoc + + ': ' + + e + + ')' }) }) } @@ -609,17 +824,30 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { var str = targetDoc.uri.split('#')[0] var p = str.slice(0, -1).lastIndexOf('/') var q = str.indexOf('//') - var targetDocDir = ((q >= 0 && p < q + 2) || p < 0) ? null : str.slice(0, p + 1) + var targetDocDir = + (q >= 0 && p < q + 2) || p < 0 ? null : str.slice(0, p + 1) // @@ TODO: The methods used for targetIsStorage are HACKs - it should not be relied upon, and work is // @@ underway to standardize a behavior that does not rely upon this hack // @@ hopefully fixed as part of https://github.com/solid/data-interoperability-panel/issues/10 - const targetIsStorage = kb.holds(targetDoc, UI.ns.rdf('type'), UI.ns.space('Storage'), targetACLDoc) + const targetIsStorage = kb.holds( + targetDoc, + UI.ns.rdf('type'), + UI.ns.space('Storage'), + targetACLDoc + ) const targetAclIsProtected = hasProtectedAcl(targetDoc) const targetIsProtected = targetIsStorage || targetAclIsProtected if (!targetIsProtected && targetDocDir) { - UI.acl.getACLorDefault($rdf.sym(targetDocDir), function (ok2, p22, targetDoc2, targetACLDoc2, defaultHolder2, defaultACLDoc2) { + UI.acl.getACLorDefault($rdf.sym(targetDocDir), function ( + ok2, + p22, + targetDoc2, + targetACLDoc2, + defaultHolder2, + defaultACLDoc2 + ) { if (ok2) { prospectiveDefaultHolder = p22 ? targetDoc2 : defaultHolder2 } @@ -632,41 +860,66 @@ UI.aclControl.ACLControlBox5 = function (subject, dom, noun, kb, callback) { box.addControlForDefaults = function () { box.notice.textContent = 'Access to things within this folder:' box.notice.style.cssText = 'font-size: 120%; color: black;' - var mergeButton = UI.widgets.clearElement(box.offer).appendChild(dom.createElement('button')) - mergeButton.innerHTML = '

Set default for folder contents to
just track the sharing for the folder

' + var mergeButton = UI.widgets + .clearElement(box.offer) + .appendChild(dom.createElement('button')) + mergeButton.innerHTML = + '

Set default for folder contents to
just track the sharing for the folder

' mergeButton.style.cssText = bigButtonStyle - mergeButton.addEventListener('click', function (e) { - delete box.defaultsDiffer - delete box.defByCombo - box.saveBack(function (ok, error) { - if (ok) { - box.removeControlForDefaults() - } else { - alert(error) - } - }) - }, false) + mergeButton.addEventListener( + 'click', + function (_event) { + delete box.defaultsDiffer + delete box.defByCombo + box.saveBack(function (ok, error) { + if (ok) { + box.removeControlForDefaults() + } else { + alert(error) + } + }) + }, + false + ) box.defaultsDiffer = true - box.defByCombo = ACLControlEditable(box, targetDoc, targetACLDoc, kb, {modify: true, doingDefaults: true}) + box.defByCombo = ACLControlEditable( + box, + targetDoc, + targetACLDoc, + kb, + { modify: true, doingDefaults: true } + ) } box.removeControlForDefaults = function () { - statusBlock.textContent = 'This is also the default for things in this folder.' - box.notice.textContent = 'Sharing for things within the folder currently tracks sharing for the folder.' + statusBlock.textContent = + 'This is also the default for things in this folder.' + box.notice.textContent = + 'Sharing for things within the folder currently tracks sharing for the folder.' box.notice.style.cssText = 'font-size: 80%; color: #888;' - var splitButton = UI.widgets.clearElement(box.offer).appendChild(dom.createElement('button')) - splitButton.innerHTML = '

Set the sharing of folder contents
separately from the sharing for the folder

' + var splitButton = UI.widgets + .clearElement(box.offer) + .appendChild(dom.createElement('button')) + splitButton.innerHTML = + '

Set the sharing of folder contents
separately from the sharing for the folder

' splitButton.style.cssText = bigButtonStyle - splitButton.addEventListener('click', function (e) { + splitButton.addEventListener('click', function (_event) { box.addControlForDefaults() statusBlock.textContent = '' }) while (box.divider.nextSibling) { box.removeChild(box.divider.nextSibling) } - statusBlock.textContent = 'This is now also the default for things in this folder.' + statusBlock.textContent = + 'This is now also the default for things in this folder.' } - box.mainByCombo = ACLControlEditable(box, targetDoc, targetACLDoc, kb, {modify: true}) // yes can edit + box.mainByCombo = ACLControlEditable( + box, + targetDoc, + targetACLDoc, + kb, + { modify: true } + ) // yes can edit box.divider = box.appendChild(dom.createElement('tr')) box.notice = box.divider.appendChild(dom.createElement('td')) box.notice.style.cssText = 'font-size: 80%; color: #888;' diff --git a/src/acl.js b/src/acl.js index 3fc83582e..22280933b 100644 --- a/src/acl.js +++ b/src/acl.js @@ -1,6 +1,7 @@ +/* global $rdf */ // Access control logic -var acl = module.exports = {} +var acl = (module.exports = {}) var UI = { acl: acl, @@ -20,22 +21,40 @@ const kb = UI.store // Take the "defaltForNew" ACL and convert it into the equivlent ACL // which the resource would have had. Return it as a new separate store. -UI.acl.adoptACLDefault = function (doc, aclDoc, defaultResource, defaultACLdoc) { +UI.acl.adoptACLDefault = function ( + doc, + aclDoc, + defaultResource, + defaultACLdoc +) { var kb = UI.store var ACL = UI.ns.acl var isContainer = doc.uri.slice(-1) === '/' // Give default for all directories - var defaults = kb.each(undefined, ACL('default'), defaultResource, defaultACLdoc) - .concat(kb.each(undefined, ACL('defaultForNew'), defaultResource, defaultACLdoc)) + var defaults = kb + .each(undefined, ACL('default'), defaultResource, defaultACLdoc) + .concat( + kb.each(undefined, ACL('defaultForNew'), defaultResource, defaultACLdoc) + ) var proposed = [] defaults.map(function (da) { - proposed = proposed.concat(kb.statementsMatching(da, ACL('agent'), undefined, defaultACLdoc)) - .concat(kb.statementsMatching(da, ACL('agentClass'), undefined, defaultACLdoc)) - .concat(kb.statementsMatching(da, ACL('agentGroup'), undefined, defaultACLdoc)) - .concat(kb.statementsMatching(da, ACL('origin'), undefined, defaultACLdoc)) - .concat(kb.statementsMatching(da, ACL('originClass'), undefined, defaultACLdoc)) + proposed = proposed + .concat(kb.statementsMatching(da, ACL('agent'), undefined, defaultACLdoc)) + .concat( + kb.statementsMatching(da, ACL('agentClass'), undefined, defaultACLdoc) + ) + .concat( + kb.statementsMatching(da, ACL('agentGroup'), undefined, defaultACLdoc) + ) + .concat( + kb.statementsMatching(da, ACL('origin'), undefined, defaultACLdoc) + ) + .concat( + kb.statementsMatching(da, ACL('originClass'), undefined, defaultACLdoc) + ) .concat(kb.statementsMatching(da, ACL('mode'), undefined, defaultACLdoc)) proposed.push($rdf.st(da, ACL('accessTo'), doc, defaultACLdoc)) // Suppose - if (isContainer) { // By default, make this apply to folder contents too + if (isContainer) { + // By default, make this apply to folder contents too proposed.push($rdf.st(da, ACL('default'), doc, defaultACLdoc)) } }) @@ -43,10 +62,18 @@ UI.acl.adoptACLDefault = function (doc, aclDoc, defaultResource, defaultACLdoc) proposed.map(function (st) { var move = function (sym) { var y = defaultACLdoc.uri.length // The default ACL file - return $rdf.sym((sym.uri.slice(0, y) === defaultACLdoc.uri) - ? aclDoc.uri + sym.uri.slice(y) : sym.uri) + return $rdf.sym( + sym.uri.slice(0, y) === defaultACLdoc.uri + ? aclDoc.uri + sym.uri.slice(y) + : sym.uri + ) } - kb2.add(move(st.subject), move(st.predicate), move(st.object), $rdf.sym(aclDoc.uri)) + kb2.add( + move(st.subject), + move(st.predicate), + move(st.object), + $rdf.sym(aclDoc.uri) + ) }) return kb2 @@ -59,13 +86,25 @@ UI.acl.adoptACLDefault = function (doc, aclDoc, defaultResource, defaultACLdoc) UI.acl.readACL = function (x, aclDoc, kb, getDefaults) { kb = kb || UI.store var ns = UI.ns - var auths = getDefaults ? kb.each(undefined, ns.acl('default'), x) - .concat(kb.each(undefined, ns.acl('defaultForNew'), x)) - : kb.each(undefined, ns.acl('accessTo'), x) + var auths = getDefaults + ? getDefaultsFallback(kb, ns) + : kb.each(undefined, ns.acl('accessTo'), x) var ACL = UI.ns.acl - var ac = {'agent': [], 'agentClass': [], 'agentGroup': [], 'origin': [], 'originClass': []} - for (var pred in {'agent': true, 'agentClass': true, 'agentGroup': true, 'origin': true, 'originClass': true}) { + var ac = { + agent: [], + agentClass: [], + agentGroup: [], + origin: [], + originClass: [] + } + for (var pred in { + agent: true, + agentClass: true, + agentGroup: true, + origin: true, + originClass: true + }) { auths.map(function (a) { kb.each(a, ACL('mode')).map(function (mode) { kb.each(a, ACL(pred)).map(function (agent) { @@ -76,12 +115,24 @@ UI.acl.readACL = function (x, aclDoc, kb, getDefaults) { }) } return ac + + function getDefaultsFallback (kb, ns) { + return kb + .each(undefined, ns.acl('default'), x) + .concat(kb.each(undefined, ns.acl('defaultForNew'), x)) + } } // Compare two ACLs UI.acl.sameACL = function (a, b) { var contains = function (a, b) { - for (var pred in {'agent': true, 'agentClass': true, 'agentGroup': true, 'origin': true, 'originClass': true}) { + for (var pred in { + agent: true, + agentClass: true, + agentGroup: true, + origin: true, + originClass: true + }) { if (a[pred]) { for (var agent in a[pred]) { for (var mode in a[pred][agent]) { @@ -102,17 +153,19 @@ UI.acl.ACLunion = function (list) { var b = list[0] var a, ag for (var k = 1; k < list.length; k++) { - ['agent', 'agentClass', 'agentGroup', 'origin', 'originClass'].map(function (pred) { - a = list[k] - if (a[pred]) { - for (ag in a[pred]) { - for (var mode in a[pred][ag]) { - if (!b[pred][ag]) b[pred][ag] = [] - b[pred][ag][mode] = true + ;['agent', 'agentClass', 'agentGroup', 'origin', 'originClass'].map( + function (pred) { + a = list[k] + if (a[pred]) { + for (ag in a[pred]) { + for (var mode in a[pred][ag]) { + if (!b[pred][ag]) b[pred][ag] = [] + b[pred][ag][mode] = true + } } } } - }) + ) } return b } @@ -124,14 +177,25 @@ UI.acl.loadUnionACL = function (subjectList, callbackFunction) { var doList = function (list) { if (list.length) { var doc = list.shift().doc() - UI.acl.getACLorDefault(doc, function (ok, p2, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc) { + UI.acl.getACLorDefault(doc, function ( + ok, + p2, + targetDoc, + targetACLDoc, + defaultHolder, + defaultACLDoc + ) { var defa = !p2 if (!ok) return callbackFunction(ok, targetACLDoc) - aclList.push((defa) ? UI.widgets.readACL(defaultHolder, defaultACLDoc) - : UI.widgets.readACL(targetDoc, targetACLDoc)) + aclList.push( + defa + ? UI.widgets.readACL(defaultHolder, defaultACLDoc) + : UI.widgets.readACL(targetDoc, targetACLDoc) + ) doList(list.slice(1)) }) - } else { // all gone + } else { + // all gone callbackFunction(true, UI.widgets.ACLunion(aclList)) } } @@ -144,8 +208,10 @@ UI.acl.loadUnionACL = function (subjectList, callbackFunction) { // Combos are like full control, read append, read only etc. // UI.acl.ACLbyCombination = function (ac) { - var byCombo = []; - ['agent', 'agentClass', 'agentGroup', 'origin', 'originClass'].map(function (pred) { + var byCombo = [] + ;['agent', 'agentClass', 'agentGroup', 'origin', 'originClass'].map(function ( + pred + ) { for (var agent in ac[pred]) { var combo = [] for (var mode in ac[pred][agent]) { @@ -173,7 +239,11 @@ UI.acl.makeACLGraphbyCombo = function (kb, x, byCombo, aclDoc, main, defa) { var ACL = UI.ns.acl for (var combo in byCombo) { var modeURIs = combo.split('\n') - var short = modeURIs.map(function (u) { return u.split('#')[1] }).join('') + var short = modeURIs + .map(function (u) { + return u.split('#')[1] + }) + .join('') if (defa && !main) short += 'Default' // don't muddle authorizations var a = kb.sym(aclDoc.uri + '#' + short) kb.add(a, UI.ns.rdf('type'), ACL('Authorization'), aclDoc) @@ -199,22 +269,24 @@ UI.acl.makeACLGraphbyCombo = function (kb, x, byCombo, aclDoc, main, defa) { // and who knows maybe in the UI // UI.acl.ACLToString = function (ac) { - return UI.widgets.comboToString( - UI.widgets.ACLbyCombination(ac)) + return UI.widgets.comboToString(UI.widgets.ACLbyCombination(ac)) } UI.acl.comboToString = function (byCombo) { var str = '' for (var combo in byCombo) { var modeURIs = combo.split('\n') - var initials = modeURIs.map(function (u) { return u.split('#')[1][0] }).join('') + var initials = modeURIs + .map(function (u) { + return u.split('#')[1][0] + }) + .join('') str += initials + ':' var pairs = byCombo[combo] for (var i = 0; i < pairs.length; i++) { var pred = pairs[i][0] var ag = $rdf.sym(pairs[i][1]) - str += (pred === 'agent') ? '@' : '' - str += (ag.sameTerm(UI.ns.foaf('Agent')) ? '*' - : utils.label(ag)) + str += pred === 'agent' ? '@' : '' + str += ag.sameTerm(UI.ns.foaf('Agent')) ? '*' : utils.label(ag) if (i < pairs.length - 1) str += ',' } str += ';' @@ -244,8 +316,11 @@ UI.acl.putACLbyCombo = function (kb, x, byCombo, aclDoc, callbackFunction) { UI.widgets.makeACLGraphbyCombo(kb2, x, byCombo, aclDoc, true) // var str = UI.widgets.makeACLString = function(x, ac, aclDoc) - kb.updater.put(aclDoc, kb2.statementsMatching(undefined, undefined, undefined, aclDoc), - 'text/turtle', function (uri, ok, message) { + kb.updater.put( + aclDoc, + kb2.statementsMatching(undefined, undefined, undefined, aclDoc), + 'text/turtle', + function (uri, ok, message) { if (!ok) { callbackFunction(ok, message) } else { @@ -254,7 +329,8 @@ UI.acl.putACLbyCombo = function (kb, x, byCombo, aclDoc, callbackFunction) { kb.fetcher.requested[aclDoc.uri] = 'done' // missing: save headers callbackFunction(ok) } - }) + } + ) } // Fix the ACl for an individual card as a function of the groups it is in @@ -271,15 +347,24 @@ UI.acl.fixIndividualCardACL = function (person, log, callbackFunction) { log('This card is in no groups') callbackFunction(true) // fine, no requirements to access. default should be ok } -// @@ if no groups, then use default for People container or the book top container.? + // @@ if no groups, then use default for People container or the book top container.? } UI.acl.fixIndividualACL = function (item, subjects, log, callbackFunction) { log = log || console.log var doc = item.doc() - UI.acl.getACLorDefault(doc, function (ok, exists, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc) { + UI.acl.getACLorDefault(doc, function ( + ok, + exists, + targetDoc, + targetACLDoc, + defaultHolder, + defaultACLDoc + ) { if (!ok) return callbackFunction(false, targetACLDoc) // ie message - var ac = (exists) ? UI.widgets.readACL(targetDoc, targetACLDoc) : UI.widgets.readACL(defaultHolder, defaultACLDoc) + var ac = exists + ? UI.widgets.readACL(targetDoc, targetACLDoc) + : UI.widgets.readACL(defaultHolder, defaultACLDoc) UI.widgets.loadUnionACL(subjects, function (ok, union) { if (!ok) return callbackFunction(false, union) if (UI.widgets.sameACL(union, ac)) { @@ -291,27 +376,48 @@ UI.acl.fixIndividualACL = function (item, subjects, log, callbackFunction) { // log((exists ? "Previous set" : "Default") + " ACLs: " + // UI.widgets.makeACLString(targetDoc, ac, targetACLDoc)) - UI.widgets.putACLObject(UI.store, targetDoc, union, targetACLDoc, callbackFunction) + UI.widgets.putACLObject( + UI.store, + targetDoc, + union, + targetACLDoc, + callbackFunction + ) } }) }) } UI.acl.setACL = function (docURI, aclText, callbackFunction) { - var aclDoc = kb.any(kb.sym(docURI), - kb.sym('http://www.iana.org/assignments/link-relations/acl')) // @@ check that this get set by web.js - if (aclDoc) { // Great we already know where it is - kb.fetcher.webOperation('PUT', aclDoc.uri, {data: aclText, contentType: 'text/turtle'}).then(callbackFunction) // @@@ check params + var aclDoc = kb.any( + kb.sym(docURI), + kb.sym('http://www.iana.org/assignments/link-relations/acl') + ) // @@ check that this get set by web.js + if (aclDoc) { + // Great we already know where it is + kb.fetcher + .webOperation('PUT', aclDoc.uri, { + data: aclText, + contentType: 'text/turtle' + }) + .then(callbackFunction) // @@@ check params } else { kb.fetcher.nowOrWhenFetched(docURI, undefined, function (ok, body) { if (!ok) return callbackFunction(ok, 'Gettting headers for ACL: ' + body) - var aclDoc = kb.any(kb.sym(docURI), - kb.sym('http://www.iana.org/assignments/link-relations/acl')) // @@ check that this get set by web.js + var aclDoc = kb.any( + kb.sym(docURI), + kb.sym('http://www.iana.org/assignments/link-relations/acl') + ) // @@ check that this get set by web.js if (!aclDoc) { // complainIfBad(false, "No Link rel=ACL header for " + docURI) callbackFunction(false, 'No Link rel=ACL header for ' + docURI) } else { - kb.fetcher.webOperation('PUT', aclDoc.uri, {data: aclText, contentType: 'text/turtle'}).then(callbackFunction) + kb.fetcher + .webOperation('PUT', aclDoc.uri, { + data: aclText, + contentType: 'text/turtle' + }) + .then(callbackFunction) } }) } @@ -344,37 +450,81 @@ UI.acl.getACLorDefault = function (doc, callbackFunction) { var doc2 = $rdf.sym(uri) UI.acl.getACL(doc2, function (ok, status, defaultACLDoc) { if (!ok) { - return callbackFunction(false, true, status, '( No ACL pointer ' + uri + ' ' + status + ')' + defaultACLDoc) + return callbackFunction( + false, + true, + status, + '( No ACL pointer ' + uri + ' ' + status + ')' + defaultACLDoc + ) } else if (status === 403) { - return callbackFunction(false, true, status, '( default ACL file FORBIDDEN. Stop.' + uri + ')') + return callbackFunction( + false, + true, + status, + '( default ACL file FORBIDDEN. Stop.' + uri + ')' + ) } else if (status === 404) { return tryParent(uri) } else if (status !== 200) { - return callbackFunction(false, true, status, "Error status '" + status + "' searching for default for " + doc2) + return callbackFunction( + false, + true, + status, + "Error status '" + status + "' searching for default for " + doc2 + ) } // 200 // statusBlock.textContent += (" ACCESS set at " + uri + ". End search.") - var defaults = kb.each(undefined, ACL('default'), kb.sym(uri), defaultACLDoc) - .concat(kb.each(undefined, ACL('defaultForNew'), kb.sym(uri), defaultACLDoc)) + var defaults = kb + .each(undefined, ACL('default'), kb.sym(uri), defaultACLDoc) + .concat( + kb.each(undefined, ACL('defaultForNew'), kb.sym(uri), defaultACLDoc) + ) if (!defaults.length) { return tryParent(uri) // Keep searching } var defaultHolder = kb.sym(uri) - return callbackFunction(true, false, doc, aclDoc, defaultHolder, defaultACLDoc) + return callbackFunction( + true, + false, + doc, + aclDoc, + defaultHolder, + defaultACLDoc + ) }) } // tryParent if (!ok) { - return callbackFunction(false, false, status, - 'Error accessing Access Control information for ' + doc + ') ' + message) + return callbackFunction( + false, + false, + status, + 'Error accessing Access Control information for ' + doc + ') ' + message + ) } else if (status === 404) { tryParent(doc.uri) // @@ construct default one - the server should do that } else if (status === 403) { - return callbackFunction(false, false, status, '(Sharing not available to you)' + message) + return callbackFunction( + false, + false, + status, + '(Sharing not available to you)' + message + ) } else if (status !== 200) { - return callbackFunction(false, false, status, 'Error ' + status + - ' accessing Access Control information for ' + doc + ': ' + message) - } else { // 200 + return callbackFunction( + false, + false, + status, + 'Error ' + + status + + ' accessing Access Control information for ' + + doc + + ': ' + + message + ) + } else { + // 200 return callbackFunction(true, true, doc, aclDoc) } }) // Call to getACL @@ -389,19 +539,40 @@ UI.acl.getACLorDefault = function (doc, callbackFunction) { // UI.acl.getACL = function (doc, callbackFunction) { UI.store.fetcher.nowOrWhenFetched(doc, undefined, function (ok, body) { - if (!ok) return callbackFunction(ok, "Can't get headers to find ACL for " + doc + ': ' + body) + if (!ok) { + return callbackFunction( + ok, + "Can't get headers to find ACL for " + doc + ': ' + body + ) + } var kb = UI.store - var aclDoc = kb.any(doc, - kb.sym('http://www.iana.org/assignments/link-relations/acl')) // @@ check that this get set by web.js + var aclDoc = kb.any( + doc, + kb.sym('http://www.iana.org/assignments/link-relations/acl') + ) // @@ check that this get set by web.js if (!aclDoc) { callbackFunction(false, 900, 'No Link rel=ACL header for ' + doc) } else { if (UI.store.fetcher.nonexistent[aclDoc.uri]) { - return callbackFunction(true, 404, aclDoc, 'ACL file ' + aclDoc + ' does not exist.') + return callbackFunction( + true, + 404, + aclDoc, + 'ACL file ' + aclDoc + ' does not exist.' + ) } - UI.store.fetcher.nowOrWhenFetched(aclDoc, undefined, function (ok, message, response) { + UI.store.fetcher.nowOrWhenFetched(aclDoc, undefined, function ( + ok, + message, + response + ) { if (!ok) { - callbackFunction(true, response.status, aclDoc, "Can't read Access Control File " + aclDoc + ': ' + message) + callbackFunction( + true, + response.status, + aclDoc, + "Can't read Access Control File " + aclDoc + ': ' + message + ) } else { callbackFunction(true, 200, aclDoc) } diff --git a/src/chat/bookmarks.js b/src/chat/bookmarks.js index 6773bb6f2..330b8f15c 100644 --- a/src/chat/bookmarks.js +++ b/src/chat/bookmarks.js @@ -1,4 +1,3 @@ - /* global alert confirm */ const UI = { @@ -28,31 +27,46 @@ const dom = UI.dom || window.document * Be absolutely sure something does not exist before creating a new empty file * as otherwise existing could be deleted. * @param doc {NamedNode} - The resource -*/ + */ function createIfNotExists (doc) { return new Promise(function (resolve, reject) { - kb.fetcher.load(doc).then(response => { - console.log('createIfNotExists doc exists, all good ' + doc) - // kb.fetcher.webOperation('HEAD', doc.uri).then(response => { - resolve(response) - }, err => { - if (err.response.status === 404) { - console.log('createIfNotExists doc does NOT exist, will create... ' + doc) - - kb.fetcher.webOperation('PUT', doc.uri, {data: '', contentType: 'text/turtle'}).then(response => { - // fetcher.requested[doc.uri] = 'done' // do not need to read ?? but no headers - delete kb.fetcher.requested[doc.uri] // delete cached 404 error - console.log('createIfNotExists doc created ok ' + doc) - resolve(response) - }, err => { - console.log('createIfNotExists doc FAILED: ' + doc + ': ' + err) + kb.fetcher.load(doc).then( + response => { + console.log('createIfNotExists doc exists, all good ' + doc) + // kb.fetcher.webOperation('HEAD', doc.uri).then(response => { + resolve(response) + }, + err => { + if (err.response.status === 404) { + console.log( + 'createIfNotExists doc does NOT exist, will create... ' + doc + ) + + kb.fetcher + .webOperation('PUT', doc.uri, { + data: '', + contentType: 'text/turtle' + }) + .then( + response => { + // fetcher.requested[doc.uri] = 'done' // do not need to read ?? but no headers + delete kb.fetcher.requested[doc.uri] // delete cached 404 error + console.log('createIfNotExists doc created ok ' + doc) + resolve(response) + }, + err => { + console.log('createIfNotExists doc FAILED: ' + doc + ': ' + err) + reject(err) + } + ) + } else { + console.log( + 'createIfNotExists doc load error NOT 404: ' + doc + ': ' + err + ) reject(err) - }) - } else { - console.log('createIfNotExists doc load error NOT 404: ' + doc + ': ' + err) - reject(err) + } } - }) + ) }) } @@ -72,9 +86,9 @@ function updatePromise (del, ins) { // export findBookmarkDocument, /* Bookmarking -*/ + */ /** Find a user's bookmarks -*/ + */ export async function findBookmarkDocument (userContext) { const klass = BOOK('Bookmark') const fileTail = 'bookmarks.ttl' @@ -87,16 +101,24 @@ export async function findBookmarkDocument (userContext) { alert('More than one bookmark file! ' + userContext.instances) } } else { - if (userContext.publicProfile) { // publicProfile or preferencesFile - var newBookmarkFile = $rdf.sym(userContext.publicProfile.dir().uri + fileTail) + if (userContext.publicProfile) { + // publicProfile or preferencesFile + var newBookmarkFile = $rdf.sym( + userContext.publicProfile.dir().uri + fileTail + ) try { console.log('Creating new bookmark file ' + newBookmarkFile) await createIfNotExists(newBookmarkFile) } catch (e) { - alert.error('Can\'t make fresh bookmark file:' + e) + alert.error("Can't make fresh bookmark file:" + e) return userContext } - await UI.authn.registerInTypeIndex(userContext, newBookmarkFile, klass, true) // public + await UI.authn.registerInTypeIndex( + userContext, + newBookmarkFile, + klass, + true + ) // public userContext.bookmarkDocument = newBookmarkFile } else { alert('You seem to have no bookmark file and not even a profile file.') @@ -105,7 +127,7 @@ export async function findBookmarkDocument (userContext) { return userContext } - /** Add a bookmark +/** Add a bookmark */ async function addBookmark (context, target) { @@ -126,8 +148,8 @@ async function addBookmark (context, target) { if (!me) throw new Error('Must be logged on to add Bookmark') var author = kb.any(target, ns.foaf('maker')) - title = label(author) + ': ' + - kb.anyValue(target, ns.sioc('content')).slice(0, 80) // @@ add chat title too? + title = + label(author) + ': ' + kb.anyValue(target, ns.sioc('content')).slice(0, 80) // @@ add chat title too? const bookmarkDoc = context.bookmarkDocument const bookmark = UI.widgets.newThing(bookmarkDoc, title) const ins = [ @@ -141,7 +163,7 @@ async function addBookmark (context, target) { try { await updatePromise([], ins) // 20190118A } catch (e) { - let msg = 'Making bookmark: ' + e + const msg = 'Making bookmark: ' + e alert.error(msg) return null } @@ -150,8 +172,14 @@ async function addBookmark (context, target) { export async function toggleBookmark (userContext, target, bookmarkButton) { await kb.fetcher.load(userContext.bookmarkDocument) - let bookmarks = kb.each(null, BOOK('recalls'), target, userContext.bookmarkDocument) - if (bookmarks.length) { // delete + const bookmarks = kb.each( + null, + BOOK('recalls'), + target, + userContext.bookmarkDocument + ) + if (bookmarks.length) { + // delete if (!confirm('Delete bookmark on this?' + bookmarks.length)) return for (let i = 0; i < bookmarks.length; i++) { try { @@ -164,7 +192,7 @@ export async function toggleBookmark (userContext, target, bookmarkButton) { } } } else { - let bookmark = await addBookmark(userContext, target) + const bookmark = await addBookmark(userContext, target) bookmarkButton.style.backgroundColor = 'yellow' console.log('Bookmark added: ' + bookmark) } @@ -173,17 +201,26 @@ export async function toggleBookmark (userContext, target, bookmarkButton) { export async function renderBookmarksButton (userContext, target) { async function setBookmarkButtonColor (bookmarkButton) { await kb.fetcher.load(userContext.bookmarkDocument) - let bookmarked = kb.any(null, BOOK('recalls'), bookmarkButton.target, userContext.bookmarkDocument) + const bookmarked = kb.any( + null, + BOOK('recalls'), + bookmarkButton.target, + userContext.bookmarkDocument + ) bookmarkButton.style = UI.style.buttonStyle if (bookmarked) bookmarkButton.style.backgroundColor = 'yellow' } var bookmarkButton if (userContext.bookmarkDocument) { - bookmarkButton = UI.widgets.button(dom, UI.icons.iconBase + BOOKMARK_ICON, - label(BOOK('Bookmark')), () => { - toggleBookmark(userContext, target, bookmarkButton) - }) + bookmarkButton = UI.widgets.button( + dom, + UI.icons.iconBase + BOOKMARK_ICON, + label(BOOK('Bookmark')), + () => { + toggleBookmark(userContext, target, bookmarkButton) + } + ) bookmarkButton.target = target await setBookmarkButtonColor(bookmarkButton) return bookmarkButton diff --git a/src/chat/dateFolder.js b/src/chat/dateFolder.js index 12e719fde..bb9e07000 100644 --- a/src/chat/dateFolder.js +++ b/src/chat/dateFolder.js @@ -1,6 +1,7 @@ +/* global $rdf */ /** Track back through the YYYY/MM/DD tree to find the previous/next day -** -*/ + ** + */ const kb = require('../store.js') const ns = require('../ns.js') @@ -14,18 +15,18 @@ module.exports = class DateFolder { } /* Generate the leaf document (rdf object) from date - * @returns: - document - */ + * @returns: - document + */ leafDocumentFromDate (date) { // console.log('incoming date: ' + date) - let isoDate = date.toISOString() // Like "2018-05-07T17:42:46.576Z" + const isoDate = date.toISOString() // Like "2018-05-07T17:42:46.576Z" var path = isoDate.split('T')[0].replace(/-/g, '/') // Like "2018/05/07" path = this.root.dir().uri + path + '/' + this.leafFileName return kb.sym(path) } /* Generate a date object from the leaf file name - */ + */ dateFromLeafDocument (doc) { const head = this.rootFolder.uri.length const str = doc.uri.slice(head, head + 10).replace(/\//g, '-') @@ -44,7 +45,10 @@ module.exports = class DateFolder { return true } function suitable (x) { - let tail = x.uri.slice(0, -1).split('/').slice(-1)[0] + const tail = x.uri + .slice(0, -1) + .split('/') + .slice(-1)[0] if (!'0123456789'.includes(tail[0])) return false // not numeric return true } @@ -55,11 +59,14 @@ module.exports = class DateFolder { if (!backwards) siblings.reverse() if (level !== 3) return siblings.pop() // only length chck final leverl while (siblings.length) { - let folder = siblings.pop() - let leafDocument = kb.sym(folder.uri + thisDateFolder.leafFileName) + const folder = siblings.pop() + const leafDocument = kb.sym(folder.uri + thisDateFolder.leafFileName) await kb.fetcher.load(leafDocument) // files can have seealso links. skip ones with no leafObjects with a date - if (kb.statementsMatching(null, ns.dct('created'), null, leafDocument).length > 0) { + if ( + kb.statementsMatching(null, ns.dct('created'), null, leafDocument) + .length > 0 + ) { return folder } } @@ -70,7 +77,7 @@ module.exports = class DateFolder { await kb.fetcher.load(parent) var siblings = kb.each(parent, ns.ldp('contains')) siblings = siblings.filter(younger) - let folder = await lastNonEmpty(siblings) + const folder = await lastNonEmpty(siblings) if (folder) return folder if (level === 0) return null // 3:day, 2:month, 1: year 0: no @@ -79,32 +86,36 @@ module.exports = class DateFolder { if (!uncle) return null // reached first ever await kb.fetcher.load(uncle) var cousins = kb.each(uncle, ns.ldp('contains')) - let result = await lastNonEmpty(cousins) + const result = await lastNonEmpty(cousins) return result } // previousPeriod - let folder = this.leafDocumentFromDate(date).dir() - let found = await previousPeriod(folder, 3) + const folder = this.leafDocumentFromDate(date).dir() + const found = await previousPeriod(folder, 3) if (found) { - let doc = kb.sym(found.uri + this.leafFileNam) + const doc = kb.sym(found.uri + this.leafFileNam) return this.dateFromLeafDocument(doc) } return null } // loadPrevious - async firstLeaf (backwards) { // backwards -> last leafObject + async firstLeaf (backwards) { + // backwards -> last leafObject var folderStore = $rdf.graph() var folderFetcher = new $rdf.Fetcher(folderStore) async function earliestSubfolder (parent) { function suitable (x) { - let tail = x.uri.slice(0, -1).split('/').slice(-1)[0] + const tail = x.uri + .slice(0, -1) + .split('/') + .slice(-1)[0] if (!'0123456789'.includes(tail[0])) return false // not numeric return true } console.log(' parent ' + parent) delete folderFetcher.requested[parent.uri] // try { - await folderFetcher.load(parent, {force: true}) // Force fetch as will have changed + await folderFetcher.load(parent, { force: true }) // Force fetch as will have changed // }catch (err) { // } @@ -118,21 +129,32 @@ module.exports = class DateFolder { if (backwards) kids.reverse() return kids[0] } - let y = await earliestSubfolder(this.root.dir()) - let month = await earliestSubfolder(y) - let d = await earliestSubfolder(month) - let leafDocument = $rdf.sym(d.uri + 'chat.ttl') + const y = await earliestSubfolder(this.root.dir()) + const month = await earliestSubfolder(y) + const d = await earliestSubfolder(month) + const leafDocument = $rdf.sym(d.uri + 'chat.ttl') await folderFetcher.load(leafDocument) - let leafObjects = folderStore.each(this.root, this.membershipProperty, null, leafDocument) + const leafObjects = folderStore.each( + this.root, + this.membershipProperty, + null, + leafDocument + ) if (leafObjects.length === 0) { - let msg = ' INCONSISTENCY -- no chat leafObject in file ' + leafDocument + const msg = + ' INCONSISTENCY -- no chat leafObject in file ' + leafDocument console.trace(msg) throw new Error(msg) } - let sortMe = leafObjects.map(leafObject => [folderStore.any(leafObject, ns.dct('created')), leafObject]) + const sortMe = leafObjects.map(leafObject => [ + folderStore.any(leafObject, ns.dct('created')), + leafObject + ]) sortMe.sort() if (backwards) sortMe.reverse() - console.log((backwards ? 'Latest' : 'Earliest') + ' leafObject is ' + sortMe[0][1]) + console.log( + (backwards ? 'Latest' : 'Earliest') + ' leafObject is ' + sortMe[0][1] + ) return sortMe[0][1] } // firstleafObject } // class diff --git a/src/chat/infinite.js b/src/chat/infinite.js index 7663b273d..4200ca00a 100644 --- a/src/chat/infinite.js +++ b/src/chat/infinite.js @@ -4,7 +4,7 @@ // Parameters for the whole chat like its title are stred on // index.ttl#this and the chats messages are stored in YYYY/MM/DD/chat.ttl // -/* global alert */ +/* global alert $rdf */ import DateFolder from './dateFolder' // @@ trace20190428T1745 @@ -38,9 +38,14 @@ async function createIfNotExists (doc, contentType = 'text/turtle', data = '') { var response = await fetcher.load(doc) } catch (err) { if (err.response.status === 404) { - console.log('createIfNotExists: doc does NOT exist, will create... ' + doc) + console.log( + 'createIfNotExists: doc does NOT exist, will create... ' + doc + ) try { - response = await fetcher.webOperation('PUT', doc.uri, {data, contentType}) + response = await fetcher.webOperation('PUT', doc.uri, { + data, + contentType + }) } catch (err) { console.log('createIfNotExists doc FAILED: ' + doc + ': ' + err) throw err @@ -49,7 +54,9 @@ async function createIfNotExists (doc, contentType = 'text/turtle', data = '') { // console.log('createIfNotExists doc created ok ' + doc) return response } else { - console.log('createIfNotExists doc load error NOT 404: ' + doc + ': ' + err) + console.log( + 'createIfNotExists doc load error NOT 404: ' + doc + ': ' + err + ) throw err } } @@ -81,14 +88,14 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { var div = dom.createElement('div') var menuButton const statusArea = div.appendChild(dom.createElement('div')) - var userContext = {dom, statusArea, div: statusArea} // logged on state, pointers to user's stuff + var userContext = { dom, statusArea, div: statusArea } // logged on state, pointers to user's stuff var me var updater = UI.store.updater /** Does a file exist on the web? * @returns {Boolean} - */ + */ /* async function documentExists (doc) { try { @@ -105,7 +112,7 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { } */ /* Form for a new message - */ + */ function newMessageForm (messageTable) { var form = dom.createElement('tr') var lhs = dom.createElement('td') @@ -128,22 +135,34 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { var sts = [] var timestamp = '' + now.getTime() var dateStamp = $rdf.term(now) - let chatDocument = dateFolder.leafDocumentFromDate(now) + const chatDocument = dateFolder.leafDocumentFromDate(now) var message = kb.sym(chatDocument.uri + '#' + 'Msg' + timestamp) var content = kb.literal(text || field.value) // if (text) field.value = text No - don't destroy half-finsihed user input - sts.push(new $rdf.Statement(chatChannel, ns.wf('message'), message, chatDocument)) - sts.push(new $rdf.Statement(message, ns.sioc('content'), content, chatDocument)) - sts.push(new $rdf.Statement(message, DCT('created'), dateStamp, chatDocument)) - if (me) sts.push(new $rdf.Statement(message, ns.foaf('maker'), me, chatDocument)) + sts.push( + new $rdf.Statement(chatChannel, ns.wf('message'), message, chatDocument) + ) + sts.push( + new $rdf.Statement(message, ns.sioc('content'), content, chatDocument) + ) + sts.push( + new $rdf.Statement(message, DCT('created'), dateStamp, chatDocument) + ) + if (me) { + sts.push( + new $rdf.Statement(message, ns.foaf('maker'), me, chatDocument) + ) + } function sendComplete () { - var bindings = { '?msg': message, + var bindings = { + '?msg': message, '?content': content, '?date': dateStamp, - '?creator': me} + '?creator': me + } renderMessage(liveMessageTable, bindings, false, options, userContext) // not green if (!text) { @@ -155,14 +174,23 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { field.select() } } - if (SERVER_MKDIRP_BUG && (kb.fetcher.requested[chatDocument.uri] === undefined || kb.fetcher.requested[chatDocument.uri] === 404)) { - console.log('@@@ SERVER_MKDIRP_BUG: Should only happen once: create chat file: ' + chatDocument) + if ( + SERVER_MKDIRP_BUG && + (kb.fetcher.requested[chatDocument.uri] === undefined || + kb.fetcher.requested[chatDocument.uri] === 404) + ) { + console.log( + '@@@ SERVER_MKDIRP_BUG: Should only happen once: create chat file: ' + + chatDocument + ) await createIfNotExists(chatDocument) } try { await updater.update([], sts) } catch (err) { - form.appendChild(UI.widgets.errorMessageBlock(dom, 'Error writing message: ' + err)) + form.appendChild( + UI.widgets.errorMessageBlock(dom, 'Error writing message: ' + err) + ) return } sendComplete() @@ -172,11 +200,17 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { // DRAG AND DROP function droppedFileHandler (files) { - let base = messageTable.chatDocument.dir().uri - UI.widgets.uploadFiles(kb.fetcher, files, base + 'Files', base + 'Pictures', - async function (theFile, destURI) { // @@@@@@ Wait for eachif several + const base = messageTable.chatDocument.dir().uri + UI.widgets.uploadFiles( + kb.fetcher, + files, + base + 'Files', + base + 'Pictures', + async function (theFile, destURI) { + // @@@@@@ Wait for eachif several await sendMessage(destURI) - }) + } + ) } // When a set of URIs are dropped on the field @@ -189,10 +223,19 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { // When we are actually logged on function turnOnInput () { if (options.menuHandler && menuButton) { - let menuOptions = { me, dom, div, newBase: messageTable.chatDocument.dir().uri } - menuButton.addEventListener('click', - event => { options.menuHandler(event, chatChannel, menuOptions) } - , false) + const menuOptions = { + me, + dom, + div, + newBase: messageTable.chatDocument.dir().uri + } + menuButton.addEventListener( + 'click', + event => { + options.menuHandler(event, chatChannel, menuOptions) + }, + false + ) } // Turn on message input @@ -206,25 +249,37 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { field.setAttribute('style', messageBodyStyle + 'background-color: #eef;') // Trap the Enter BEFORE it is used ti make a newline - field.addEventListener('keydown', async function (e) { // User preference? - if (e.keyCode === 13) { - if (!e.altKey) { // Alt-Enter just adds a new line - await sendMessage() + field.addEventListener( + 'keydown', + async function (e) { + // User preference? + if (e.keyCode === 13) { + if (!e.altKey) { + // Alt-Enter just adds a new line + await sendMessage() + } } - } - }, false) + }, + false + ) UI.widgets.makeDropTarget(field, droppedURIHandler, droppedFileHandler) rhs.innerHTML = '' - sendButton = UI.widgets.button(dom, UI.icons.iconBase + 'noun_383448.svg', 'Send') + sendButton = UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_383448.svg', + 'Send' + ) sendButton.setAttribute('style', UI.style.buttonStyle + 'float: right;') - sendButton.addEventListener('click', ev => sendMessage(), false) + sendButton.addEventListener('click', _event => sendMessage(), false) rhs.appendChild(sendButton) const chatDocument = dateFolder.leafDocumentFromDate(new Date()) var imageDoc function getImageDoc () { - imageDoc = kb.sym(chatDocument.dir().uri + 'Image_' + Date.now() + '.png') + imageDoc = kb.sym( + chatDocument.dir().uri + 'Image_' + Date.now() + '.png' + ) return imageDoc } async function tookPicture (imageDoc) { @@ -232,12 +287,14 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { await sendMessage(imageDoc.uri) } } - middle.appendChild(UI.media.cameraButton(dom, kb, getImageDoc, tookPicture)) + middle.appendChild( + UI.media.cameraButton(dom, kb, getImageDoc, tookPicture) + ) UI.pad.recordParticipation(chatChannel, chatChannel.doc()) // participation = } // turn on inpuut - let context = {div: middle, dom: dom} + const context = { div: middle, dom: dom } UI.authn.logIn(context).then(context => { me = context.me turnOnInput() @@ -261,8 +318,16 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { } } - var messages = kb.statementsMatching( - about, ns.wf('message'), null, messageTable.chatDocument).map(st => { return st.object }) + var messages = kb + .statementsMatching( + about, + ns.wf('message'), + null, + messageTable.chatDocument + ) + .map(st => { + return st.object + }) var stored = {} messages.map(function (m) { stored[m.uri] = true @@ -271,7 +336,8 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { } }) - for (ele = messageTable.firstChild; ele;) { + // eslint-disable-next-line space-in-parens + for (ele = messageTable.firstChild; ele; ) { ele2 = ele.nextSibling if (ele.AJAR_subject && !stored[ele.AJAR_subject.uri]) { messageTable.removeChild(ele) @@ -279,7 +345,8 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { ele = ele2 } for (ele = messageTable.firstChild; ele; ele = ele.nextSibling) { - if (ele.AJAR_subject) { // Refresh thumbs up etc + if (ele.AJAR_subject) { + // Refresh thumbs up etc UI.widgets.refreshTree(ele) // Things inside may have changed too } } @@ -292,65 +359,79 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { '?date': kb.any(message, DCT('created')), '?content': kb.any(message, ns.sioc('content')) } - renderMessage(messageTable, bindings, messageTable.fresh, options, userContext) // fresh from elsewhere + renderMessage( + messageTable, + bindings, + messageTable.fresh, + options, + userContext + ) // fresh from elsewhere } -// //////// + // //////// /* Add a new messageTable at the top/bottom - */ + */ async function insertPreviousMessages (backwards) { - let extremity = backwards ? earliest : latest - let date = extremity.messageTable.date// day in mssecs + const extremity = backwards ? earliest : latest + let date = extremity.messageTable.date // day in mssecs date = await dateFolder.loadPrevious(date, backwards) // backwards - console.log(`insertPreviousMessages: from ${backwards ? 'backwards' : 'forwards'} loadPrevious: ${date}`) + console.log( + `insertPreviousMessages: from ${ + backwards ? 'backwards' : 'forwards' + } loadPrevious: ${date}` + ) if (!date && !backwards && !liveMessageTable) { - await appendCurrentMessages() // If necessary skip to today and add that + await appendCurrentMessages() // If necessary skip to today and add that } if (!date) return true // done var live = false if (!backwards) { - let todayDoc = dateFolder.leafDocumentFromDate(new Date()) - let doc = dateFolder.leafDocumentFromDate(date) + const todayDoc = dateFolder.leafDocumentFromDate(new Date()) + const doc = dateFolder.leafDocumentFromDate(date) live = doc.sameTerm(todayDoc) // Is this todays? } - let newMessageTable = await createMessageTable(date, live) + const newMessageTable = await createMessageTable(date, live) extremity.messageTable = newMessageTable // move pointer to earliest - if (backwards ? newestFirst : !newestFirst) { // put on bottom or top + if (backwards ? newestFirst : !newestFirst) { + // put on bottom or top div.appendChild(newMessageTable) - } else { // put on top as we scroll back + } else { + // put on top as we scroll back div.insertBefore(newMessageTable, div.firstChild) } return live // not done } /* Remove message tables earlier than this one - */ + */ function removePreviousMessages (backwards, messageTable) { - if (backwards ? newestFirst : !newestFirst) { // it was put on bottom + if (backwards ? newestFirst : !newestFirst) { + // it was put on bottom while (messageTable.nextSibling) { div.removeChild(messageTable.nextSibling) } - } else { // it was put on top as we scroll back + } else { + // it was put on top as we scroll back while (messageTable.previousSibling) { div.removeChild(messageTable.previousSibling) } } - let extr = backwards ? earliest : latest + const extr = backwards ? earliest : latest extr.messageTable = messageTable } /* Load and render message table - ** @returns DOM element generates - */ + ** @returns DOM element generates + */ async function createMessageTable (date, live) { console.log(' createMessageTable for ' + date) const chatDocument = dateFolder.leafDocumentFromDate(date) try { await kb.fetcher.load(chatDocument) } catch (err) { - let messageTable = (dom.createElement('table')) - let statusTR = messageTable.appendChild(dom.createElement('tr')) // ### find status in exception + const messageTable = dom.createElement('table') + const statusTR = messageTable.appendChild(dom.createElement('tr')) // ### find status in exception if (err.response && err.response.status && err.response.status === 404) { console.log('Error 404 for chat file ' + chatDocument) return renderMessageTable(date, live) // no mssage file is fine.. will be craeted later @@ -368,12 +449,15 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { var scrollBackButton var scrollForwardButton -/// ///////////////// Scroll down adding more above + /// ///////////////// Scroll down adding more above async function extendBackwards () { - let done = await insertPreviousMessages(true) + const done = await insertPreviousMessages(true) if (done) { - scrollBackButton.firstChild.setAttribute('src', UI.icons.iconBase + 'noun_T-Block_1114655_000000.svg') // T + scrollBackButton.firstChild.setAttribute( + 'src', + UI.icons.iconBase + 'noun_T-Block_1114655_000000.svg' + ) // T scrollBackButton.disabled = true messageTable.initial = true } else { @@ -383,12 +467,20 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { return done } function setScrollBackButtonIcon () { - let sense = messageTable.extendedBack ? !newestFirst : newestFirst - let scrollBackIcon = messageTable.initial ? 'noun_T-Block_1114655_000000.svg' - : (sense ? 'noun_1369241.svg' : 'noun_1369237.svg') - scrollBackButton.firstChild.setAttribute('src', UI.icons.iconBase + scrollBackIcon) + const sense = messageTable.extendedBack ? !newestFirst : newestFirst + const scrollBackIcon = messageTable.initial + ? 'noun_T-Block_1114655_000000.svg' + : getScrollbackIcon(sense) + scrollBackButton.firstChild.setAttribute( + 'src', + UI.icons.iconBase + scrollBackIcon + ) + + function getScrollbackIcon (sense) { + return sense ? 'noun_1369241.svg' : 'noun_1369237.svg' + } } - async function scrollBackButtonHandler (event) { + async function scrollBackButtonHandler (_event) { if (messageTable.extendedBack) { removePreviousMessages(true, messageTable) messageTable.extendedBack = false @@ -401,9 +493,12 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { /// ////////////// Scroll up adding more below async function extendForwards () { - let done = await insertPreviousMessages(false) + const done = await insertPreviousMessages(false) if (done) { - scrollForwardButton.firstChild.setAttribute('src', UI.icons.iconBase + 'noun_T-Block_1114655_000000.svg') + scrollForwardButton.firstChild.setAttribute( + 'src', + UI.icons.iconBase + 'noun_T-Block_1114655_000000.svg' + ) scrollForwardButton.disabled = true messageTable.final = true } else { @@ -413,12 +508,20 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { return done } function setScrollForwardButtonIcon () { - let sense = messageTable.extendedForwards ? !newestFirst : newestFirst // noun_T-Block_1114657_000000.svg - let scrollForwardIcon = messageTable.final ? 'noun_T-Block_1114657_000000.svg' - : (!sense ? 'noun_1369241.svg' : 'noun_1369237.svg') - scrollForwardButton.firstChild.setAttribute('src', UI.icons.iconBase + scrollForwardIcon) + const sense = messageTable.extendedForwards ? !newestFirst : newestFirst // noun_T-Block_1114657_000000.svg + const scrollForwardIcon = messageTable.final + ? 'noun_T-Block_1114657_000000.svg' + : getScrollForwardButtonIcon(sense) + scrollForwardButton.firstChild.setAttribute( + 'src', + UI.icons.iconBase + scrollForwardIcon + ) + + function getScrollForwardButtonIcon (sense) { + return !sense ? 'noun_1369241.svg' : 'noun_1369237.svg' + } } - async function scrollForwardButtonHandler (event) { + async function scrollForwardButtonHandler (_event) { if (messageTable.extendedForwards) { removePreviousMessages(false, messageTable) messageTable.extendedForwards = false @@ -460,43 +563,66 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { // // @@ listen for swipe past end event not just button if (options.infinite) { - let scrollBackButtonTR = dom.createElement('tr') - let scrollBackButtonCell = scrollBackButtonTR.appendChild(dom.createElement('td')) + const scrollBackButtonTR = dom.createElement('tr') + const scrollBackButtonCell = scrollBackButtonTR.appendChild( + dom.createElement('td') + ) // up traingles: noun_1369237.svg // down triangles: noun_1369241.svg - let scrollBackIcon = newestFirst ? 'noun_1369241.svg' : 'noun_1369237.svg' // down and up arrows respoctively - scrollBackButton = UI.widgets.button(dom, UI.icons.iconBase + scrollBackIcon, 'Previous messages ...') + const scrollBackIcon = newestFirst + ? 'noun_1369241.svg' + : 'noun_1369237.svg' // down and up arrows respoctively + scrollBackButton = UI.widgets.button( + dom, + UI.icons.iconBase + scrollBackIcon, + 'Previous messages ...' + ) scrollBackButtonCell.style = 'width:3em; height:3em;' scrollBackButton.addEventListener('click', scrollBackButtonHandler, false) messageTable.extendedBack = false scrollBackButtonCell.appendChild(scrollBackButton) setScrollBackButtonIcon() - let dateCell = scrollBackButtonTR.appendChild(dom.createElement('td')) - dateCell.style = 'text-align: center; vertical-align: middle; color: #888; font-style: italic;' + const dateCell = scrollBackButtonTR.appendChild(dom.createElement('td')) + dateCell.style = + 'text-align: center; vertical-align: middle; color: #888; font-style: italic;' dateCell.textContent = UI.widgets.shortDate(date.toISOString(), true) // no time, only date // @@@@@@@@@@@ todo move this button to other end of message cell, o - let scrollForwardButtonCell = scrollBackButtonTR.appendChild(dom.createElement('td')) - let scrollForwardIcon = newestFirst ? 'noun_1369241.svg' : 'noun_1369237.svg' // down and up arrows respoctively - scrollForwardButton = UI.widgets.button(dom, UI.icons.iconBase + scrollForwardIcon, 'Later messages ...') + const scrollForwardButtonCell = scrollBackButtonTR.appendChild( + dom.createElement('td') + ) + const scrollForwardIcon = newestFirst + ? 'noun_1369241.svg' + : 'noun_1369237.svg' // down and up arrows respoctively + scrollForwardButton = UI.widgets.button( + dom, + UI.icons.iconBase + scrollForwardIcon, + 'Later messages ...' + ) scrollForwardButtonCell.appendChild(scrollForwardButton) scrollForwardButtonCell.style = 'width:3em; height:3em;' - scrollForwardButton.addEventListener('click', scrollForwardButtonHandler, false) + scrollForwardButton.addEventListener( + 'click', + scrollForwardButtonHandler, + false + ) messageTable.extendedForward = false setScrollForwardButtonIcon() messageTable.extendedForwards = false - if (!newestFirst) { // opposite end from the entry field + if (!newestFirst) { + // opposite end from the entry field messageTable.insertBefore(scrollBackButtonTR, messageTable.firstChild) // If not newestFirst } else { messageTable.appendChild(scrollBackButtonTR) // newestFirst } } - let sts = kb.statementsMatching(null, WF('message'), null, chatDocument) - if (!live && sts.length === 0) { // not todays + const sts = kb.statementsMatching(null, WF('message'), null, chatDocument) + if (!live && sts.length === 0) { + // not todays // no need buttomns at the moment // messageTable.style.visibility = 'collapse' // Hide files with no messages } @@ -513,8 +639,9 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { async function addNewTableIfNewDay (now) { // let now = new Date() // @@ Remove listener from previous table as it is now static - let newChatDocument = dateFolder.leafDocumentFromDate(now) - if (!newChatDocument.sameTerm(latest.messageTable.chatDocument)) { // It is a new day + const newChatDocument = dateFolder.leafDocumentFromDate(now) + if (!newChatDocument.sameTerm(latest.messageTable.chatDocument)) { + // It is a new day if (liveMessageTable.inputRow) { liveMessageTable.removeChild(liveMessageTable.inputRow) delete liveMessageTable.inputRow @@ -522,8 +649,22 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { var oldChatDocument = latest.messageTable.chatDocument await appendCurrentMessages() // Adding a link in the document will ping listeners to add the new block too - if (!kb.holds(oldChatDocument, ns.rdfs('seeAlso'), newChatDocument, oldChatDocument)) { - let sts = [$rdf.st(oldChatDocument, ns.rdfs('seeAlso'), newChatDocument, oldChatDocument)] + if ( + !kb.holds( + oldChatDocument, + ns.rdfs('seeAlso'), + newChatDocument, + oldChatDocument + ) + ) { + const sts = [ + $rdf.st( + oldChatDocument, + ns.rdfs('seeAlso'), + newChatDocument, + oldChatDocument + ) + ] updater.update([], sts, function (ok, body) { if (!ok) { alert('Unable to link old message block to new one.' + body) @@ -532,7 +673,7 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { } } } -/* + /* function messageCount () { var n = 0 const tables = div.children @@ -543,15 +684,15 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { return n } */ -/* Add the live message block with entry field for today -*/ + /* Add the live message block with entry field for today + */ async function appendCurrentMessages () { var now = new Date() var chatDocument = dateFolder.leafDocumentFromDate(now) /* Don't actually make the documemnt until a message is sent @@@@@ WHEN SERVER FIXED * currently server won't patch to a file ina non-existent directory - */ + */ /* if (SERVER_MKDIRP_BUG) { try { @@ -566,8 +707,11 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { /// /////////////////////////////////////////////////////////// const messageTable = await createMessageTable(now, true) div.appendChild(messageTable) - div.refresh = function () { // only the last messageTable is live - addNewTableIfNewDay(new Date()).then(() => { syncMessages(chatChannel, messageTable) }) + div.refresh = function () { + // only the last messageTable is live + addNewTableIfNewDay(new Date()).then(() => { + syncMessages(chatChannel, messageTable) + }) } // The short chat version fors live update in the pane but we do it in the widget kb.updater.addDownstreamChangeListener(chatDocument, div.refresh) // Live update liveMessageTable = messageTable @@ -576,8 +720,8 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { } var liveMessageTable - var earliest = {messageTable: null} // Stuff about each end of the loaded days - var latest = {messageTable: null} + var earliest = { messageTable: null } // Stuff about each end of the loaded days + var latest = { messageTable: null } var lock = false async function loadMoreWhereNeeded (event, fixScroll) { @@ -589,11 +733,13 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { // const bottom = div.scrollHeight - top - div.clientHeight var done - while (div.scrollTop < magicZone && - earliest.messageTable && - !earliest.messageTable.initial && - earliest.messageTable.extendBackwards) { - let scrollBottom = div.scrollHeight - div.scrollTop + while ( + div.scrollTop < magicZone && + earliest.messageTable && + !earliest.messageTable.initial && + earliest.messageTable.extendBackwards + ) { + const scrollBottom = div.scrollHeight - div.scrollTop console.log('infinite scroll: adding above: top ' + div.scrollTop) done = await earliest.messageTable.extendBackwards() if (freeze) { @@ -602,13 +748,18 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { if (fixScroll) fixScroll() if (done) break } - while (options.selectedMessage && // we started in the middle not at the bottom - div.scrollHeight - div.scrollTop - div.clientHeight < magicZone && // we are scrolled right to the bottom - latest.messageTable && - !latest.messageTable.final && // there is more data to come - latest.messageTable.extendForwards) { - let scrollTop = div.scrollTop - console.log('infinite scroll: adding below: bottom: ' + (div.scrollHeight - div.scrollTop - div.clientHeight)) + while ( + options.selectedMessage && // we started in the middle not at the bottom + div.scrollHeight - div.scrollTop - div.clientHeight < magicZone && // we are scrolled right to the bottom + latest.messageTable && + !latest.messageTable.final && // there is more data to come + latest.messageTable.extendForwards + ) { + const scrollTop = div.scrollTop + console.log( + 'infinite scroll: adding below: bottom: ' + + (div.scrollHeight - div.scrollTop - div.clientHeight) + ) done = await latest.messageTable.extendForwards() // then add more data on the bottom if (freeze) { div.scrollTop = scrollTop // while adding below keep same things in view @@ -621,13 +772,13 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { async function go () { function yank () { - selectedMessageTable.selectedElement.scrollIntoView({block: 'center'}) + selectedMessageTable.selectedElement.scrollIntoView({ block: 'center' }) } // During initial load ONLY keep scroll to selected thing or bottom function fixScroll () { if (options.selectedElement) { - options.selectedElement.scrollIntoView({block: 'center'}) // allign tops or bopttoms + options.selectedElement.scrollIntoView({ block: 'center' }) // allign tops or bopttoms } else { liveMessageTable.inputRow.scrollIntoView(newestFirst) // allign tops or bopttoms } @@ -648,7 +799,8 @@ export function infiniteMessageArea (dom, kb, chatChannel, options) { latest.messageTable = selectedMessageTable yank() setTimeout(yank, 1000) // @@ kludge - restore position distubed by other cHANGES - } else { // Live end + } else { + // Live end await appendCurrentMessages() earliest.messageTable = liveMessageTable latest.messageTable = liveMessageTable diff --git a/src/chat/message.js b/src/chat/message.js index 0547a3b5d..26fe08edf 100644 --- a/src/chat/message.js +++ b/src/chat/message.js @@ -1,3 +1,4 @@ +/* global $rdf */ import { messageToolbar, sentimentStripLinked } from './messageTools' const UI = { @@ -24,15 +25,18 @@ const messageBodyStyle = UI.style.messageBodyStyle const label = UI.utils.label export function elementForImageURI (imageUri, options) { - let img = dom.createElement('img') + const img = dom.createElement('img') let height = '10' if (options.inlineImageHeightEms) { height = ('' + options.inlineImageHeightEms).trim() } - img.setAttribute('style', 'max-height: ' + height + 'em; border-radius: 1em; margin: 0.7em;') + img.setAttribute( + 'style', + 'max-height: ' + height + 'em; border-radius: 1em; margin: 0.7em;' + ) // UI.widgets.makeDropTarget(img, handleURIsDroppedOnMugshot, droppedFileHandler) if (imageUri) img.setAttribute('src', imageUri) - let anchor = dom.createElement('a') + const anchor = dom.createElement('a') anchor.setAttribute('href', imageUri) anchor.setAttribute('target', 'images') anchor.appendChild(img) @@ -40,7 +44,8 @@ export function elementForImageURI (imageUri, options) { return anchor } -var anchor = function (text, term) { // If there is no link return an element anyway +var anchor = function (text, term) { + // If there is no link return an element anyway var a = dom.createElement('a') if (term && term.uri) { a.setAttribute('href', term.uri) @@ -60,7 +65,10 @@ function nick (person) { export function creatorAndDate (td1, creator, date, message) { var nickAnchor = td1.appendChild(anchor(nick(creator), creator)) if (creator.uri) { - UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function (ok, body) { + UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function ( + _ok, + _body + ) { nickAnchor.textContent = nick(creator) }) } @@ -71,7 +79,10 @@ export function creatorAndDate (td1, creator, date, message) { export function creatorAndDateHorizontal (td1, creator, date, message) { var nickAnchor = td1.appendChild(anchor(label(creator), creator)) if (creator.uri) { - UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function (ok, body) { + UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function ( + _ok, + _body + ) { nickAnchor.textContent = nick(creator) }) } @@ -83,8 +94,15 @@ export function creatorAndDateHorizontal (td1, creator, date, message) { // BODY of renderMessage -export function renderMessage (messageTable, bindings, fresh, options, userContext) { - var colorizeByAuthor = options.colorizeByAuthor === '1' || options.colorizeByAuthor === true +export function renderMessage ( + messageTable, + bindings, + fresh, + options, + userContext +) { + var colorizeByAuthor = + options.colorizeByAuthor === '1' || options.colorizeByAuthor === true var creator = bindings['?creator'] var message = bindings['?msg'] @@ -104,12 +122,15 @@ export function renderMessage (messageTable, bindings, fresh, options, userConte var done = false for (var ele = messageTable.firstChild; ; ele = ele.nextSibling) { - if (!ele) { // empty + if (!ele) { + // empty break } var newestFirst = options.newestfirst === true - if (((dateString > ele.AJAR_date) && newestFirst) || - ((dateString < ele.AJAR_date) && !newestFirst)) { + if ( + (dateString > ele.AJAR_date && newestFirst) || + (dateString < ele.AJAR_date && !newestFirst) + ) { messageTable.insertBefore(messageRow, ele) done = true break @@ -122,8 +143,11 @@ export function renderMessage (messageTable, bindings, fresh, options, userConte var td1 = dom.createElement('td') messageRow.appendChild(td1) if (options.authorAboveContent) { - let img = dom.createElement('img') - img.setAttribute('style', 'max-height: 2.5em; max-width: 2.5em; border-radius: 0.5em; margin: auto;') + const img = dom.createElement('img') + img.setAttribute( + 'style', + 'max-height: 2.5em; max-width: 2.5em; border-radius: 0.5em; margin: auto;' + ) UI.widgets.setImage(img, creator) td1.appendChild(img) } else { @@ -134,34 +158,49 @@ export function renderMessage (messageTable, bindings, fresh, options, userConte var td2 = messageRow.appendChild(dom.createElement('td')) if (options.authorAboveContent) { - creatorAndDateHorizontal(td2, creator, UI.widgets.shortDate(dateString), message) + creatorAndDateHorizontal( + td2, + creator, + UI.widgets.shortDate(dateString), + message + ) } - let text = content.value.trim() - let isURI = (/^https?:\/[^ <>]*$/i).test(text) + const text = content.value.trim() + const isURI = /^https?:\/[^ <>]*$/i.test(text) let para = null if (isURI) { - var isImage = (/\.(gif|jpg|jpeg|tiff|png|svg)$/i).test(text) // @@ Should use content-type not URI + var isImage = /\.(gif|jpg|jpeg|tiff|png|svg)$/i.test(text) // @@ Should use content-type not URI if (isImage && options.expandImagesInline) { - let img = elementForImageURI(text, options) + const img = elementForImageURI(text, options) td2.appendChild(img) - } else { // Link but not Image - let anc = td2.appendChild(dom.createElement('a')) + } else { + // Link but not Image + const anc = td2.appendChild(dom.createElement('a')) para = anc.appendChild(dom.createElement('p')) anc.href = text para.textContent = text td2.appendChild(anc) } - } else { // text + } else { + // text para = dom.createElement('p') td2.appendChild(para) para.textContent = text } if (para) { var bgcolor = colorizeByAuthor - ? UI.pad.lightColorHash(creator) - : (fresh ? '#e8ffe8' : 'white') - para.setAttribute('style', messageBodyStyle + 'background-color: ' + bgcolor + ';') + ? UI.pad.lightColorHash(creator) + : getBgColor(fresh) + para.setAttribute( + 'style', + messageBodyStyle + 'background-color: ' + bgcolor + ';' + ) } + + function getBgColor (fresh) { + return fresh ? '#e8ffe8' : 'white' + } + // Sentiment strip const strip = sentimentStripLinked(message, message.doc()) if (strip.children.length) { @@ -172,17 +211,23 @@ export function renderMessage (messageTable, bindings, fresh, options, userConte // Message tool bar button var td3 = dom.createElement('td') messageRow.appendChild(td3) - var toolsButton = UI.widgets.button(dom, UI.icons.iconBase + 'noun_243787.svg', '...') + var toolsButton = UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_243787.svg', + '...' + ) td3.appendChild(toolsButton) - toolsButton.addEventListener('click', function (e) { - if (messageRow.toolTR) { // already got a toolbar? Toogle + toolsButton.addEventListener('click', function (_event) { + if (messageRow.toolTR) { + // already got a toolbar? Toogle messageRow.parentNode.removeChild(messageRow.toolTR) delete messageRow.toolTR return } const toolsTR = dom.createElement('tr') const tools = messageToolbar(message, messageRow, userContext) - tools.style = 'border: 0.05em solid #888; border-radius: 0 0 0.7em 0.7em; border-top: 0; height:3.5em; background-color: #fff;' // @@ fix + tools.style = + 'border: 0.05em solid #888; border-radius: 0 0 0.7em 0.7em; border-top: 0; height:3.5em; background-color: #fff;' // @@ fix if (messageRow.nextSibling) { messageRow.parentElement.insertBefore(toolsTR, messageRow.nextSibling) } else { diff --git a/src/chat/messageTools.js b/src/chat/messageTools.js index 93912bb6d..35328525f 100644 --- a/src/chat/messageTools.js +++ b/src/chat/messageTools.js @@ -1,10 +1,11 @@ +/* global $rdf */ /* Tools for doing things with a message * Let is be cretiev here. Allow all sorts of things to * be done to a message - linking to new or old objects in an open way * * Ideas: Bookmark, Like, star, pin at top of chat, reply as new thread, * If you made it originally: edit, delete, attach -*/ + */ const UI = { authn: require('../signin'), @@ -55,7 +56,7 @@ function updatePromise (del, ins) { } /* Emoji in Unicode -*/ + */ var emoji = {} emoji[ns.schema('AgreeAction')] = '👍' @@ -64,7 +65,7 @@ emoji[ns.schema('EndorseAction')] = '⭐️' emoji[ns.schema('LikeAction')] = '❤️' /* Strip of sentiments expressed -*/ + */ export function sentimentStrip (target, doc) { const actions = kb.each(null, ns.schema('target'), target, doc) const sentiments = actions.map(a => kb.any(a, ns.rdf('type'), null, doc)) @@ -76,7 +77,7 @@ export function sentimentStrip (target, doc) { * * @param target {NamedNode} - The thing about which they are expressed * @param doc {NamedNode} - The document iun which they are expressed -*/ + */ export function sentimentStripLinked (target, doc) { var strip = dom.createElement('span') @@ -85,10 +86,11 @@ export function sentimentStripLinked (target, doc) { const actions = kb.each(null, ns.schema('target'), target, doc) const sentiments = actions.map(a => [ kb.any(a, ns.rdf('type'), null, doc), - kb.any(a, ns.schema('agent'), null, doc)]) + kb.any(a, ns.schema('agent'), null, doc) + ]) sentiments.sort() sentiments.forEach(ss => { - let [klass, agent] = ss + const [klass, agent] = ss var res if (agent) { res = dom.createElement('a') @@ -115,14 +117,19 @@ export function messageToolbar (message, messageRow, userContext) { await updatePromise(kb.connectedStatements(x), []) } - // Things only the original author can do + // Things only the original author can do let me = UI.authn.currentUser() // If already logged on if (me && kb.holds(message, ns.foaf('maker'), me)) { - // button to delete the message - const deleteButton = UI.widgets.deleteButtonWithCheck(dom, div, 'message', async function () { - await kb.updater.update(kb.connectedStatements[message], []) - closeToolbar() - }) + // button to delete the message + const deleteButton = UI.widgets.deleteButtonWithCheck( + dom, + div, + 'message', + async function () { + await kb.updater.update(kb.connectedStatements[message], []) + closeToolbar() + } + ) div.appendChild(deleteButton) } // if mine @@ -133,60 +140,75 @@ export function messageToolbar (message, messageRow, userContext) { div.appendChild(bookmarkButton) } */ - // Things anyone can do if they have a bookmark list + // Things anyone can do if they have a bookmark list - bookmarks.renderBookmarksButton(userContext).then((bookmarkButton) => { + bookmarks.renderBookmarksButton(userContext).then(bookmarkButton => { if (bookmarkButton) div.appendChild(bookmarkButton) }) - /** Button to allow user to express a sentiment (like, endorse, etc) about a target - * - * @param context {Object} - Provide dom and me - * @param target {NamedNode} - The thing the user expresses an opnion about - * @param icon {uristring} - The icon to be used for the button - * @param actionClass {NamedNode} - The RDF class - typically a subclass of schema:Action - * @param doc - {NamedNode} - the Solid document iunto which the data should be written - * @param mutuallyExclusive {Array} - Any RDF classes of sentimentswhich are mutiually exclusive + /** Button to allow user to express a sentiment (like, endorse, etc) about a target + * + * @param context {Object} - Provide dom and me + * @param target {NamedNode} - The thing the user expresses an opnion about + * @param icon {uristring} - The icon to be used for the button + * @param actionClass {NamedNode} - The RDF class - typically a subclass of schema:Action + * @param doc - {NamedNode} - the Solid document iunto which the data should be written + * @param mutuallyExclusive {Array} - Any RDF classes of sentimentswhich are mutiually exclusive */ - function sentimentButton (context, target, icon, actionClass, doc, mutuallyExclusive) { + function sentimentButton ( + context, + target, + icon, + actionClass, + doc, + mutuallyExclusive + ) { function setColor () { button.style.backgroundColor = action ? 'yellow' : 'white' } - var button = UI.widgets.button(dom, icon, UI.utils.label(actionClass), async function (event) { - if (action) { - await deleteThingThen(action) - action = null - setColor() - } else { // no action - action = UI.widgets.newThing(doc) - var insertMe = [ - $rdf.st(action, ns.schema('agent'), context.me, doc), - $rdf.st(action, ns.rdf('type'), actionClass, doc), - $rdf.st(action, ns.schema('target'), target, doc) - ] - await updatePromise([], insertMe) - setColor() - - if (mutuallyExclusive) { // Delete incompative sentiments - var dirty = false - for (let i = 0; i < mutuallyExclusive.length; i++) { - let a = existingAction(mutuallyExclusive[i]) - if (a) { - await deleteThingThen(a) // but how refresh? refreshTree the parent? - dirty = true + var button = UI.widgets.button( + dom, + icon, + UI.utils.label(actionClass), + async function (_event) { + if (action) { + await deleteThingThen(action) + action = null + setColor() + } else { + // no action + action = UI.widgets.newThing(doc) + var insertMe = [ + $rdf.st(action, ns.schema('agent'), context.me, doc), + $rdf.st(action, ns.rdf('type'), actionClass, doc), + $rdf.st(action, ns.schema('target'), target, doc) + ] + await updatePromise([], insertMe) + setColor() + + if (mutuallyExclusive) { + // Delete incompative sentiments + var dirty = false + for (let i = 0; i < mutuallyExclusive.length; i++) { + const a = existingAction(mutuallyExclusive[i]) + if (a) { + await deleteThingThen(a) // but how refresh? refreshTree the parent? + dirty = true + } + } + if (dirty) { + // UI.widgets.refreshTree(button.parentNode) // requires them all to be immediate siblings + UI.widgets.refreshTree(messageRow) // requires them all to be immediate siblings } - } - if (dirty) { - // UI.widgets.refreshTree(button.parentNode) // requires them all to be immediate siblings - UI.widgets.refreshTree(messageRow) // requires them all to be immediate siblings } } } - }) + ) function existingAction (actionClass) { - var actions = kb.each(null, ns.schema('agent'), context.me, doc) - .filter(x => kb.holds(x, ns.rdf('type'), actionClass, doc)) - .filter(x => kb.holds(x, ns.schema('target'), target, doc)) + var actions = kb + .each(null, ns.schema('agent'), context.me, doc) + .filter(x => kb.holds(x, ns.rdf('type'), actionClass, doc)) + .filter(x => kb.holds(x, ns.schema('target'), target, doc)) return actions.length ? actions[0] : null } function refresh () { @@ -199,26 +221,35 @@ export function messageToolbar (message, messageRow, userContext) { return button } - // THUMBS_UP_ICON - // https://schema.org/AgreeAction + // THUMBS_UP_ICON + // https://schema.org/AgreeAction me = UI.authn.currentUser() // If already logged on - if (me) { // Things yo mnust be logged in fo - var context1 = {me, dom, div} - div.appendChild(sentimentButton(context1, message, // @@ use UI.widgets.sentimentButton - UI.icons.iconBase + THUMBS_UP_ICON, - ns.schema('AgreeAction'), - message.doc(), - [ns.schema('DisagreeAction')] - )) - // Thumbs down - div.appendChild(sentimentButton(context1, message, - UI.icons.iconBase + THUMBS_DOWN_ICON, - ns.schema('DisagreeAction'), + if (me) { + // Things yo mnust be logged in fo + var context1 = { me, dom, div } + div.appendChild( + sentimentButton( + context1, + message, // @@ use UI.widgets.sentimentButton + UI.icons.iconBase + THUMBS_UP_ICON, + ns.schema('AgreeAction'), + message.doc(), + [ns.schema('DisagreeAction')] + ) + ) + // Thumbs down + div.appendChild( + sentimentButton( + context1, + message, + UI.icons.iconBase + THUMBS_DOWN_ICON, + ns.schema('DisagreeAction'), message.doc(), [ns.schema('AgreeAction')] - )) + ) + ) } - // X button to remove the tool UI itself + // X button to remove the tool UI itself const cancelButton = div.appendChild(UI.widgets.cancelButton(dom)) cancelButton.style.float = 'right' cancelButton.firstChild.style.opacity = '0.3' diff --git a/src/chat/thread.js b/src/chat/thread.js index 9ef44200b..8364e1cda 100644 --- a/src/chat/thread.js +++ b/src/chat/thread.js @@ -1,3 +1,4 @@ +/* global $rdf */ // Common code for a discussion are a of messages about something // var UI = { @@ -27,7 +28,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { var newestFirst = !!options.newestFirst - var messageBodyStyle = 'white-space: pre-wrap; width: 90%; font-size:100%; border: 0.07em solid #eee; padding: .2em 0.5em; margin: 0.1em 1em 0.1em 1em;' + var messageBodyStyle = + 'white-space: pre-wrap; width: 90%; font-size:100%; border: 0.07em solid #eee; padding: .2em 0.5em; margin: 0.1em 1em 0.1em 1em;' // 'font-size: 100%; margin: 0.1em 1em 0.1em 1em; background-color: white; white-space: pre-wrap; padding: 0.1em;' var div = dom.createElement('div') @@ -37,7 +39,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { var updater = UI.store.updater - var anchor = function (text, term) { // If there is no link return an element anyway + var anchor = function (text, term) { + // If there is no link return an element anyway var a = dom.createElement('a') if (term && term.uri) { a.setAttribute('href', term.uri) @@ -57,9 +60,15 @@ module.exports = function (dom, kb, subject, messageStore, options) { } var announce = { - log: function (message) { mention(message, 'color: #111;') }, - warn: function (message) { mention(message, 'color: #880;') }, - error: function (message) { mention(message, 'color: #800;') } + log: function (message) { + mention(message, 'color: #111;') + }, + warn: function (message) { + mention(message, 'color: #880;') + }, + error: function (message) { + mention(message, 'color: #800;') + } } // Form for a new message @@ -86,21 +95,39 @@ module.exports = function (dom, kb, subject, messageStore, options) { // http://www.w3schools.com/jsref/jsref_obj_date.asp var message = kb.sym(messageStore.uri + '#' + 'Msg' + timestamp) - sts.push(new $rdf.Statement(subject, ns.wf('message'), message, messageStore)) + sts.push( + new $rdf.Statement(subject, ns.wf('message'), message, messageStore) + ) // sts.push(new $rdf.Statement(message, ns.dc('title'), kb.literal(titlefield.value), messageStore)) - sts.push(new $rdf.Statement(message, ns.sioc('content'), kb.literal(field.value), messageStore)) - sts.push(new $rdf.Statement(message, DCT('created'), dateStamp, messageStore)) - if (me) sts.push(new $rdf.Statement(message, ns.foaf('maker'), me, messageStore)) + sts.push( + new $rdf.Statement( + message, + ns.sioc('content'), + kb.literal(field.value), + messageStore + ) + ) + sts.push( + new $rdf.Statement(message, DCT('created'), dateStamp, messageStore) + ) + if (me) { + sts.push( + new $rdf.Statement(message, ns.foaf('maker'), me, messageStore) + ) + } var sendComplete = function (uri, success, body) { if (!success) { - form.appendChild(UI.widgets.errorMessageBlock( - dom, 'Error writing message: ' + body)) + form.appendChild( + UI.widgets.errorMessageBlock(dom, 'Error writing message: ' + body) + ) } else { - var bindings = { '?msg': message, + var bindings = { + '?msg': message, '?content': kb.literal(field.value), '?date': dateStamp, - '?creator': me} + '?creator': me + } renderMessage(bindings, false) // not green field.value = '' // clear from out for reuse @@ -123,22 +150,32 @@ module.exports = function (dom, kb, subject, messageStore, options) { // field.cols = 40 field.setAttribute('style', messageBodyStyle + 'background-color: #eef;') - field.addEventListener('keyup', function (e) { // User preference? - if (e.keyCode === 13) { - if (!e.altKey) { // Alt-Enter just adds a new line - sendMessage() + field.addEventListener( + 'keyup', + function (e) { + // User preference? + if (e.keyCode === 13) { + if (!e.altKey) { + // Alt-Enter just adds a new line + sendMessage() + } } - } - }, false) + }, + false + ) rhs.innerHTML = '' - sendButton = UI.widgets.button(dom, UI.icons.iconBase + 'noun_383448.svg', 'Send') + sendButton = UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_383448.svg', + 'Send' + ) sendButton.setAttribute('style', UI.style.buttonStyle + 'float: right;') sendButton.addEventListener('click', sendMessage, false) rhs.appendChild(sendButton) } - let context = {div: middle, dom: dom} + const context = { div: middle, dom: dom } UI.authn.logIn(context).then(context => { me = context.me turnOnInput() @@ -156,7 +193,10 @@ module.exports = function (dom, kb, subject, messageStore, options) { function creatorAndDate (td1, creator, date, message) { var nickAnchor = td1.appendChild(anchor(nick(creator), creator)) if (creator.uri) { - UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function (ok, body) { + UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function ( + _ok, + _body + ) { nickAnchor.textContent = nick(creator) }) } @@ -183,7 +223,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { } }) - for (ele = messageTable.firstChild; ele;) { + // eslint-disable-next-line space-in-parens + for (ele = messageTable.firstChild; ele; ) { ele2 = ele.nextSibling if (ele.AJAR_subject && !stored[ele.AJAR_subject.uri]) { messageTable.removeChild(ele) @@ -193,8 +234,9 @@ module.exports = function (dom, kb, subject, messageStore, options) { } var deleteMessage = function (message) { - var deletions = kb.statementsMatching(message).concat( - kb.statementsMatching(undefined, undefined, message)) + var deletions = kb + .statementsMatching(message) + .concat(kb.statementsMatching(undefined, undefined, message)) updater.update(deletions, [], function (uri, ok, body) { if (!ok) { announce.error('Cant delete messages:' + body) @@ -227,11 +269,14 @@ module.exports = function (dom, kb, subject, messageStore, options) { var done = false for (var ele = messageTable.firstChild; ; ele = ele.nextSibling) { - if (!ele) { // empty + if (!ele) { + // empty break } - if (((dateString > ele.AJAR_date) && newestFirst) || - ((dateString < ele.AJAR_date) && !newestFirst)) { + if ( + (dateString > ele.AJAR_date && newestFirst) || + (dateString < ele.AJAR_date && !newestFirst) + ) { messageTable.insertBefore(tr, ele) done = true break @@ -248,8 +293,11 @@ module.exports = function (dom, kb, subject, messageStore, options) { var td2 = dom.createElement('td') tr.appendChild(td2) var pre = dom.createElement('p') - pre.setAttribute('style', messageBodyStyle + - (fresh ? 'background-color: #e8ffe8;' : 'background-color: #white;')) + pre.setAttribute( + 'style', + messageBodyStyle + + (fresh ? 'background-color: #e8ffe8;' : 'background-color: #white;') + ) td2.appendChild(pre) pre.textContent = content.value @@ -263,23 +311,35 @@ module.exports = function (dom, kb, subject, messageStore, options) { tr.setAttribute('class', 'hoverControl') // See tabbedtab.css (sigh global CSS) delButton.setAttribute('class', 'hoverControlHide') delButton.setAttribute('style', 'color: red;') - delButton.addEventListener('click', function (e) { - td3.removeChild(delButton) // Ask -- are you sure? - var cancelButton = dom.createElement('button') - cancelButton.textContent = 'cancel' - td3.appendChild(cancelButton).addEventListener('click', function (e) { - td3.removeChild(sureButton) - td3.removeChild(cancelButton) - td3.appendChild(delButton) - }, false) - var sureButton = dom.createElement('button') - sureButton.textContent = 'Delete message' - td3.appendChild(sureButton).addEventListener('click', function (e) { - td3.removeChild(sureButton) - td3.removeChild(cancelButton) - deleteMessage(message) - }, false) - }, false) + delButton.addEventListener( + 'click', + function (_event) { + td3.removeChild(delButton) // Ask -- are you sure? + var cancelButton = dom.createElement('button') + cancelButton.textContent = 'cancel' + td3.appendChild(cancelButton).addEventListener( + 'click', + function (_event) { + td3.removeChild(sureButton) + td3.removeChild(cancelButton) + td3.appendChild(delButton) + }, + false + ) + var sureButton = dom.createElement('button') + sureButton.textContent = 'Delete message' + td3.appendChild(sureButton).addEventListener( + 'click', + function (_event) { + td3.removeChild(sureButton) + td3.removeChild(cancelButton) + deleteMessage(message) + }, + false + ) + }, + false + ) } // Messages with date, author etc @@ -305,12 +365,12 @@ module.exports = function (dom, kb, subject, messageStore, options) { var v = {} // semicolon needed var vs = ['msg', 'date', 'creator', 'content'] vs.map(function (x) { - query.vars.push(v[x] = $rdf.variable(x)) + query.vars.push((v[x] = $rdf.variable(x))) }) - query.pat.add(subject, WF('message'), v['msg']) - query.pat.add(v['msg'], ns.dct('created'), v['date']) - query.pat.add(v['msg'], ns.foaf('maker'), v['creator']) - query.pat.add(v['msg'], ns.sioc('content'), v['content']) + query.pat.add(subject, WF('message'), v.msg) + query.pat.add(v.msg, ns.dct('created'), v.date) + query.pat.add(v.msg, ns.foaf('maker'), v.creator) + query.pat.add(v.msg, ns.sioc('content'), v.content) } function doneQuery () { messageTable.fresh = true // any new are fresh and so will be greenish diff --git a/src/create.js b/src/create.js index cb62f1d02..6419ff55e 100644 --- a/src/create.js +++ b/src/create.js @@ -1,6 +1,6 @@ /* create.js UI to craete new objects in the solid-app-set world -** -*/ + ** + */ // const error = require('./widgets/error') // const widgets = require('./widgets/index') // const utils = require('./utils') @@ -25,16 +25,18 @@ module.exports = { } /* newThingUI -- return UI for user to select a new object, folder, etc -** -** context must include: dom, div, -** optional: folder: NamedNode -- the folder where the thing is bring put -** (suppresses asking for a full URI or workspace) -** -*/ + ** + ** context must include: dom, div, + ** optional: folder: NamedNode -- the folder where the thing is bring put + ** (suppresses asking for a full URI or workspace) + ** + */ function newThingUI (context, thePanes) { const dom = context.dom const div = context.div - if (context.me && !context.me.uri) throw new Error('newThingUI: Invalid userid: ' + context.me) + if (context.me && !context.me.uri) { + throw new Error('newThingUI: Invalid userid: ' + context.me) + } var iconStyle = 'padding: 0.7em; width: 2em; height: 2em;' // was: 'padding: 1em; width: 3em; height: 3em;' var star = div.appendChild(dom.createElement('img')) @@ -51,9 +53,12 @@ function newThingUI (context, thePanes) { pre.appendChild(dom.createTextNode(message)) } - var selectNewTool = function (event) { + var selectNewTool = function (_event) { visible = !visible - star.setAttribute('style', iconStyle + (visible ? 'background-color: yellow;' : '')) + star.setAttribute( + 'style', + iconStyle + (visible ? 'background-color: yellow;' : '') + ) styleTheIcons(visible ? '' : 'display: none;') } @@ -63,61 +68,92 @@ function newThingUI (context, thePanes) { return new Promise(function (resolve, reject) { var selectUI // , selectUIParent function callbackWS (ws, newBase) { - UI.authn.logInLoadProfile(context).then(context => { - var newPaneOptions = { - newBase: newBase, - workspace: ws - } - for (var opt in options) { // get div, dom, me, folder, pane, refreshTable - newPaneOptions[opt] = options[opt] - } - console.log('newThingUI: Minting new ' + newPaneOptions.pane.name + ' at ' + newPaneOptions.newBase) - options.pane.mintNew(newPaneOptions) - .then(function (newPaneOptions) { - if (!newPaneOptions || !newPaneOptions.newInstance) { - throw new Error('Cannot mint new - missing newInstance') - } - if (newPaneOptions.folder) { - var tail = newPaneOptions.newInstance.uri.slice(newPaneOptions.folder.uri.length) - const isPackage = tail.includes('/') - console.log(' new thing is packge? ' + isPackage) - if (isPackage) { - kb.add(newPaneOptions.folder, UI.ns.ldp('contains'), kb.sym(newPaneOptions.newBase), - newPaneOptions.folder.doc()) - } else { // single file - kb.add(newPaneOptions.folder, UI.ns.ldp('contains'), newPaneOptions.newInstance, - newPaneOptions.folder.doc()) // Ping the patch system? - } - if (newPaneOptions.refreshTarget) { - newPaneOptions.refreshTarget.refresh() // Refresh the cntaining display + UI.authn.logInLoadProfile(context).then( + _context => { + var newPaneOptions = { + newBase: newBase, + workspace: ws + } + for (var opt in options) { + // get div, dom, me, folder, pane, refreshTable + newPaneOptions[opt] = options[opt] + } + console.log( + 'newThingUI: Minting new ' + + newPaneOptions.pane.name + + ' at ' + + newPaneOptions.newBase + ) + options.pane + .mintNew(newPaneOptions) + .then(function (newPaneOptions) { + if (!newPaneOptions || !newPaneOptions.newInstance) { + throw new Error('Cannot mint new - missing newInstance') } - // selectUI.parentNode.removeChild(selectUI) It removes itself - } else { - var p = options.div.appendChild(dom.createElement('p')) - p.setAttribute('style', 'font-size: 120%;') - // Make link to new thing - p.innerHTML = - "Your new " + options.noun + ' is ready to be set up. ' + - "

Go to your new " + options.noun + '.' + if (newPaneOptions.folder) { + var tail = newPaneOptions.newInstance.uri.slice( + newPaneOptions.folder.uri.length + ) + const isPackage = tail.includes('/') + console.log(' new thing is packge? ' + isPackage) + if (isPackage) { + kb.add( + newPaneOptions.folder, + UI.ns.ldp('contains'), + kb.sym(newPaneOptions.newBase), + newPaneOptions.folder.doc() + ) + } else { + // single file + kb.add( + newPaneOptions.folder, + UI.ns.ldp('contains'), + newPaneOptions.newInstance, + newPaneOptions.folder.doc() + ) // Ping the patch system? + } + if (newPaneOptions.refreshTarget) { + newPaneOptions.refreshTarget.refresh() // Refresh the cntaining display + } + // selectUI.parentNode.removeChild(selectUI) It removes itself + } else { + var p = options.div.appendChild(dom.createElement('p')) + p.setAttribute('style', 'font-size: 120%;') + // Make link to new thing + p.innerHTML = + "Your new " + + options.noun + + ' is ready to be set up. ' + + "

Go to your new " + + options.noun + + '.' // selectUI.parentNode.removeChild(selectUI) // Clean up - // selectUIParent.removeChild(selectUI) // Clean up - } - selectNewTool() // toggle star to plain and menu vanish again - }) - .catch(function (err) { - complain(err) - reject(err) - }) - }, err => { // login fails - complain('Error logging on: ' + err) - }) + // selectUIParent.removeChild(selectUI) // Clean up + } + selectNewTool() // toggle star to plain and menu vanish again + }) + .catch(function (err) { + complain(err) + reject(err) + }) + }, + err => { + // login fails + complain('Error logging on: ' + err) + } + ) } // callbackWS var pa = options.pane options.appPathSegment = 'edu.mit.solid.pane.' + pa.name options.noun = pa.mintClass ? UI.utils.label(pa.mintClass) : pa.name - if (!options.folder) { // No folder given? Ask user for full URI + if (!options.folder) { + // No folder given? Ask user for full URI selectUI = UI.authn.selectWorkspace(dom, options, callbackWS) options.div.appendChild(selectUI) // selectUIParent = options.div @@ -135,13 +171,21 @@ function newThingUI (context, thePanes) { callbackWS(null, uri) } } - UI.widgets.askName(dom, UI.store, options.div, UI.ns.foaf('name'), null, options.noun).then(gotName) + UI.widgets + .askName( + dom, + UI.store, + options.div, + UI.ns.foaf('name'), + null, + options.noun + ) + .then(gotName) // selectUI = getNameForm(dom, UI.store, options.noun, gotName) // options.div.appendChild(selectUI) // selectUIParent = options.div } - } - ) + }) } // makeNewAppInstance const iconArray = [] @@ -156,10 +200,10 @@ function newThingUI (context, thePanes) { const icon = context.div.appendChild(dom.createElement('img')) icon.setAttribute('src', pane.icon) const noun = pane.mintClass - ? (mintingClassMap[pane.mintClass] > 1 + ? mintingClassMap[pane.mintClass] > 1 ? `${UI.utils.label(pane.mintClass)} (using ${pane.name} pane)` - : UI.utils.label(pane.mintClass)) - : (pane.name + ' @@') + : UI.utils.label(pane.mintClass) + : pane.name + ' @@' icon.setAttribute('title', 'Make new ' + noun) icon.setAttribute('style', iconStyle + 'display: none;') iconArray.push(icon) @@ -185,7 +229,8 @@ function newThingUI (context, thePanes) { var styleTheIcons = function (style) { for (var i = 0; i < iconArray.length; i++) { var st = iconStyle + style - if (iconArray[i].disabled) { // @@ unused + if (iconArray[i].disabled) { + // @@ unused st += 'opacity: 0.3;' } iconArray[i].setAttribute('style', st) // eg 'background-color: #ccc;' diff --git a/src/folders.js b/src/folders.js index 946ea0155..b84dda723 100644 --- a/src/folders.js +++ b/src/folders.js @@ -1,6 +1,6 @@ /** UI To Delete Folder and content -* -*/ + * + */ /* global confirm */ const UI = { icons: require('./iconBase'), @@ -16,9 +16,10 @@ const UI = { const ns = UI.ns function deleteRecursive (kb, folder) { - return new Promise(function (resolve, reject) { + // eslint-disable-next-line promise/param-names + return new Promise(function (resolve, _reject) { kb.fetcher.load(folder).then(function () { - let promises = kb.each(folder, ns.ldp('contains')).map(file => { + const promises = kb.each(folder, ns.ldp('contains')).map(file => { if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) { return deleteRecursive(kb, file) } else { @@ -34,7 +35,9 @@ function deleteRecursive (kb, folder) { throw new Error('User aborted delete file') } promises.push(kb.fetcher.webOperation('DELETE', folder.uri)) - Promise.all(promises).then(res => { resolve() }) + Promise.all(promises).then(_res => { + resolve() + }) }) }) } @@ -46,9 +49,10 @@ function deleteRecursive (kb, folder) { * @param action - returns a promise. All the promises must be resolved */ function forAllFiles (folder, kb, action) { - return new Promise(function (resolve, reject) { + // eslint-disable-next-line promise/param-names + return new Promise(function (resolve, _reject) { kb.fetcher.load(folder).then(function () { - let promises = kb.each(folder, ns.ldp('contains')).map(file => { + const promises = kb.each(folder, ns.ldp('contains')).map(file => { if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) { return forAllFiles(file, kb, action) } else { @@ -56,7 +60,9 @@ function forAllFiles (folder, kb, action) { } }) promises.push(action(folder)) - Promise.all(promises).then(res => { resolve() }) + Promise.all(promises).then(_res => { + resolve() + }) }) }) } @@ -64,13 +70,13 @@ function forAllFiles (folder, kb, action) { module.exports.deleteRecursive = deleteRecursive /** Delete Folder and contents -* + * * @param {NamedNode} folder - The LDP container to be deleted * @param {DOMElement} containingElement - Where to put the user interface * @param {IndexedForumula} store - Quadstore (optional) * @param {Document} dom - The browser 'document' gloabl or equivalent (or iuse global) * @returns {DOMElement} - The control which has eben inserted in the -*/ + */ /* global document */ module.exports.deleteFolder = function (folder, store, dom) { store = store || UI.store @@ -89,28 +95,42 @@ module.exports.deleteFolder = function (folder, store, dom) { buttonsTR.appendChild(dom.createElement('td')) // buttonsTD2 const buttonsTD3 = buttonsTR.appendChild(dom.createElement('td')) - let cancel = buttonsTD1.appendChild(UI.widgets.cancelButton(dom)) - cancel.addEventListener('click', function (e) { - div.parentNode.removeChild(div) - }, false) + const cancel = buttonsTD1.appendChild(UI.widgets.cancelButton(dom)) + cancel.addEventListener( + 'click', + function (_event) { + div.parentNode.removeChild(div) + }, + false + ) - let doit = buttonsTD3.appendChild(UI.widgets.button(UI.icons.iconBase + 'noun_925021.svg', 'Yes, delete')) - doit.addEventListener('click', function (e) { - deleteThem(folder).then(() => { - console.log('All deleted.') - }) - }, false) + const doit = buttonsTD3.appendChild( + UI.widgets.button(UI.icons.iconBase + 'noun_925021.svg', 'Yes, delete') + ) + doit.addEventListener( + 'click', + function (_event) { + deleteThem(folder).then(() => { + console.log('All deleted.') + }) + }, + false + ) function deleteThem (folder) { - return forAllFiles(folder, (file) => store.fetcher.webOperation('DELETE', file.uri)) + return forAllFiles(folder, file => + store.fetcher.webOperation('DELETE', file.uri) + ) } var count = 0 - forAllFiles(folder, store, () => { count += 1 }) // Count files - .then(() => { - let msg = ' Files to delete: ' + count - console.log(msg) - p.textContent += msg - }) + forAllFiles(folder, store, () => { + count += 1 + }) // Count files + .then(() => { + const msg = ' Files to delete: ' + count + console.log(msg) + p.textContent += msg + }) return div } diff --git a/src/iconBase.js b/src/iconBase.js index 98355b374..0bd945105 100644 --- a/src/iconBase.js +++ b/src/iconBase.js @@ -1,15 +1,24 @@ - +/* global $SolidTestEnvironment */ // Works in FF extension - what about browserify?? -if (module.scriptURI) { // FF extension - module.exports.iconBase = '' + - module.scriptURI.slice(0, module.scriptURI.lastIndexOf('/')) + '/icons/' - module.exports.originalIconBase = '' + - module.scriptURI.slice(0, module.scriptURI.lastIndexOf('/')) + '/originalIcons/' -} else { // Node or browserify +if (module.scriptURI) { + // FF extension + module.exports.iconBase = + '' + + module.scriptURI.slice(0, module.scriptURI.lastIndexOf('/')) + + '/icons/' + module.exports.originalIconBase = + '' + + module.scriptURI.slice(0, module.scriptURI.lastIndexOf('/')) + + '/originalIcons/' +} else { + // Node or browserify var iconsOnGithub = 'https://solid.github.io/solid-ui/src' - if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.iconBase) { + if ( + typeof $SolidTestEnvironment !== 'undefined' && + $SolidTestEnvironment.iconBase + ) { module.exports.iconBase = $SolidTestEnvironment.iconBase module.exports.originalIconBase = $SolidTestEnvironment.originalIconBase } else { diff --git a/src/index.ts b/src/index.ts index 9f986f72f..ac87e85c9 100755 --- a/src/index.ts +++ b/src/index.ts @@ -45,37 +45,37 @@ import * as acl from './acl' // @ts-ignore import * as aclControl from './acl-control' // @ts-ignore -import * as authn from "./signin" +import * as authn from './signin' // @ts-ignore -import * as create from "./create" +import * as create from './create' // @ts-ignore -import * as icons from "./iconBase" +import * as icons from './iconBase' // @ts-ignore -import * as log from "./log" +import * as log from './log' // @ts-ignore -import * as matrix from "./matrix" +import * as matrix from './matrix' // @ts-ignore -import * as media from "./media-capture" +import * as media from './media-capture' // @ts-ignore -import * as messageArea from "./messageArea" +import * as messageArea from './messageArea' // @ts-ignore -import { infiniteMessageArea } from "./chat/infinite" +import { infiniteMessageArea } from './chat/infinite' // @ts-ignore -import * as pad from "./pad" +import * as pad from './pad' // @ts-ignore -import * as preferences from "./preferences" +import * as preferences from './preferences' // @ts-ignore -import * as store from "./store" +import * as store from './store' // @ts-ignore -import * as style from "./style" +import * as style from './style' // @ts-ignore -import * as table from "./table" +import * as table from './table' // @ts-ignore -import * as tabs from "./tabs" +import * as tabs from './tabs' // @ts-ignore -import * as utils from "./utils" +import * as utils from './utils' // @ts-ignore -import * as widgets from "./widgets" +import * as widgets from './widgets' const UI = { ns, @@ -102,6 +102,6 @@ const UI = { } if (typeof window !== 'undefined') { - (window).UI = UI // Simpler access by non-node scripts + ;(window).UI = UI // Simpler access by non-node scripts } export default UI diff --git a/src/log.js b/src/log.js index 27d0a4ffe..79547cb76 100644 --- a/src/log.js +++ b/src/log.js @@ -28,27 +28,38 @@ var wrapper = function () { if (!(logger.level & type)) return // bitmask if (typeof document !== 'undefined') { -// Not AJAX environment + // Not AJAX environment var logArea = document.getElementById('status') if (!logArea) return // Local version to reduce dependencies - var escapeForXML = function (str) { // don't use library one in case ithasn't been loaded yet + var escapeForXML = function (str) { + // don't use library one in case ithasn't been loaded yet return str.replace(/&/g, '&').replace(/' + addendum.innerHTML = + now.getHours() + + ':' + + now.getMinutes() + + ':' + + now.getSeconds() + + ' [' + + typestr + + '] ' + + escapeForXML(str) + + '
' if (!logger.ascending) { logArea.appendChild(addendum) } else { logArea.insertBefore(addendum, logArea.firstChild) } - } else if (typeof console !== 'undefined') { // node.js + } else if (typeof console !== 'undefined') { + // node.js console.log(str) /* } else { @@ -59,11 +70,21 @@ var wrapper = function () { } } // logger.msg - logger.warn = function (msg) { logger.msg(msg, TWARN, 'warn') } - logger.debug = function (msg) { logger.msg(msg, TDEBUG, 'dbug') } - logger.info = function (msg) { logger.msg(msg, TINFO, 'info') } - logger.error = function (msg) { logger.msg(msg, TERROR, 'eror') } - logger.success = function (msg) { logger.msg(msg, TSUCCESS, 'good') } + logger.warn = function (msg) { + logger.msg(msg, TWARN, 'warn') + } + logger.debug = function (msg) { + logger.msg(msg, TDEBUG, 'dbug') + } + logger.info = function (msg) { + logger.msg(msg, TINFO, 'info') + } + logger.error = function (msg) { + logger.msg(msg, TERROR, 'eror') + } + logger.success = function (msg) { + logger.msg(msg, TSUCCESS, 'good') + } if (typeof alert !== 'undefined') { logger.alert = alert @@ -93,6 +114,6 @@ var wrapper = function () { logger.level = l } return logger -}// wrapper +} // wrapper module.exports = wrapper() diff --git a/src/matrix.js b/src/matrix.js index d0831b9c2..107bf34a4 100644 --- a/src/matrix.js +++ b/src/matrix.js @@ -1,3 +1,4 @@ +/* global $rdf */ // Build a 2D matrix of values // // dom AKA document @@ -32,7 +33,15 @@ var UI = { const utils = require('./utils') const kb = UI.store -module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, whenDone) { +module.exports.matrixForQuery = function ( + dom, + query, + vx, + vy, + vvalue, + options, + whenDone +) { var matrix = dom.createElement('table') var header = dom.createElement('tr') var corner = header.appendChild(dom.createElement('td')) @@ -43,7 +52,8 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w var rows = [] // Associative array var setCell = function (cell, x, y, value) { - while (cell.firstChild) { // Empty any previous + while (cell.firstChild) { + // Empty any previous cell.removeChild(cell.firstChild) } cell.setAttribute('style', '') @@ -66,18 +76,30 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w header.setAttribute('style', 'padding: 0.3em;') header.textContent = utils.label(y1) // first approximation if (y1.termType === 'NamedNode') { - kb.fetcher.nowOrWhenFetched(y1.uri.split('#')[0], undefined, function (ok, body, response) { + kb.fetcher.nowOrWhenFetched(y1.uri.split('#')[0], undefined, function ( + ok, + _body, + _response + ) { if (ok) header.textContent = utils.label(y1) }) } for (var i = 0; i < columns.length; i++) { - setCell(tr.appendChild(dom.createElement('td')), $rdf.fromNT(columns[i]), y1, null) + setCell( + tr.appendChild(dom.createElement('td')), + $rdf.fromNT(columns[i]), + y1, + null + ) } tr.dataValueNT = y rows[y] = tr - for (var ele = matrix.lastHeader.nextSibling; ele; ele = ele.nextSibling) { // skip header - if (((y > ele.dataValueNT) && options && options.yDecreasing) || - ((y < ele.dataValueNT) && !(options && options.yDecreasing))) { + for (var ele = matrix.lastHeader.nextSibling; ele; ele = ele.nextSibling) { + // skip header + if ( + (y > ele.dataValueNT && options && options.yDecreasing) || + (y < ele.dataValueNT && !(options && options.yDecreasing)) + ) { return matrix.insertBefore(tr, ele) // return the tr } } @@ -93,9 +115,14 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w return i } - if (((xNT > columns[i]) && options.xDecreasing) || - ((xNT < columns[i]) && !options.xDecreasing)) { - columns = columns.slice(0, i).concat([xNT]).concat(columns.slice(i)) + if ( + (xNT > columns[i] && options.xDecreasing) || + (xNT < columns[i] && !options.xDecreasing) + ) { + columns = columns + .slice(0, i) + .concat([xNT]) + .concat(columns.slice(i)) col = i break } @@ -107,7 +134,8 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w } // col is the number of the new column, starting from 0 - for (var row = matrix.firstChild; row; row = row.nextSibling) { // For every row header or not + for (var row = matrix.firstChild; row; row = row.nextSibling) { + // For every row header or not var y = row.dataValueNT var td = dom.createElement('td') // Add a new cell td.style.textAlign = 'center' @@ -120,7 +148,8 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w row.appendChild(td) } else { var t = row.firstChild - for (var j = 0; j < col + 1; j++) { // Skip header col too + for (var j = 0; j < col + 1; j++) { + // Skip header col too t = t.nextSibling } row.insertBefore(td, t) @@ -143,7 +172,8 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w var colsUsed = [] var rowsUsed = [] - if (options.set_y) { // Knows y values create rows + if (options.set_y) { + // Knows y values create rows for (var k = 0; k < options.set_y.length; k++) { rowsUsed[options.set_y[k]] = true } @@ -175,8 +205,9 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w delete rows[row.dataValueNT] matrix.removeChild(row) } else { - for (var j = row.children.length - 1; j > 0; j--) { // backwards - let cell = row.children[j] + for (var j = row.children.length - 1; j > 0; j--) { + // backwards + const cell = row.children[j] if (!colsUsed[j]) { row.removeChild(cell) } @@ -207,7 +238,8 @@ module.exports.matrixForQuery = function (dom, query, vx, vy, vvalue, options, w setCell(cell, x, y, value) } - if (options.set_y) { // Knows y values create rows + if (options.set_y) { + // Knows y values create rows for (var k = 0; k < options.set_y.length; k++) { rowFor(options.set_y[k]) } diff --git a/src/media-capture.js b/src/media-capture.js index 501b8bdd6..bf562c639 100644 --- a/src/media-capture.js +++ b/src/media-capture.js @@ -1,4 +1,3 @@ - /// ///////////////////////////////////////////// // // Media input widget @@ -18,7 +17,7 @@ /** @module mediaCapture */ var $rdf = require('rdflib') -var media = module.exports = {} +var media = (module.exports = {}) var UI = { icons: require('./iconBase'), @@ -49,7 +48,12 @@ const contentType = 'image/png' * @param {NamedNode} getImageDoc() - NN of the image file to be created * @param {function} doneCallback - Called when a picture has been taken */ -module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, getImageDoc, doneCallback) { +module.exports.cameraCaptureControl = function cameraCaptureControl ( + dom, + store, + getImageDoc, + doneCallback +) { const div = dom.createElement('div') var destination, imageBlob, player, canvas @@ -60,28 +64,34 @@ module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, const buttons = table.appendChild(dom.createElement('tr')) - buttons.appendChild(dom.createElement('td')) // Cancel button - .appendChild(UI.widgets.cancelButton(dom)) - .addEventListener('click', e => { - stopVideo() - doneCallback(null) - }) + buttons + .appendChild(dom.createElement('td')) // Cancel button + .appendChild(UI.widgets.cancelButton(dom)) + .addEventListener('click', _event => { + stopVideo() + doneCallback(null) + }) - const retakeButton = buttons.appendChild(dom.createElement('td')) // Retake button - .appendChild(UI.widgets.button(dom, retakeIcon, 'Retake')) - retakeButton.addEventListener('click', e => { + const retakeButton = buttons + .appendChild(dom.createElement('td')) // Retake button + .appendChild(UI.widgets.button(dom, retakeIcon, 'Retake')) + retakeButton.addEventListener('click', _event => { retake() }) retakeButton.style.visibility = 'collapse' // Hide for now - const shutterButton = buttons.appendChild(dom.createElement('td')) // Trigger capture button - .appendChild(UI.widgets.button(dom, UI.icons.iconBase + 'noun_10636.svg', 'Snap')) + const shutterButton = buttons + .appendChild(dom.createElement('td')) // Trigger capture button + .appendChild( + UI.widgets.button(dom, UI.icons.iconBase + 'noun_10636.svg', 'Snap') + ) shutterButton.addEventListener('click', grabCanvas) shutterButton.style.visibility = 'collapse' // Hide for now - const sendButton = buttons.appendChild(dom.createElement('td')) // Confirm and save button - .appendChild(UI.widgets.continueButton(dom)) // @@ or send icon?? - sendButton.addEventListener('click', e => { + const sendButton = buttons + .appendChild(dom.createElement('td')) // Confirm and save button + .appendChild(UI.widgets.continueButton(dom)) // @@ or send icon?? + sendButton.addEventListener('click', _event => { saveBlob(imageBlob, destination) }) sendButton.style.visibility = 'collapse' // Hide for now @@ -91,13 +101,12 @@ module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, player.setAttribute('controls', '1') player.setAttribute('autoplay', '1') player.setAttribute('style', controlStyle) - navigator.mediaDevices.getUserMedia(constraints) - .then((stream) => { - player.srcObject = stream - shutterButton.style.visibility = 'visible' // Enable - sendButton.style.visibility = 'collapse' - retakeButton.style.visibility = 'collapse' - }) + navigator.mediaDevices.getUserMedia(constraints).then(stream => { + player.srcObject = stream + shutterButton.style.visibility = 'visible' // Enable + sendButton.style.visibility = 'collapse' + retakeButton.style.visibility = 'collapse' + }) } const constraints = { @@ -123,7 +132,7 @@ module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, player.parentNode.removeChild(player) canvas.toBlob(blob => { - let msg = `got blob type ${blob.type} size ${blob.size}` + const msg = `got blob type ${blob.type} size ${blob.size}` console.log(msg) destination = getImageDoc() imageBlob = blob // save for review @@ -144,17 +153,27 @@ module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, } } function saveBlob (blob, destination) { - let contentType = blob.type + const contentType = blob.type // if (!confirm('Save picture to ' + destination + ' ?')) return - console.log('Putting ' + blob.size + ' bytes of ' + contentType + ' to ' + destination) - store.fetcher.webOperation('PUT', destination.uri, {data: blob, contentType: contentType}).then(resp => { - console.log('ok saved ' + destination) - stopVideo() - doneCallback(destination) - }, err => { - stopVideo() - alert(err) - }) + console.log( + 'Putting ' + blob.size + ' bytes of ' + contentType + ' to ' + destination + ) + store.fetcher + .webOperation('PUT', destination.uri, { + data: blob, + contentType: contentType + }) + .then( + _resp => { + console.log('ok saved ' + destination) + stopVideo() + doneCallback(destination) + }, + err => { + stopVideo() + alert(err) + } + ) } // Attach the video stream to the video element and autoplay. @@ -172,7 +191,12 @@ module.exports.cameraCaptureControl = function cameraCaptureControl (dom, store, * This expacts the buttton to a large control when it is pressed */ -module.exports.cameraButton = function cameraButton (dom, store, getImageDoc, doneCallback) { +module.exports.cameraButton = function cameraButton ( + dom, + store, + getImageDoc, + doneCallback +) { const div = dom.createElement('div') const but = UI.widgets.button(dom, cameraIcon, 'Take picture') var control @@ -182,9 +206,14 @@ module.exports.cameraButton = function cameraButton (dom, store, getImageDoc, do doneCallback(imageDoc) } div.appendChild(but) - but.addEventListener('click', event => { + but.addEventListener('click', _event => { div.removeChild(but) - control = UI.media.cameraCaptureControl(dom, store, getImageDoc, restoreButton) + control = UI.media.cameraCaptureControl( + dom, + store, + getImageDoc, + restoreButton + ) div.appendChild(control) }) return div @@ -195,7 +224,7 @@ module.exports.cameraButton = function cameraButton (dom, store, getImageDoc, do // Put up a video stream and take a picture // In: context.div, dom -UI.media.cameraOLD = function (context, gotBlob) { +UI.media.cameraOLD = function (context, _gotBlob) { function takeSnapshot () { var dom = context.dom var img = dom.createElement('img') @@ -218,13 +247,14 @@ UI.media.cameraOLD = function (context, gotBlob) { context.div.appendChild(video) // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia // https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob - navigator.mediaDevices.getUserMedia({video: true}) - .then(function (stream) { - video.src = window.URL.createObjectURL(stream) - video.addEventListener('click', takeSnapshot) - }) - .catch(function (error) { - alert('Could not access the camera. Error: ' + error.name) - }) + navigator.mediaDevices + .getUserMedia({ video: true }) + .then(function (stream) { + video.src = window.URL.createObjectURL(stream) + video.addEventListener('click', takeSnapshot) + }) + .catch(function (error) { + alert('Could not access the camera. Error: ' + error.name) + }) return video } diff --git a/src/messageArea.js b/src/messageArea.js index 8bd7b958f..f4ea2c0f2 100644 --- a/src/messageArea.js +++ b/src/messageArea.js @@ -1,3 +1,4 @@ +/* global $rdf */ // Common code for a discussion are a of messages about something // var UI = { @@ -27,7 +28,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { var newestFirst = !!options.newestFirst - var messageBodyStyle = 'white-space: pre-wrap; width: 90%; font-size:100%; border: 0.07em solid #eee; padding: .2em 0.5em; margin: 0.1em 1em 0.1em 1em;' + var messageBodyStyle = + 'white-space: pre-wrap; width: 90%; font-size:100%; border: 0.07em solid #eee; padding: .2em 0.5em; margin: 0.1em 1em 0.1em 1em;' // 'font-size: 100%; margin: 0.1em 1em 0.1em 1em; background-color: white; white-space: pre-wrap; padding: 0.1em;' var div = dom.createElement('div') @@ -37,7 +39,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { var updater = UI.store.updater - var anchor = function (text, term) { // If there is no link return an element anyway + var anchor = function (text, term) { + // If there is no link return an element anyway var a = dom.createElement('a') if (term && term.uri) { a.setAttribute('href', term.uri) @@ -57,9 +60,15 @@ module.exports = function (dom, kb, subject, messageStore, options) { } var announce = { - log: function (message) { mention(message, 'color: #111;') }, - warn: function (message) { mention(message, 'color: #880;') }, - error: function (message) { mention(message, 'color: #800;') } + log: function (message) { + mention(message, 'color: #111;') + }, + warn: function (message) { + mention(message, 'color: #880;') + }, + error: function (message) { + mention(message, 'color: #800;') + } } // Form for a new message @@ -86,21 +95,39 @@ module.exports = function (dom, kb, subject, messageStore, options) { // http://www.w3schools.com/jsref/jsref_obj_date.asp var message = kb.sym(messageStore.uri + '#' + 'Msg' + timestamp) - sts.push(new $rdf.Statement(subject, ns.wf('message'), message, messageStore)) + sts.push( + new $rdf.Statement(subject, ns.wf('message'), message, messageStore) + ) // sts.push(new $rdf.Statement(message, ns.dc('title'), kb.literal(titlefield.value), messageStore)) - sts.push(new $rdf.Statement(message, ns.sioc('content'), kb.literal(field.value), messageStore)) - sts.push(new $rdf.Statement(message, DCT('created'), dateStamp, messageStore)) - if (me) sts.push(new $rdf.Statement(message, ns.foaf('maker'), me, messageStore)) + sts.push( + new $rdf.Statement( + message, + ns.sioc('content'), + kb.literal(field.value), + messageStore + ) + ) + sts.push( + new $rdf.Statement(message, DCT('created'), dateStamp, messageStore) + ) + if (me) { + sts.push( + new $rdf.Statement(message, ns.foaf('maker'), me, messageStore) + ) + } var sendComplete = function (uri, success, body) { if (!success) { - form.appendChild(UI.widgets.errorMessageBlock( - dom, 'Error writing message: ' + body)) + form.appendChild( + UI.widgets.errorMessageBlock(dom, 'Error writing message: ' + body) + ) } else { - var bindings = { '?msg': message, + var bindings = { + '?msg': message, '?content': kb.literal(field.value), '?date': dateStamp, - '?creator': me} + '?creator': me + } renderMessage(bindings, false) // not green field.value = '' // clear from out for reuse @@ -123,22 +150,32 @@ module.exports = function (dom, kb, subject, messageStore, options) { // field.cols = 40 field.setAttribute('style', messageBodyStyle + 'background-color: #eef;') - field.addEventListener('keyup', function (e) { // User preference? - if (e.keyCode === 13) { - if (!e.altKey) { // Alt-Enter just adds a new line - sendMessage() + field.addEventListener( + 'keyup', + function (e) { + // User preference? + if (e.keyCode === 13) { + if (!e.altKey) { + // Alt-Enter just adds a new line + sendMessage() + } } - } - }, false) + }, + false + ) rhs.innerHTML = '' - sendButton = UI.widgets.button(dom, UI.icons.iconBase + 'noun_383448.svg', 'Send') + sendButton = UI.widgets.button( + dom, + UI.icons.iconBase + 'noun_383448.svg', + 'Send' + ) sendButton.setAttribute('style', UI.style.buttonStyle + 'float: right;') sendButton.addEventListener('click', sendMessage, false) rhs.appendChild(sendButton) } - let context = {div: middle, dom: dom} + const context = { div: middle, dom: dom } UI.authn.logIn(context).then(context => { me = context.me turnOnInput() @@ -156,7 +193,10 @@ module.exports = function (dom, kb, subject, messageStore, options) { function creatorAndDate (td1, creator, date, message) { var nickAnchor = td1.appendChild(anchor(nick(creator), creator)) if (creator.uri) { - UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function (ok, body) { + UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function ( + _ok, + _body + ) { nickAnchor.textContent = nick(creator) }) } @@ -183,7 +223,8 @@ module.exports = function (dom, kb, subject, messageStore, options) { } }) - for (ele = messageTable.firstChild; ele;) { + // eslint-disable-next-line space-in-parens + for (ele = messageTable.firstChild; ele; ) { ele2 = ele.nextSibling if (ele.AJAR_subject && !stored[ele.AJAR_subject.uri]) { messageTable.removeChild(ele) @@ -193,8 +234,9 @@ module.exports = function (dom, kb, subject, messageStore, options) { } var deleteMessage = function (message) { - var deletions = kb.statementsMatching(message).concat( - kb.statementsMatching(undefined, undefined, message)) + var deletions = kb + .statementsMatching(message) + .concat(kb.statementsMatching(undefined, undefined, message)) updater.update(deletions, [], function (uri, ok, body) { if (!ok) { announce.error('Cant delete messages:' + body) @@ -227,11 +269,14 @@ module.exports = function (dom, kb, subject, messageStore, options) { var done = false for (var ele = messageTable.firstChild; ; ele = ele.nextSibling) { - if (!ele) { // empty + if (!ele) { + // empty break } - if (((dateString > ele.AJAR_date) && newestFirst) || - ((dateString < ele.AJAR_date) && !newestFirst)) { + if ( + (dateString > ele.AJAR_date && newestFirst) || + (dateString < ele.AJAR_date && !newestFirst) + ) { messageTable.insertBefore(tr, ele) done = true break @@ -248,8 +293,11 @@ module.exports = function (dom, kb, subject, messageStore, options) { var td2 = dom.createElement('td') tr.appendChild(td2) var pre = dom.createElement('p') - pre.setAttribute('style', messageBodyStyle + - (fresh ? 'background-color: #e8ffe8;' : 'background-color: #white;')) + pre.setAttribute( + 'style', + messageBodyStyle + + (fresh ? 'background-color: #e8ffe8;' : 'background-color: #white;') + ) td2.appendChild(pre) pre.textContent = content.value @@ -263,23 +311,35 @@ module.exports = function (dom, kb, subject, messageStore, options) { tr.setAttribute('class', 'hoverControl') // See tabbedtab.css (sigh global CSS) delButton.setAttribute('class', 'hoverControlHide') delButton.setAttribute('style', 'color: red;') - delButton.addEventListener('click', function (e) { - td3.removeChild(delButton) // Ask -- are you sure? - var cancelButton = dom.createElement('button') - cancelButton.textContent = 'cancel' - td3.appendChild(cancelButton).addEventListener('click', function (e) { - td3.removeChild(sureButton) - td3.removeChild(cancelButton) - td3.appendChild(delButton) - }, false) - var sureButton = dom.createElement('button') - sureButton.textContent = 'Delete message' - td3.appendChild(sureButton).addEventListener('click', function (e) { - td3.removeChild(sureButton) - td3.removeChild(cancelButton) - deleteMessage(message) - }, false) - }, false) + delButton.addEventListener( + 'click', + function (_event) { + td3.removeChild(delButton) // Ask -- are you sure? + var cancelButton = dom.createElement('button') + cancelButton.textContent = 'cancel' + td3.appendChild(cancelButton).addEventListener( + 'click', + function (_event) { + td3.removeChild(sureButton) + td3.removeChild(cancelButton) + td3.appendChild(delButton) + }, + false + ) + var sureButton = dom.createElement('button') + sureButton.textContent = 'Delete message' + td3.appendChild(sureButton).addEventListener( + 'click', + function (_event) { + td3.removeChild(sureButton) + td3.removeChild(cancelButton) + deleteMessage(message) + }, + false + ) + }, + false + ) } // Messages with date, author etc @@ -305,12 +365,12 @@ module.exports = function (dom, kb, subject, messageStore, options) { var v = {} // semicolon needed var vs = ['msg', 'date', 'creator', 'content'] vs.map(function (x) { - query.vars.push(v[x] = $rdf.variable(x)) + query.vars.push((v[x] = $rdf.variable(x))) }) - query.pat.add(subject, WF('message'), v['msg']) - query.pat.add(v['msg'], ns.dct('created'), v['date']) - query.pat.add(v['msg'], ns.foaf('maker'), v['creator']) - query.pat.add(v['msg'], ns.sioc('content'), v['content']) + query.pat.add(subject, WF('message'), v.msg) + query.pat.add(v.msg, ns.dct('created'), v.date) + query.pat.add(v.msg, ns.foaf('maker'), v.creator) + query.pat.add(v.msg, ns.sioc('content'), v.content) } function doneQuery () { messageTable.fresh = true // any new are fresh and so will be greenish diff --git a/src/noun_Camera_1618446_000000.js b/src/noun_Camera_1618446_000000.js index c547e782f..9bc6eba02 100644 --- a/src/noun_Camera_1618446_000000.js +++ b/src/noun_Camera_1618446_000000.js @@ -1 +1,2 @@ -module.exports = 'data:image/svg;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAwIDEwMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PHBhdGggZD0iTTcyLjkyNiwzNC4zMzNINjIuNDc4bC0yLjUtNS42NjZINDAuMDIybC0yLjUsNS42NjZoLTIuMjc1di0zLjcwN2gtNnYzLjcwN2gtMi4xNzNjLTEuOTMsMC0zLjUsMS41Ny0zLjUsMy41djMwICAgYzAsMS45MywxLjU3LDMuNSwzLjUsMy41aDQ1Ljg1MmMxLjkzLDAsMy41LTEuNTcsMy41LTMuNXYtMzBDNzYuNDI2LDM1LjkwMyw3NC44NTUsMzQuMzMzLDcyLjkyNiwzNC4zMzN6IE03My40MjYsNjcuODMzICAgYzAsMC4yNzUtMC4yMjUsMC41LTAuNSwwLjVIMjcuMDc0Yy0wLjI3NSwwLTAuNS0wLjIyNS0wLjUtMC41di0zMGMwLTAuMjc1LDAuMjI1LTAuNSwwLjUtMC41aDEyLjQwM2wyLjUtNS42NjZoMTYuMDQ1bDIuNSw1LjY2NiAgIGgxMi40MDNjMC4yNzUsMCwwLjUsMC4yMjUsMC41LDAuNVY2Ny44MzN6Ij48L3BhdGg+PHBhdGggZD0iTTUwLDM4Ljc2NmMtNy4yOTgsMC0xMy4yMzQsNS45MzctMTMuMjM0LDEzLjIzNFM0Mi43MDIsNjUuMjM0LDUwLDY1LjIzNFM2My4yMzQsNTkuMjk4LDYzLjIzNCw1MlM1Ny4yOTgsMzguNzY2LDUwLDM4Ljc2NiAgIHogTTUwLDYyLjIzNGMtNS42NDQsMC0xMC4yMzQtNC41OTEtMTAuMjM0LTEwLjIzNFM0NC4zNTYsNDEuNzY2LDUwLDQxLjc2NlM2MC4yMzQsNDYuMzU2LDYwLjIzNCw1MlM1NS42NDQsNjIuMjM0LDUwLDYyLjIzNHoiPjwvcGF0aD48cGF0aCBkPSJNNTAuMDAxLDQzLjI0MmMtNC44MywwLTguNzYsMy45MjktOC43Niw4Ljc1OHMzLjkzLDguNzU4LDguNzYsOC43NThjNC44MjksMCw4Ljc1OC0zLjkyOSw4Ljc1OC04Ljc1OCAgIFM1NC44Myw0My4yNDIsNTAuMDAxLDQzLjI0MnogTTUwLjAwMSw1OS43NThjLTQuMjc4LDAtNy43Ni0zLjQ4LTcuNzYtNy43NThzMy40ODEtNy43NTgsNy43Ni03Ljc1OCAgIGM0LjI3NywwLDcuNzU4LDMuNDgsNy43NTgsNy43NThTNTQuMjc4LDU5Ljc1OCw1MC4wMDEsNTkuNzU4eiI+PC9wYXRoPjwvZz48L3N2Zz4=' +module.exports = + 'data:image/svg;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAwIDEwMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PHBhdGggZD0iTTcyLjkyNiwzNC4zMzNINjIuNDc4bC0yLjUtNS42NjZINDAuMDIybC0yLjUsNS42NjZoLTIuMjc1di0zLjcwN2gtNnYzLjcwN2gtMi4xNzNjLTEuOTMsMC0zLjUsMS41Ny0zLjUsMy41djMwICAgYzAsMS45MywxLjU3LDMuNSwzLjUsMy41aDQ1Ljg1MmMxLjkzLDAsMy41LTEuNTcsMy41LTMuNXYtMzBDNzYuNDI2LDM1LjkwMyw3NC44NTUsMzQuMzMzLDcyLjkyNiwzNC4zMzN6IE03My40MjYsNjcuODMzICAgYzAsMC4yNzUtMC4yMjUsMC41LTAuNSwwLjVIMjcuMDc0Yy0wLjI3NSwwLTAuNS0wLjIyNS0wLjUtMC41di0zMGMwLTAuMjc1LDAuMjI1LTAuNSwwLjUtMC41aDEyLjQwM2wyLjUtNS42NjZoMTYuMDQ1bDIuNSw1LjY2NiAgIGgxMi40MDNjMC4yNzUsMCwwLjUsMC4yMjUsMC41LDAuNVY2Ny44MzN6Ij48L3BhdGg+PHBhdGggZD0iTTUwLDM4Ljc2NmMtNy4yOTgsMC0xMy4yMzQsNS45MzctMTMuMjM0LDEzLjIzNFM0Mi43MDIsNjUuMjM0LDUwLDY1LjIzNFM2My4yMzQsNTkuMjk4LDYzLjIzNCw1MlM1Ny4yOTgsMzguNzY2LDUwLDM4Ljc2NiAgIHogTTUwLDYyLjIzNGMtNS42NDQsMC0xMC4yMzQtNC41OTEtMTAuMjM0LTEwLjIzNFM0NC4zNTYsNDEuNzY2LDUwLDQxLjc2NlM2MC4yMzQsNDYuMzU2LDYwLjIzNCw1MlM1NS42NDQsNjIuMjM0LDUwLDYyLjIzNHoiPjwvcGF0aD48cGF0aCBkPSJNNTAuMDAxLDQzLjI0MmMtNC44MywwLTguNzYsMy45MjktOC43Niw4Ljc1OHMzLjkzLDguNzU4LDguNzYsOC43NThjNC44MjksMCw4Ljc1OC0zLjkyOSw4Ljc1OC04Ljc1OCAgIFM1NC44Myw0My4yNDIsNTAuMDAxLDQzLjI0MnogTTUwLjAwMSw1OS43NThjLTQuMjc4LDAtNy43Ni0zLjQ4LTcuNzYtNy43NThzMy40ODEtNy43NTgsNy43Ni03Ljc1OCAgIGM0LjI3NywwLDcuNzU4LDMuNDgsNy43NTgsNy43NThTNTQuMjc4LDU5Ljc1OCw1MC4wMDEsNTkuNzU4eiI+PC9wYXRoPjwvZz48L3N2Zz4=' diff --git a/src/pad.js b/src/pad.js index d2d6bce56..44cb6d506 100644 --- a/src/pad.js +++ b/src/pad.js @@ -1,13 +1,12 @@ - /** ************** -* Notepad Widget -*/ + * Notepad Widget + */ /** @module UI.pad -*/ + */ const $rdf = require('rdflib') -var padModule = module.exports = {} +var padModule = (module.exports = {}) var UI = { authn: require('./signin'), icons: require('./iconBase'), @@ -24,13 +23,20 @@ const ns = UI.ns const utils = require('./utils') /** 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 -*/ + * + * @param {NamedNode} author - The author of text being displayed + * @returns {String} The CSS color generated, constrained to be light for a background color + */ UI.pad.lightColorHash = function (author) { - var hash = function (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 + var hash = function (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 // Manage participation in this session @@ -51,7 +57,11 @@ UI.pad.renderPartipants = function (dom, table, padDoc, subject, me, options) { var bg = kb.anyValue(parp, ns.ui('backgroundColor')) || 'white' var block = dom.createElement('div') - block.setAttribute('style', 'height: 1.5em; width: 1.5em; margin: 0.3em; border 0.01em solid #888; background-color: ' + bg) + block.setAttribute( + 'style', + 'height: 1.5em; width: 1.5em; margin: 0.3em; border 0.01em solid #888; background-color: ' + + bg + ) tr = UI.widgets.personTR(dom, null, person, options) table.appendChild(tr) var td = dom.createElement('td') @@ -66,7 +76,9 @@ UI.pad.renderPartipants = function (dom, table, padDoc, subject, me, options) { return [kb.anyValue(parp, UI.ns.cal('dtstart')) || '9999-12-31', parp] }) parps.sort() // List in order of joining - var participations = parps.map(function (p) { return p[1] }) + var participations = parps.map(function (p) { + return p[1] + }) utils.syncTableToArray(table, participations, newRowForParticpation) } table.refresh = syncTable @@ -75,14 +87,14 @@ UI.pad.renderPartipants = function (dom, table, padDoc, subject, me, options) { } /** Record, or find old, Particpation object -* -* A particpaption object is a place to record things specifically about -* subject and the user, such as preferences, start of membership, etc -* @param {Node} subject - The thing in which the participation is happening -* @param {NamedNode} document - Where to record the data -* @param {NamedNode} me - The logged in user -* -*/ + * + * A particpaption object is a place to record things specifically about + * subject and the user, such as preferences, start of membership, etc + * @param {Node} subject - The thing in which the participation is happening + * @param {NamedNode} document - Where to record the data + * @param {NamedNode} me - The logged in user + * + */ UI.pad.participationObject = function (subject, padDoc, me) { return new Promise(function (resolve, reject) { if (!me) { @@ -95,7 +107,8 @@ UI.pad.participationObject = function (subject, padDoc, me) { if (parps.length > 1) { throw new Error('Multiple records of your participation') } - if (parps.length) { // If I am not already recorded + if (parps.length) { + // If I am not already recorded resolve(parps[0]) // returns the particpation object } else { var participation = UI.widgets.newThing(padDoc) @@ -104,7 +117,12 @@ UI.pad.participationObject = function (subject, padDoc, me) { UI.rdf.st(participation, ns.wf('participant'), me, padDoc), UI.rdf.st(participation, ns.cal('dtstart'), new Date(), padDoc), - UI.rdf.st(participation, ns.ui('backgroundColor'), UI.pad.lightColorHash(me), padDoc) + UI.rdf.st( + participation, + ns.ui('backgroundColor'), + UI.pad.lightColorHash(me), + padDoc + ) ] kb.updater.update([], ins, function (uri, ok, errorMessage) { if (!ok) { @@ -124,7 +142,7 @@ UI.pad.participationObject = function (subject, padDoc, me) { * @param {NamedNode} padDoc - The document into which the particpation should be recorded * @param {DOMNode} refreshable - A DOM element whose refresh() is to be called if the change works * -*/ + */ UI.pad.recordParticipation = function (subject, padDoc, refreshable) { var me = UI.authn.currentUser() if (!me) return // Not logged in @@ -135,7 +153,8 @@ UI.pad.recordParticipation = function (subject, padDoc, refreshable) { if (parps.length > 1) { throw new Error('Multiple records of your participation') } - if (parps.length) { // If I am not already recorded + if (parps.length) { + // If I am not already recorded return parps[0] // returns the particpation object } else { var participation = UI.widgets.newThing(padDoc) @@ -144,7 +163,12 @@ UI.pad.recordParticipation = function (subject, padDoc, refreshable) { UI.rdf.st(participation, ns.wf('participant'), me, padDoc), UI.rdf.st(participation, UI.ns.cal('dtstart'), new Date(), padDoc), - UI.rdf.st(participation, ns.ui('backgroundColor'), UI.pad.lightColorHash(me), padDoc) + UI.rdf.st( + participation, + ns.ui('backgroundColor'), + UI.pad.lightColorHash(me), + padDoc + ) ] kb.updater.update([], ins, function (uri, ok, errorMessage) { if (!ok) { @@ -161,14 +185,26 @@ UI.pad.recordParticipation = function (subject, padDoc, refreshable) { // Record my participation and display participants // -UI.pad.manageParticipation = function (dom, container, padDoc, subject, me, options) { +UI.pad.manageParticipation = function ( + dom, + container, + padDoc, + subject, + me, + options +) { var table = dom.createElement('table') container.appendChild(table) UI.pad.renderPartipants(dom, table, padDoc, subject, me, options) try { UI.pad.recordParticipation(subject, padDoc, table) } catch (e) { - container.appendChild(UI.widgets.errorMessageBlock(dom, 'Error recording your partipation: ' + e)) // Clean up? + container.appendChild( + UI.widgets.errorMessageBlock( + dom, + 'Error recording your partipation: ' + e + ) + ) // Clean up? } return table } @@ -186,7 +222,10 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var PAD = $rdf.Namespace('http://www.w3.org/ns/pim/pad#') - table.setAttribute('style', 'padding: 1em; overflow: auto; resize: horizontal; min-width: 40em;') + table.setAttribute( + 'style', + 'padding: 1em; overflow: auto; resize: horizontal; min-width: 40em;' + ) var upstreamStatus = null var downstreamStatus = null @@ -203,12 +242,13 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var complain = function (message, upstream) { console.log(message) if (options.statusArea) { - (upstream ? upstreamStatus : downstreamStatus).appendChild( - UI.widgets.errorMessageBlock(dom, message, 'pink')) + ;(upstream ? upstreamStatus : downstreamStatus).appendChild( + UI.widgets.errorMessageBlock(dom, message, 'pink') + ) } } - var clearStatus = function (upsteam) { + var clearStatus = function (_upsteam) { if (options.statusArea) { options.statusArea.innerHTML = '' } @@ -217,25 +257,36 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var setPartStyle = function (part, colors, pending) { var chunk = part.subject colors = colors || '' - var baseStyle = 'font-size: 100%; font-family: monospace; width: 100%; border: none; white-space: pre-wrap;' - var headingCore = 'font-family: sans-serif; font-weight: bold; border: none;' - var headingStyle = [ 'font-size: 110%; padding-top: 0.5em; padding-bottom: 0.5em; width: 100%;', + var baseStyle = + 'font-size: 100%; font-family: monospace; width: 100%; border: none; white-space: pre-wrap;' + var headingCore = + 'font-family: sans-serif; font-weight: bold; border: none;' + var headingStyle = [ + 'font-size: 110%; padding-top: 0.5em; padding-bottom: 0.5em; width: 100%;', 'font-size: 120%; padding-top: 1em; padding-bottom: 1em; width: 100%;', - 'font-size: 150%; padding-top: 1em; padding-bottom: 1em; width: 100%;' ] + 'font-size: 150%; padding-top: 1em; padding-bottom: 1em; width: 100%;' + ] var author = kb.any(chunk, ns.dc('author')) - if (!colors && author) { // Hash the user webid for now -- later allow user selection! + if (!colors && author) { + // Hash the user webid for now -- later allow user selection! var bgcolor = UI.pad.lightColorHash(author) - colors = 'color: ' + (pending ? '#888' : 'black') + '; background-color: ' + bgcolor + ';' + colors = + 'color: ' + + (pending ? '#888' : 'black') + + '; background-color: ' + + bgcolor + + ';' } var indent = kb.any(chunk, PAD('indent')) indent = indent ? indent.value : 0 - var style = (indent >= 0) // - // baseStyle + 'padding-left: ' + (indent * 3) + 'em;' - ? baseStyle + 'text-indent: ' + (indent * 3) + 'em;' - : headingCore + headingStyle[ -1 - indent ] + var style = + indent >= 0 + ? baseStyle + 'text-indent: ' + indent * 3 + 'em;' + : headingCore + headingStyle[-1 - indent] + // ? baseStyle + 'padding-left: ' + (indent * 3) + 'em;' part.setAttribute('style', style + colors) } @@ -244,14 +295,16 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { 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 + if (prev.sameTerm(subject) && next.sameTerm(subject)) { + // Last one console.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 = [ $rdf.st(prev, PAD('next'), next, padDoc) ] + var del = kb + .statementsMatching(chunk, undefined, undefined, padDoc) + .concat(kb.statementsMatching(undefined, undefined, chunk, padDoc)) + var ins = [$rdf.st(prev, PAD('next'), next, padDoc)] var label = chunk.uri.slice(-4) console.log('Deleting line ' + label) @@ -264,24 +317,26 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { if (before && before.firstChild) { before.firstChild.focus() } - } else if (response && response.status === 409) { // Conflict + } else if (response && response.status === 409) { + // Conflict setPartStyle(part, 'color: black; background-color: #ffd;') // yellow part.state = 0 // Needs downstream refresh utils.beep(0.5, 512) // Ooops clash with other person - setTimeout(function () { // Ideally, beep! @@ - reloadAndSync() // Throw away our changes and + setTimeout(function () { + // Ideally, beep! @@ + reloadAndSync() // Throw away our changes and // updater.requestDownstreamAction(padDoc, reloadAndSync) }, 1000) } else { console.log(' removePart FAILED ' + chunk + ': ' + errorMessage) console.log(" removePart was deleteing :'" + del) - setPartStyle(part, 'color: black; background-color: #fdd;')// failed - let res = response ? response.status : ' [no response field] ' + setPartStyle(part, 'color: black; background-color: #fdd;') // failed + const res = response ? response.status : ' [no response field] ' complain('Error ' + res + ' saving changes: ' + errorMessage.true) // upstream, - // updater.requestDownstreamAction(padDoc, reloadAndSync); - }; + // updater.requestDownstreamAction(padDoc, reloadAndSync); + } }) - }// removePart + } // removePart var changeIndent = function (part, chunk, delta) { var del = kb.statementsMatching(chunk, PAD('indent')) @@ -291,7 +346,14 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var ins = $rdf.st(chunk, PAD('indent'), newIndent, padDoc) updater.update(del, ins, function (uri, ok, errorBody) { if (!ok) { - console.log("Indent change FAILED '" + newIndent + "' for " + padDoc + ': ' + errorBody) + console.log( + "Indent change FAILED '" + + newIndent + + "' for " + + padDoc + + ': ' + + errorBody + ) setPartStyle(part, 'color: black; background-color: #fdd;') // failed updater.requestDownstreamAction(padDoc, reloadAndSync) } else { @@ -300,8 +362,8 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { }) } - // Use this sort of code to split the line when return pressed in the middle @@ -/* + // Use this sort of code to split the line when return pressed in the middle @@ + /* function doGetCaretPosition doGetCaretPosition (oField) { var iCaretPos = 0 // IE Support @@ -329,11 +391,11 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var addListeners = function (part, chunk) { part.addEventListener('keydown', function (event) { var queueProperty, queue - // up 38; down 40; left 37; right 39 tab 9; shift 16; escape 27 + // up 38; down 40; left 37; right 39 tab 9; shift 16; escape 27 switch (event.keyCode) { - case 13: // Return + case 13: // Return var before = event.shiftKey - console.log('enter') // Shift-return inserts before -- only way to add to top of pad. + console.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' @@ -353,7 +415,9 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { case 8: // Delete if (part.value.length === 0) { - console.log('Delete key line ' + chunk.uri.slice(-4) + ' state ' + part.state) + console.log( + 'Delete key line ' + chunk.uri.slice(-4) + ' state ' + part.state + ) switch (part.state) { case 1: // contents being sent @@ -379,7 +443,7 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { changeIndent(part, chunk, delta) event.preventDefault() // default is to highlight next field break - case 27: // ESC + case 27: // ESC console.log('escape') updater.requestDownstreamAction(padDoc, reloadAndSync) event.preventDefault() @@ -407,25 +471,48 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var chunk = part.subject setPartStyle(part, undefined, true) var old = kb.any(chunk, ns.sioc('content')).value - var del = [ $rdf.st(chunk, ns.sioc('content'), old, padDoc) ] - var ins = [ $rdf.st(chunk, ns.sioc('content'), part.value, padDoc) ] + var del = [$rdf.st(chunk, ns.sioc('content'), old, padDoc)] + var ins = [$rdf.st(chunk, ns.sioc('content'), part.value, padDoc)] var newOne = part.value - // DEBUGGING ONLY + // DEBUGGING ONLY if (part.lastSent) { if (old !== part.lastSent) { - throw new Error("Out of order, last sent expected '" + old + - "' but found '" + 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 + "' ") + console.log( + ' Patch proposed to ' + + chunk.uri.slice(-4) + + " '" + + old + + "' -> '" + + newOne + + "' " + ) updater.update(del, ins, function (uri, ok, errorBody, xhr) { if (!ok) { - // alert("clash " + errorBody); - console.log(' patch FAILED ' + xhr.status + " for '" + old + "' -> '" + newOne + "': " + errorBody) - if (xhr.status === 409) { // Conflict - @@ we assume someone else + // alert("clash " + errorBody); + console.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 utils.beep(0.5, 512) // Ooops clash with other person @@ -435,22 +522,27 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { } else { setPartStyle(part, 'color: black; background-color: #fdd;') // failed pink part.state = 0 - complain(' Error ' + xhr.status + ' sending data: ' + errorBody, true) + complain( + ' Error ' + xhr.status + ' sending data: ' + errorBody, + true + ) utils.beep(1.0, 128) // Other - // @@@ Do soemthing more serious with other errors eg auth, etc + // @@@ Do soemthing more serious with other errors eg auth, etc } } else { - clearStatus(true)// upstream + clearStatus(true) // upstream setPartStyle(part) // synced console.log(" Patch ok '" + old + "' -> '" + newOne + "' ") - if (part.state === 4) { // delete me + if (part.state === 4) { + // delete me part.state = 3 removePart(part) - } else if (part.state === 3) { // being deleted - // pass + } else if (part.state === 3) { + // being deleted + // pass } else if (part.state === 2) { - part.state = 1 // pending: lock + part.state = 1 // pending: lock updateStore(part) } else { part.state = 0 // clear lock @@ -459,10 +551,12 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { }) } - part.addEventListener('input', function inputChangeListener (event) { - // console.log("input changed "+part.value); + part.addEventListener('input', function inputChangeListener (_event) { + // console.log("input changed "+part.value); setPartStyle(part, undefined, true) // grey out - not synced - console.log('Input event state ' + part.state + " value '" + part.value + "'") + console.log( + 'Input event state ' + part.state + " value '" + part.value + "'" + ) switch (part.state) { case 3: // being deleted return @@ -481,13 +575,15 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { }) // listener } // addlisteners - var newPartAfter = function (tr1, chunk, before) { // @@ take chunk and add listeners + var newPartAfter = function (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 + } else { + // after if (tr1 && tr1.nextSibling) { table.insertBefore(tr, tr1.nextSibling) } else { @@ -508,7 +604,8 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { return part } - var newChunk = function (ele, before) { // element of chunk being split + var newChunk = function (ele, before) { + // element of chunk being split var kb = UI.store var indent = 0 var queueProperty = null @@ -543,28 +640,38 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { var label = chunk.uri.slice(-4) var del = [$rdf.st(prev, PAD('next'), next, padDoc)] - var ins = [$rdf.st(prev, PAD('next'), chunk, padDoc), + var ins = [ + $rdf.st(prev, PAD('next'), chunk, padDoc), $rdf.st(chunk, PAD('next'), next, padDoc), $rdf.st(chunk, ns.dc('author'), me, padDoc), - $rdf.st(chunk, ns.sioc('content'), '', padDoc)] - if (indent > 0) { // Do not inherit + $rdf.st(chunk, ns.sioc('content'), '', padDoc) + ] + if (indent > 0) { + // Do not inherit ins.push($rdf.st(chunk, PAD('indent'), indent, padDoc)) } console.log(' Fresh chunk ' + label + ' proposed') - updater.update(del, ins, function (uri, ok, errorBody, xhr) { + updater.update(del, ins, function (uri, ok, errorBody, _xhr) { if (!ok) { - // alert("Error writing new line " + label + ": " + errorBody); + // alert("Error writing new line " + label + ": " + errorBody); console.log(' ERROR writing new line ' + label + ': ' + errorBody) } else { var newPart = newPartAfter(tr1, chunk, before) setPartStyle(newPart) newPart.focus() // Note this is delayed if (queueProperty) { - console.log(' Fresh chunk ' + label + ' updated, queue = ' + queue[queueProperty]) + console.log( + ' Fresh chunk ' + + label + + ' updated, queue = ' + + queue[queueProperty] + ) queue[queueProperty] -= 1 if (queue[queueProperty] > 0) { - console.log(' Implementing queued newlines = ' + next.newLinesBefore) + console.log( + ' Implementing queued newlines = ' + next.newLinesBefore + ) newChunk(newPart, before) } } @@ -584,7 +691,7 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { complain2('No initial next pointer') return false // can't do linked list } - // var chunk = kb.the(subject, PAD('next')) + // var chunk = kb.the(subject, PAD('next')) var prev = subject var chunk for (;;) { @@ -604,16 +711,24 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { 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) + 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) + 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) + 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) + if (k !== 1) { + complain2('Should be 1 not ' + k + ' author for ' + label) + } var sts = kb.statementsMatching(undefined, ns.sioc('contents')) sts.map(function (st) { @@ -625,12 +740,13 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { return !failed } - // Ensure that the display matches the current state of the + // Ensure that the display matches the current state of the var sync = function () { // 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) + var msg = + 'Pad: Inconsistent data - NEXT pointers: ' + + kb.each(subject, PAD('next')).length console.log(msg) if (options.statusAra) { options.statusArea.textContent += msg @@ -641,13 +757,15 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { // var chunk = first // = kb.the(subject, PAD('next')); var row - // First see which of the logical chunks have existing physical manifestations + // First see which of the logical chunks have existing physical manifestations var manif = [] - // Find which lines correspond to existing chunks + // Find which lines correspond to existing chunks - for (let chunk = kb.the(subject, PAD('next')); - !chunk.sameTerm(subject); - chunk = kb.the(chunk, PAD('next'))) { + for ( + let chunk = kb.the(subject, PAD('next')); + !chunk.sameTerm(subject); + chunk = kb.the(chunk, PAD('next')) + ) { for (let i = 0; i < table.children.length; i++) { var tr = table.children[i] if (tr.firstChild.subject.sameTerm(chunk)) { @@ -656,21 +774,23 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { } } - // Remove any deleted lines + // Remove any deleted lines for (let 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 + // Insert any new lines and update old ones row = table.firstChild // might be null - for (let chunk = kb.the(subject, PAD('next')); - !chunk.sameTerm(subject); - chunk = kb.the(chunk, PAD('next'))) { + for ( + let 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 + // 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) { @@ -683,10 +803,10 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { } else { newPartAfter(row, chunk, true) // actually before } - }; + } } - // Refresh the DOM tree + // Refresh the DOM tree var refreshTree = function (root) { if (root.refresh) { @@ -725,14 +845,22 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { checkAndSync() } else { if (xhr.status === 0) { - complain('Network error refreshing the pad. Retrying in ' + - retryTimeout / 1000) + 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) + complain( + 'Error ' + + xhr.status + + 'refreshing the pad:' + + message + + '. Stopped. ' + + padDoc + ) } } }) @@ -749,19 +877,22 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { console.log('Existing pad.') if (consistencyCheck()) { sync() - if (kb.holds(subject, PAD('next'), subject)) { // Empty list untenable + if (kb.holds(subject, PAD('next'), subject)) { + // Empty list untenable newChunk() // require at least one line } } else { - console.log(table.textContent = 'Inconsistent data. Abort') + console.log((table.textContent = 'Inconsistent data. Abort')) } - } else { // Make new pad + } else { + // Make new pad console.log('No pad exists - making new one.') var insertables = [ $rdf.st(subject, ns.rdf('type'), PAD('Notepad'), padDoc), $rdf.st(subject, ns.dc('author'), me, padDoc), $rdf.st(subject, ns.dc('created'), new Date(), padDoc), - $rdf.st(subject, PAD('next'), subject, padDoc)] + $rdf.st(subject, PAD('next'), subject, padDoc) + ] updater.update([], insertables, function (uri, ok, errorBody) { if (!ok) { @@ -769,7 +900,7 @@ UI.pad.notepad = function (dom, padDoc, subject, me, options) { } else { console.log('Initial pad created') newChunk() // Add a first chunck - // getResults(); + // getResults(); } }) } diff --git a/src/preferences.js b/src/preferences.js index 93d534e1e..d86b75cb1 100644 --- a/src/preferences.js +++ b/src/preferences.js @@ -1,3 +1,4 @@ +/* global $rdf */ // Solid-UI temporary preferences // ============================== // @@ -9,9 +10,11 @@ const pad = require('./pad') // This was tabulator . preferences in the tabulator // -module.exports = { // used for storing user name +module.exports = { + // used for storing user name value: [], - get: function (k) { // original + get: function (k) { + // original return this.value[k] }, set: function (k, v) { @@ -33,8 +36,10 @@ function recordSharedPreferences (subject, context) { return new Promise(function (resolve, reject) { var sharedPreferences = kb.any(subject, ns.ui('sharedPreferences')) if (!sharedPreferences) { - let sp = $rdf.sym(subject.doc().uri + '#SharedPreferences') - let ins = [$rdf.st(subject, ns.ui('sharedPreferences'), sp, subject.doc())] + const sp = $rdf.sym(subject.doc().uri + '#SharedPreferences') + const ins = [ + $rdf.st(subject, ns.ui('sharedPreferences'), sp, subject.doc()) + ] console.log('Creating shared preferences ' + sp) kb.updater.update([], ins, function (uri, ok, errorMessage) { if (!ok) { @@ -55,76 +60,137 @@ function recordSharedPreferences (subject, context) { // function recordPersonalDefaults (klass, context) { return new Promise(function (resolve, reject) { - authn.logInLoadPreferences(context).then(context => { - if (!context.preferencesFile) { - console.log('Not doing private class preferences as no access to preferences file. ' + context.preferencesFileError) - return - } - var regs = kb.each(null, ns.solid('forClass'), klass, context.preferencesFile) - var ins = [] - var prefs - var reg - if (regs.length) { // Use existing node if we can - regs.forEach(r => { - prefs = prefs || kb.any(r, ns.solid('personalDefaults')) - }) - if (prefs) { - context.personalDefaults = prefs // Found one - resolve(context) + authn.logInLoadPreferences(context).then( + context => { + if (!context.preferencesFile) { + console.log( + 'Not doing private class preferences as no access to preferences file. ' + + context.preferencesFileError + ) return - } else { - prefs = widgets.newThing(context.preferencesFile) - reg = regs[0] } - } else { // no regs fo class - reg = widgets.newThing(context.preferencesFile) - ins = [ $rdf.st(reg, ns.rdf('type'), ns.solid('TypeRegistration'), context.preferencesFile), - $rdf.st(reg, ns.solid('forClass'), klass, context.preferencesFile)] - } - prefs = widgets.newThing(context.preferencesFile) - ins.push($rdf.st(reg, ns.solid('personalDefaults'), prefs, context.preferencesFile)) - kb.updater.update([], ins, function (uri, ok, errm) { - if (!ok) { - reject(new Error('Setting preferences for ' + klass + ': ' + errm)) + var regs = kb.each( + null, + ns.solid('forClass'), + klass, + context.preferencesFile + ) + var ins = [] + var prefs + var reg + if (regs.length) { + // Use existing node if we can + regs.forEach(r => { + prefs = prefs || kb.any(r, ns.solid('personalDefaults')) + }) + if (prefs) { + context.personalDefaults = prefs // Found one + resolve(context) + return + } else { + prefs = widgets.newThing(context.preferencesFile) + reg = regs[0] + } } else { - context.personalDefaults = prefs - resolve(context) + // no regs fo class + reg = widgets.newThing(context.preferencesFile) + ins = [ + $rdf.st( + reg, + ns.rdf('type'), + ns.solid('TypeRegistration'), + context.preferencesFile + ), + $rdf.st(reg, ns.solid('forClass'), klass, context.preferencesFile) + ] } - }) - }, err => { - reject(err) - }) + prefs = widgets.newThing(context.preferencesFile) + ins.push( + $rdf.st( + reg, + ns.solid('personalDefaults'), + prefs, + context.preferencesFile + ) + ) + kb.updater.update([], ins, function (uri, ok, errm) { + if (!ok) { + reject(new Error('Setting preferences for ' + klass + ': ' + errm)) + } else { + context.personalDefaults = prefs + resolve(context) + } + }) + }, + err => { + reject(err) + } + ) }) } function renderPreferencesForm (subject, klass, preferencesForm, context) { var prefContainer = context.dom.createElement('div') - pad.participationObject(subject, subject.doc(), context.me).then(participation => { - let dom = context.dom - function heading (text) { - prefContainer.appendChild(dom.createElement('h5')).textContent = text - } - heading('My view of this ' + context.noun) - widgets.appendForm(dom, prefContainer, {}, participation, preferencesForm, subject.doc(), - (ok, mes) => { if (!ok) widgets.complain(context, mes) }) + pad.participationObject(subject, subject.doc(), context.me).then( + participation => { + const dom = context.dom + function heading (text) { + prefContainer.appendChild(dom.createElement('h5')).textContent = text + } + heading('My view of this ' + context.noun) + widgets.appendForm( + dom, + prefContainer, + {}, + participation, + preferencesForm, + subject.doc(), + (ok, mes) => { + if (!ok) widgets.complain(context, mes) + } + ) - heading('Everyone\'s view of this ' + context.noun) - recordSharedPreferences(subject, context).then(context => { - var sharedPreferences = context.sharedPreferences - widgets.appendForm(dom, prefContainer, {}, sharedPreferences, preferencesForm, subject.doc(), - (ok, mes) => { if (!ok) widgets.complain(context, mes) }) + heading("Everyone's view of this " + context.noun) + recordSharedPreferences(subject, context).then(context => { + var sharedPreferences = context.sharedPreferences + widgets.appendForm( + dom, + prefContainer, + {}, + sharedPreferences, + preferencesForm, + subject.doc(), + (ok, mes) => { + if (!ok) widgets.complain(context, mes) + } + ) - heading('My default view of any ' + context.noun) - recordPersonalDefaults(klass, context).then(context => { - widgets.appendForm(dom, prefContainer, {}, context.personalDefaults, preferencesForm, context.preferencesFile, - (ok, mes) => { if (!ok) widgets.complain(context, mes) }) - }, err => { - widgets.complain(context, err) + heading('My default view of any ' + context.noun) + recordPersonalDefaults(klass, context).then( + context => { + widgets.appendForm( + dom, + prefContainer, + {}, + context.personalDefaults, + preferencesForm, + context.preferencesFile, + (ok, mes) => { + if (!ok) widgets.complain(context, mes) + } + ) + }, + err => { + widgets.complain(context, err) + } + ) }) - }) - }, err => { // parp object fails - prefContainer.appendChild(widgets.errorMessageBlock(context.dom, err)) - }) + }, + err => { + // parp object fails + prefContainer.appendChild(widgets.errorMessageBlock(context.dom, err)) + } + ) return prefContainer } @@ -135,8 +201,10 @@ function toJS (term) { if (term.datatype.equals(ns.xsd('boolean'))) { return term.value === '1' } - if (term.datatype.equals(ns.xsd('dateTime')) || - term.datatype.equals(ns.xsd('date'))) { + if ( + term.datatype.equals(ns.xsd('dateTime')) || + term.datatype.equals(ns.xsd('date')) + ) { return new Date(term.value) } if ( @@ -157,24 +225,30 @@ function getPreferencesForClass (subject, klass, predicates, context) { recordSharedPreferences(subject, context).then(context => { var sharedPreferences = context.sharedPreferences if (context.me) { - pad.participationObject(subject, subject.doc(), context.me).then(participation => { - recordPersonalDefaults(klass, context).then(context => { - var results = [] - var personalDefaults = context.personalDefaults - predicates.forEach(pred => { - // Order of preference: My settings on object, Global settings on object, my settings on class - let v1 = kb.any(participation, pred) || kb.any(sharedPreferences, pred) || kb.any(personalDefaults, pred) - if (v1) { - results[pred.uri] = toJS(v1) - } - }) - resolve(results) + pad + .participationObject(subject, subject.doc(), context.me) + .then(participation => { + recordPersonalDefaults(klass, context).then(context => { + var results = [] + var personalDefaults = context.personalDefaults + predicates.forEach(pred => { + // Order of preference: My settings on object, Global settings on object, my settings on class + const v1 = + kb.any(participation, pred) || + kb.any(sharedPreferences, pred) || + kb.any(personalDefaults, pred) + if (v1) { + results[pred.uri] = toJS(v1) + } + }) + resolve(results) + }, reject) }, reject) - }, reject) - } else { // no user defined, just use common prefs + } else { + // no user defined, just use common prefs var results = [] predicates.forEach(pred => { - let v1 = kb.any(sharedPreferences, pred) + const v1 = kb.any(sharedPreferences, pred) if (v1) { results[pred.uri] = toJS(v1) } diff --git a/src/signin.js b/src/signin.js index 492b2f1ee..e52a2eeee 100644 --- a/src/signin.js +++ b/src/signin.js @@ -6,7 +6,7 @@ * * Many functions in this module take a context object, add to it, and return a promise of it. */ - /* global localStorage confirm alert */ +/* global localStorage confirm alert $SolidTestEnvironment */ // const Solid = require('solid-client') const SolidTls = require('solid-auth-tls') @@ -31,7 +31,7 @@ const ns = UI.ns const kb = UI.store module.exports = { - checkUser, // Async + checkUser, // Async currentUser, // Sync defaultTestUser, // Sync filterAvailablePanes, // Async @@ -57,7 +57,7 @@ module.exports = { // const userCheckSite = 'https://databox.me/' // Look for and load the User who has control over it -function findOriginOwner (doc, callback) { +function findOriginOwner (doc, _callback) { var uri = doc.uri || doc var i = uri.indexOf('://') if (i < 0) return false @@ -94,7 +94,7 @@ function saveUser (webId, context) { let webIdUri, me if (webId) { webIdUri = webId.uri || webId - let me = $rdf.namedNode(webIdUri) + const me = $rdf.namedNode(webIdUri) if (context) { context.me = me } @@ -108,7 +108,7 @@ function saveUser (webId, context) { */ function defaultTestUser () { // Check for offline override - let offlineId = offlineTestID() + const offlineId = offlineTestID() if (offlineId) { return offlineId @@ -120,11 +120,11 @@ function defaultTestUser () { /** Checks syncronously whether user is logged in * * @returns Named Node or null -*/ + */ function currentUser () { - let str = localStorage['solid-auth-client'] + const str = localStorage['solid-auth-client'] if (str) { - let da = JSON.parse(str) + const da = JSON.parse(str) if (da.session && da.session.webId) { // @@ check has not expired return $rdf.sym(da.session.webId) @@ -142,15 +142,16 @@ function currentUser () { * @returns {Promise} */ function logIn (context) { - let me = defaultTestUser() // me is a NamedNode or null + const me = defaultTestUser() // me is a NamedNode or null if (me) { context.me = me return Promise.resolve(context) } - return new Promise((resolve) => { - checkUser().then(webId => { // Already logged in? + return new Promise(resolve => { + checkUser().then(webId => { + // Already logged in? if (webId) { context.me = $rdf.sym(webId) console.log('logIn: Already logged in as ' + context.me) @@ -159,7 +160,7 @@ function logIn (context) { if (!context.div || !context.dom) { return resolve(context) } - const box = loginStatusBox(context.dom, (webIdUri) => { + const box = loginStatusBox(context.dom, webIdUri => { saveUser(webIdUri, context) resolve(context) // always pass growing context }) @@ -178,13 +179,15 @@ function logIn (context) { * @returns {Promise} Resolves with the context after login / fetch */ function logInLoadProfile (context) { - if (context.publicProfile) { return Promise.resolve(context) } // already done + if (context.publicProfile) { + return Promise.resolve(context) + } // already done const fetcher = UI.store.fetcher var profileDocument return new Promise(function (resolve, reject) { return logIn(context) .then(context => { - let webID = context.me + const webID = context.me if (!webID) { return reject(new Error('Could not log in')) } @@ -192,20 +195,29 @@ function logInLoadProfile (context) { // Load the profile into the knowledge base (fetcher.store) // withCredentials: Web arch should let us just load by turning off creds helps CORS // reload: Gets around a specifc old Chrome bug caching/origin/cors - fetcher.load(profileDocument, {withCredentials: false, cache: 'reload'}) - .then(response => { + fetcher + .load(profileDocument, { withCredentials: false, cache: 'reload' }) + .then(_response => { context.publicProfile = profileDocument resolve(context) }) .catch(err => { - let message = 'Logged in but cannot load profile ' + profileDocument + ' : ' + err + const message = + 'Logged in but cannot load profile ' + + profileDocument + + ' : ' + + err if (context.div && context.dom) { - context.div.appendChild(UI.widgets.errorMessageBlock(context.dom, message)) + context.div.appendChild( + UI.widgets.errorMessageBlock(context.dom, message) + ) } reject(message) }) }) - .catch(err => { reject(new Error("Can't log in: " + err)) }) + .catch(err => { + reject(new Error("Can't log in: " + err)) + }) }) } @@ -228,33 +240,43 @@ function logInLoadPreferences (context) { return new Promise(function (resolve, reject) { return logInLoadProfile(context) .then(context => { - let preferencesFile = kb.any(context.me, UI.ns.space('preferencesFile')) + const preferencesFile = kb.any( + context.me, + UI.ns.space('preferencesFile') + ) function complain (message) { message = 'logInLoadPreferences: ' + message if (statusArea) { // statusArea.innerHTML = '' - statusArea.appendChild(UI.widgets.errorMessageBlock(context.dom, message)) + statusArea.appendChild( + UI.widgets.errorMessageBlock(context.dom, message) + ) } console.log(message) reject(new Error(message)) } /** Are we working cross-origin? - * - * @returns {Boolean} True if we are in a webapp at an origin, and the file origin is different - */ + * + * @returns {Boolean} True if we are in a webapp at an origin, and the file origin is different + */ function differentOrigin () { - return window.location && (window.location.origin + '/' !== preferencesFile.site().uri) + return ( + window.location && + window.location.origin + '/' !== preferencesFile.site().uri + ) } if (!preferencesFile) { - let message = "Can't find a preferences file pointer in profile " + context.publicProfile + const message = + "Can't find a preferences file pointer in profile " + + context.publicProfile return reject(new Error(message)) } // //// Load preferences file return kb.fetcher - .load(preferencesFile, {withCredentials: true}) + .load(preferencesFile, { withCredentials: true }) .then(function () { if (progressDisplay) { progressDisplay.parentNode.removeChild(progressDisplay) @@ -262,37 +284,66 @@ function logInLoadPreferences (context) { context.preferencesFile = preferencesFile return resolve(context) }) - .catch(function (err) { // Really important to look at why - let status = err.status - let message = err.message - console.log('HTTP status ' + status + ' for pref file ' + preferencesFile) + .catch(function (err) { + // Really important to look at why + const status = err.status + const message = err.message + console.log( + 'HTTP status ' + status + ' for pref file ' + preferencesFile + ) let m2 if (status === 401) { - m2 = 'Strange - you are not authenticated (properly logged on) to read preferences file.' + m2 = + 'Strange - you are not authenticated (properly logged on) to read preferences file.' alert(m2) } else if (status === 403) { if (differentOrigin()) { - m2 = 'Unauthorized: Assuming prefs file blocked for origin ' + window.location.origin + m2 = + 'Unauthorized: Assuming prefs file blocked for origin ' + + window.location.origin context.preferencesFileError = m2 return resolve(context) } - m2 = 'You are not authorized to read your preferences file. This may be because you are using an untrusted web app.' + m2 = + 'You are not authorized to read your preferences file. This may be because you are using an untrusted web app.' console.warn(m2) } else if (status === 404) { - if (confirm('You do not currently have a Preferences file. Ok for me to create an empty one? ' + preferencesFile)) { + if ( + confirm( + 'You do not currently have a Preferences file. Ok for me to create an empty one? ' + + preferencesFile + ) + ) { // @@@ code me ... weird to have a name o fthe file but no file - alert('Sorry; I am not prepared to do this. Please create an empty file at ' + preferencesFile) - return complain(new Error('Sorry; no code yet to create a preferences file at ')) + alert( + 'Sorry; I am not prepared to do this. Please create an empty file at ' + + preferencesFile + ) + return complain( + new Error( + 'Sorry; no code yet to create a preferences file at ' + ) + ) } else { - reject(new Error('User declined to create a preferences file at ' + preferencesFile)) + reject( + new Error( + 'User declined to create a preferences file at ' + + preferencesFile + ) + ) } } else { - m2 = 'Strange: Error ' + status + ' trying to read your preferences file.' + message + m2 = + 'Strange: Error ' + + status + + ' trying to read your preferences file.' + + message alert(m2) } }) // load prefs file then }) - .catch(err => { // Fail initial login load prefs + .catch(err => { + // Fail initial login load prefs reject(new Error('(via loadPrefs) ' + err)) }) }) @@ -321,7 +372,9 @@ async function loadPrivateTypeIndex (context) { return loadIndex(context, ns.solid('privateTypeIndex'), false) } async function loadOneTypeIndex (context, isPublic) { - let predicate = isPublic ? ns.solid('publicTypeIndex') : ns.solid('privateTypeIndex') + const predicate = isPublic + ? ns.solid('publicTypeIndex') + : ns.solid('privateTypeIndex') return loadIndex(context, predicate, isPublic) } @@ -329,11 +382,16 @@ async function loadIndex (context, predicate, isPublic) { var ns = UI.ns var kb = UI.store - // Loading preferences is more than loading profile + // Loading preferences is more than loading profile try { - await isPublic ? logInLoadProfile(context) : logInLoadPreferences(context) + ;(await isPublic) + ? logInLoadProfile(context) + : logInLoadPreferences(context) } catch (err) { - UI.widgets.complain(context, 'loadPubicIndex: login and load problem ' + err) + UI.widgets.complain( + context, + 'loadPubicIndex: login and load problem ' + err + ) } var me = context.me var ixs @@ -344,21 +402,35 @@ async function loadIndex (context, predicate, isPublic) { context.index.public = ixs } else { if (!context.preferencesFileError) { - ixs = kb.each(me, ns.solid('privateTypeIndex'), undefined, context.preferencesFile) + ixs = kb.each( + me, + ns.solid('privateTypeIndex'), + undefined, + context.preferencesFile + ) context.index.private = ixs if (ixs.length === 0) { - UI.widgets.complain('Your preference file ' + context.preferencesFile + ' does not point to a private type index.') + UI.widgets.complain( + 'Your preference file ' + + context.preferencesFile + + ' does not point to a private type index.' + ) return context } } else { - console.log('We know your preferences file is noty available, so not bothering with private type indexes.') + console.log( + 'We know your preferences file is noty available, so not bothering with private type indexes.' + ) } } try { await kb.fetcher.load(ixs) } catch (err) { - UI.widgets.complain(context, 'loadPubicIndex: loading public type index ' + err) + UI.widgets.complain( + context, + 'loadPubicIndex: loading public type index ' + err + ) } return context } @@ -388,7 +460,7 @@ async function ensureTypeIndexes (context) { * Find one or mke one or fail * Many reasons for filing including script not having permission etc * -*/ + */ /** * Adds it output to the context * @see https://github.com/solid/solid/blob/master/proposals/data-discovery.md#discoverability @@ -414,10 +486,11 @@ async function ensureOneTypeIndex (context, isPublic) { try { await kb.fetcher.webOperation('PUT', newIndex.uri, { data: '# ' + new Date() + ' Blank initial Type index\n', - contentType: 'text/turtle'}) + contentType: 'text/turtle' + }) return context } catch (e) { - let msg = 'Error creating new index ' + e + const msg = 'Error creating new index ' + e widgets.complain(context, msg) } } // putIndex @@ -428,15 +501,29 @@ async function ensureOneTypeIndex (context, isPublic) { if (context.index[visibility].length === 0) { newIndex = $rdf.sym(relevant.dir().uri + visibility + 'TypeIndex.ttl') console.log('Linking to new fresh type index ' + newIndex) - if (!confirm('Ok to create a new empty index file at ' + newIndex + ', overwriting anything that was there?')) { - throw (new Error('cancelled by user')) + if ( + !confirm( + 'Ok to create a new empty index file at ' + + newIndex + + ', overwriting anything that was there?' + ) + ) { + throw new Error('cancelled by user') } console.log('Linking to new fresh type index ' + newIndex) - var addMe = [ $rdf.st(context.me, ns.solid(visibility + 'TypeIndex'), newIndex, relevant) ] + var addMe = [ + $rdf.st( + context.me, + ns.solid(visibility + 'TypeIndex'), + newIndex, + relevant + ) + ] try { await updatePromise([], addMe) } catch (err) { - let msg = 'Error saving type index link saving back ' + newIndex + ': ' + err + const msg = + 'Error saving type index link saving back ' + newIndex + ': ' + err UI.widgets.complain(context, msg) return context } @@ -444,19 +531,27 @@ async function ensureOneTypeIndex (context, isPublic) { console.log('Creating new fresh type index file' + newIndex) await putIndex(newIndex) context.index[visibility].push(newIndex) // @@ wait - } else { // officially exists + } else { + // officially exists var ixs = context.index[visibility] try { await kb.fetcher.load(ixs) } catch (err) { - UI.widgets.complain(context, 'ensureOneTypeIndex: loading indexes ' + err) + UI.widgets.complain( + context, + 'ensureOneTypeIndex: loading indexes ' + err + ) } } } // makeIndexIfNecesary try { await loadOneTypeIndex(context, isPublic) - console.log('ensureOneTypeIndex: Type index exists already ' + isPublic ? context.index.public[0] : context.index.private[0]) + console.log( + 'ensureOneTypeIndex: Type index exists already ' + isPublic + ? context.index.public[0] + : context.index.private[0] + ) return context } catch (error) { await makeIndexIfNecesary(context, isPublic) @@ -480,7 +575,8 @@ async function findAppInstances (context, klass, isPublic) { var kb = UI.store var ns = UI.ns var fetcher = UI.store.fetcher - if (isPublic === undefined) { // Then both public and private + if (isPublic === undefined) { + // Then both public and private await findAppInstances(context, klass, true) await findAppInstances(context, klass, false) return context @@ -489,14 +585,18 @@ async function findAppInstances (context, klass, isPublic) { const visibility = isPublic ? 'public' : 'private' try { await loadOneTypeIndex(context, isPublic) - } catch (err) { - - } + } catch (err) {} var thisIndex = context.index[visibility] - var registrations = thisIndex.map(ix => kb.each(undefined, ns.solid('forClass'), klass, ix)).flat() - var instances = registrations.map(reg => kb.each(reg, ns.solid('instance'))).flat() - var containers = registrations.map(reg => kb.each(reg, ns.solid('instanceContainer'))).flat() + var registrations = thisIndex + .map(ix => kb.each(undefined, ns.solid('forClass'), klass, ix)) + .flat() + var instances = registrations + .map(reg => kb.each(reg, ns.solid('instance'))) + .flat() + var containers = registrations + .map(reg => kb.each(reg, ns.solid('instanceContainer'))) + .flat() context.instances = context.instances || [] context.instances = context.instances.concat(instances) @@ -512,13 +612,18 @@ async function findAppInstances (context, klass, isPublic) { } catch (err) { var e = new Error('[FAI] Unable to load containers' + err) console.log(e) // complain - UI.widgets.complain(context, `Error looking for ${UI.utils.label(klass)}: ${err}`) + UI.widgets.complain( + context, + `Error looking for ${UI.utils.label(klass)}: ${err}` + ) // but then ignoire it // throw new Error(e) } for (var i = 0; i < containers.length; i++) { var cont = containers[i] - context.instances = context.instances.concat(kb.each(cont, ns.ldp('contains'))) + context.instances = context.instances.concat( + kb.each(cont, ns.ldp('contains')) + ) } return context } @@ -536,16 +641,19 @@ function updatePromise (updater, del, ins) { }) // promise } /* Register a new app in a type index -*/ + */ async function registerInTypeIndex (context, instance, klass, isPublic) { const kb = UI.store const ns = UI.ns await ensureOneTypeIndex(context, isPublic) const indexes = isPublic ? context.index.public : context.index.private - if (!indexes.length) throw new Error('registerInTypeIndex: What no type index?') + if (!indexes.length) { + throw new Error('registerInTypeIndex: What no type index?') + } const index = indexes[0] const registration = UI.widgets.newThing(index) - const ins = [ // See https://github.com/solid/solid/blob/master/proposals/data-discovery.md + const ins = [ + // See https://github.com/solid/solid/blob/master/proposals/data-discovery.md $rdf.st(registration, ns.rdf('type'), ns.solid('TypeRegistration'), index), $rdf.st(registration, ns.solid('forClass'), klass, index), $rdf.st(registration, ns.solid('instance'), instance, index) @@ -577,48 +685,78 @@ function registrationControl (context, instance, klass) { context.div.appendChild(box) return ensureTypeIndexes(context) - .then(function () { - box.innerHTML = '
' // 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 = kb.bnode()// @@ say for now - - var registrationStatements = function (index) { - var registrations = kb.each(undefined, ns.solid('instance'), instance) - .filter(function (r) { return kb.holds(r, ns.solid('forClass'), klass) }) - var reg = registrations.length ? registrations[0] : widgets.newThing(index) - return [ $rdf.st(reg, ns.solid('instance'), instance, index), - $rdf.st(reg, ns.solid('forClass'), klass, index) ] - } - - var index, statements + .then( + function () { + box.innerHTML = '
' // 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 = kb.bnode() // @@ say for now + + var registrationStatements = function (index) { + var registrations = kb + .each(undefined, ns.solid('instance'), instance) + .filter(function (r) { + return kb.holds(r, ns.solid('forClass'), klass) + }) + var reg = registrations.length + ? registrations[0] + : widgets.newThing(index) + return [ + $rdf.st(reg, ns.solid('instance'), instance, index), + $rdf.st(reg, ns.solid('forClass'), klass, index) + ] + } - if (context.index.public && context.index.public.length > 0) { - index = context.index.public[0] - statements = registrationStatements(index) - tbody.children[0].appendChild(widgets.buildCheckboxForm( - context.dom, UI.store, 'Public link to this ' + context.noun, null, statements, form, index)) - } + var index, statements + + if (context.index.public && context.index.public.length > 0) { + index = context.index.public[0] + statements = registrationStatements(index) + tbody.children[0].appendChild( + widgets.buildCheckboxForm( + context.dom, + UI.store, + 'Public link to this ' + context.noun, + null, + statements, + form, + index + ) + ) + } - if (context.index.private && context.index.private.length > 0) { - index = context.index.private[0] - statements = registrationStatements(index) - tbody.children[1].appendChild(widgets.buildCheckboxForm( - context.dom, UI.store, 'Personal note of this ' + context.noun, null, statements, form, index)) - } - return context - }, - function (e) { - var msg - if (context.preferencesFileError) { - msg = '(Preferences not available)' - context.div.appendChild(dom.createElement('p')).textContent = msg - } else { - msg = 'registrationControl: Type indexes not available: ' + e - context.div.appendChild(UI.widgets.errorMessageBlock(context.dom, e)) + if (context.index.private && context.index.private.length > 0) { + index = context.index.private[0] + statements = registrationStatements(index) + tbody.children[1].appendChild( + widgets.buildCheckboxForm( + context.dom, + UI.store, + 'Personal note of this ' + context.noun, + null, + statements, + form, + index + ) + ) + } + return context + }, + function (e) { + var msg + if (context.preferencesFileError) { + msg = '(Preferences not available)' + context.div.appendChild(dom.createElement('p')).textContent = msg + } else { + msg = 'registrationControl: Type indexes not available: ' + e + context.div.appendChild(UI.widgets.errorMessageBlock(context.dom, e)) + } + console.log(msg) } - console.log(msg) - }) + ) .catch(function (e) { var msg = 'registrationControl: Error making panel:' + e context.div.appendChild(UI.widgets.errorMessageBlock(context.dom, e)) @@ -641,50 +779,58 @@ function registrationList (context, options) { var box = dom.createElement('div') context.div.appendChild(box) - return ensureTypeIndexes(context) - .then((indexes) => { - box.innerHTML = '
' // 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 (options[visibility]) { - ix = ix.concat(context.index[visibility][0]) - sts = sts.concat(kb.statementsMatching( - undefined, ns.solid('instance'), undefined, context.index[visibility][0])) - } - }) + return ensureTypeIndexes(context).then(_indexes => { + box.innerHTML = '
' // 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 (options[visibility]) { + ix = ix.concat(context.index[visibility][0]) + sts = sts.concat( + kb.statementsMatching( + undefined, + ns.solid('instance'), + undefined, + context.index[visibility][0] + ) + ) + } + }) - for (var i = 0; i < sts.length; i++) { - var statement = sts[i] - // var cla = statement.subject - var inst = statement.object - // if (false) { - // var tr = table.appendChild(dom.createElement('tr')) - // var anchor = tr.appendChild(dom.createElement('a')) - // anchor.setAttribute('href', inst.uri) - // anchor.textContent = utils.label(inst) - // } else { - // } - - var deleteInstance = function (x) { - kb.updater.update([statement], [], function (uri, ok, errorBody) { - if (ok) { - console.log('Removed from index: ' + statement.subject) - } else { - console.log('Error: Cannot delete ' + statement + ': ' + errorBody) - } - }) - } - var opts = { deleteFunction: deleteInstance } - var tr = widgets.personTR(dom, ns.solid('instance'), inst, opts) - table.appendChild(tr) + for (var i = 0; i < sts.length; i++) { + var statement = sts[i] + // var cla = statement.subject + var inst = statement.object + // if (false) { + // var tr = table.appendChild(dom.createElement('tr')) + // var anchor = tr.appendChild(dom.createElement('a')) + // anchor.setAttribute('href', inst.uri) + // anchor.textContent = utils.label(inst) + // } else { + // } + + var deleteInstance = function (_x) { + kb.updater.update([statement], [], function (uri, ok, errorBody) { + if (ok) { + console.log('Removed from index: ' + statement.subject) + } else { + console.log('Error: Cannot delete ' + statement + ': ' + errorBody) + } + }) } + var opts = { deleteFunction: deleteInstance } + var tr = widgets.personTR(dom, ns.solid('instance'), inst, opts) + table.appendChild(tr) + } - /* + /* //var containers = kb.each(klass, ns.solid('instanceContainer')); if (containers.length) { fetcher.load(containers).then(function(xhrs){ @@ -696,8 +842,8 @@ function registrationList (context, options) { } */ - return context - }) + return context + }) } /** @@ -717,23 +863,29 @@ function registrationList (context, options) { */ function setACLUserPublic (docURI, me, options) { const kb = UI.store - let aclDoc = kb.any(kb.sym(docURI), - kb.sym('http://www.iana.org/assignments/link-relations/acl')) + const aclDoc = kb.any( + kb.sym(docURI), + kb.sym('http://www.iana.org/assignments/link-relations/acl') + ) return Promise.resolve() .then(() => { - if (aclDoc) { return aclDoc } + if (aclDoc) { + return aclDoc + } - return fetchACLRel(docURI) - .catch(err => { - throw new Error(`Error fetching rel=ACL header for ${docURI}: ${err}`) - }) + return fetchACLRel(docURI).catch(err => { + throw new Error(`Error fetching rel=ACL header for ${docURI}: ${err}`) + }) }) .then(aclDoc => { - let aclText = genACLText(docURI, me, aclDoc.uri, options) + const aclText = genACLText(docURI, me, aclDoc.uri, options) - return kb.fetcher.webOperation('PUT', aclDoc.uri, - { data: aclText, contentType: 'text/turtle' }) + return kb.fetcher + .webOperation('PUT', aclDoc.uri, { + data: aclText, + contentType: 'text/turtle' + }) .then(result => { if (!result.ok) { throw new Error('Error writing ACL text: ' + result.error) @@ -752,21 +904,22 @@ function fetchACLRel (docURI) { const kb = UI.store const fetcher = kb.fetcher - return fetcher.load(docURI) - .then(result => { - if (!result.ok) { - throw new Error('fetchACLRel: While loading:' + result.error) - } + return fetcher.load(docURI).then(result => { + if (!result.ok) { + throw new Error('fetchACLRel: While loading:' + result.error) + } - let aclDoc = kb.any(kb.sym(docURI), - kb.sym('http://www.iana.org/assignments/link-relations/acl')) + const aclDoc = kb.any( + kb.sym(docURI), + kb.sym('http://www.iana.org/assignments/link-relations/acl') + ) - if (!aclDoc) { - throw new Error('fetchACLRel: No Link rel=ACL header for ' + docURI) - } + if (!aclDoc) { + throw new Error('fetchACLRel: No Link rel=ACL header for ' + docURI) + } - return aclDoc - }) + return aclDoc + }) } /** @@ -811,19 +964,26 @@ function genACLText (docURI, me, aclURI, options = {}) { * @returns {NamedNode|null} */ function offlineTestID () { - if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.username) { // Test setup + if ( + typeof $SolidTestEnvironment !== 'undefined' && + $SolidTestEnvironment.username + ) { + // Test setup console.log('Assuming the user is ' + $SolidTestEnvironment.username) return $rdf.sym($SolidTestEnvironment.username) } - if (typeof document !== 'undefined' && - document.location && ('' + document.location).slice(0, 16) === 'http://localhost') { + 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 = kb.any(subject, UI.ns.acl('owner')); // when testing on plane with no webid - */ + */ console.log('Assuming user is ' + id) return $rdf.sym(id) } @@ -857,28 +1017,32 @@ function signInOrSignUpBox (dom, setUserCallback, options) { box.style = 'display:flex;' // Sign in button with PopUP - let signInPopUpButton = dom.createElement('input') // multi + const signInPopUpButton = dom.createElement('input') // multi box.appendChild(signInPopUpButton) signInPopUpButton.setAttribute('type', 'button') signInPopUpButton.setAttribute('value', 'Log in') - signInPopUpButton.setAttribute('style', signInButtonStyle + 'background-color: #eef;') - - signInPopUpButton.addEventListener('click', () => { - var offline = offlineTestID() - if (offline) return setUserCallback(offline.uri) - return solidAuthClient.popupLogin() - .then(session => { - let webIdURI = session.webId + signInPopUpButton.setAttribute( + 'style', + signInButtonStyle + 'background-color: #eef;' + ) + + signInPopUpButton.addEventListener( + 'click', + () => { + var offline = offlineTestID() + if (offline) return setUserCallback(offline.uri) + return solidAuthClient.popupLogin().then(session => { + const webIdURI = session.webId // setUserCallback(webIdURI) var divs = dom.getElementsByClassName(magicClassName) console.log('Logged in, ' + divs.length + ' panels to be serviced') // At the same time, satiffy all the other login boxes for (let i = 0; i < divs.length; i++) { - let div = divs[i] + const div = divs[i] if (div.setUserCallback) { try { div.setUserCallback(webIdURI) - let parent = div.parentNode + const parent = div.parentNode if (parent) { parent.removeChild(div) } @@ -889,22 +1053,31 @@ function signInOrSignUpBox (dom, setUserCallback, options) { } } }) - }, false) + }, + false + ) // Sign up button - let signupButton = dom.createElement('input') + const signupButton = dom.createElement('input') box.appendChild(signupButton) signupButton.setAttribute('type', 'button') signupButton.setAttribute('value', 'Sign Up for Solid') - signupButton.setAttribute('style', signInButtonStyle + 'background-color: #efe;') - - signupButton.addEventListener('click', function (e) { - let signupMgr = new SolidTls.Signup() - signupMgr.signup().then(function (uri) { - console.log('signInOrSignUpBox signed up ' + uri) - setUserCallback(uri) - }) - }, false) + signupButton.setAttribute( + 'style', + signInButtonStyle + 'background-color: #efe;' + ) + + signupButton.addEventListener( + 'click', + function (_event) { + const signupMgr = new SolidTls.Signup() + signupMgr.signup().then(function (uri) { + console.log('signInOrSignUpBox signed up ' + uri) + setUserCallback(uri) + }) + }, + false + ) return box } @@ -922,7 +1095,7 @@ function webIdFromSession (session) { /** * @returns {Promise} Resolves with WebID URI or null */ - /* +/* function checkCurrentUser () { return checkUser() } @@ -942,13 +1115,13 @@ function checkUser (setUserCallback) { // doc = kb.any(doc, UI.ns.link('userMirror')) || doc - return solidAuthClient.currentSession() + return solidAuthClient + .currentSession() - .then(webIdFromSession, - err => { - console.log('Error fetching currentSession:', err) - return null - }) + .then(webIdFromSession, err => { + console.log('Error fetching currentSession:', err) + return null + }) .then(webId => { // if (webId.startsWith('dns:')) { // legacy rww.io pseudo-users @@ -974,43 +1147,51 @@ function checkUser (setUserCallback) { * * @returns {Element} */ -function loginStatusBox (dom, listener, options) { // 20190630 +function loginStatusBox (dom, listener, options) { + // 20190630 var me = defaultTestUser() var box = dom.createElement('div') function setIt (newidURI) { - if (!newidURI) { return } + if (!newidURI) { + return + } - let uri = newidURI.uri || newidURI -// UI.preferences.set('me', uri) + const uri = newidURI.uri || newidURI + // UI.preferences.set('me', uri) me = $rdf.sym(uri) box.refresh() if (listener) listener(me.uri) } - function logoutButtonHandler (event) { + function logoutButtonHandler (_event) { // UI.preferences.set('me', '') - solidAuthClient.logout().then(function () { - var message = 'Your Web ID was ' + me + '. It has been forgotten.' - me = null - try { - UI.log.alert(message) - } catch (e) { - window.alert(message) + solidAuthClient.logout().then( + function () { + var message = 'Your Web ID was ' + me + '. It has been forgotten.' + me = null + try { + UI.log.alert(message) + } catch (e) { + window.alert(message) + } + box.refresh() + if (listener) listener(null) + }, + err => { + alert('Fail to log out:' + err) } - box.refresh() - if (listener) listener(null) - }, err => { - alert('Fail to log out:' + err) - }) + ) } var logoutButton = function (me, options) { options = options || {} - const signInButtonStyle = options.buttonStyle || getDefaultSignInButtonStyle() + const signInButtonStyle = + options.buttonStyle || getDefaultSignInButtonStyle() var logoutLabel = 'Web ID logout' if (me) { - var nick = UI.store.any(me, UI.ns.foaf('nick')) || + var nick = + UI.store.any(me, UI.ns.foaf('nick')) || UI.store.any(me, UI.ns.foaf('name')) if (nick) { logoutLabel = 'Logout ' + nick.value @@ -1020,30 +1201,36 @@ function loginStatusBox (dom, listener, options) { // 20190630 // signOutButton.className = 'WebIDCancelButton' signOutButton.setAttribute('type', 'button') signOutButton.setAttribute('value', logoutLabel) - signOutButton.setAttribute('style', signInButtonStyle + 'background-color: #eee;') + signOutButton.setAttribute( + 'style', + signInButtonStyle + 'background-color: #eee;' + ) signOutButton.addEventListener('click', logoutButtonHandler, false) return signOutButton } box.refresh = function () { - solidAuthClient.currentSession().then(session => { - if (session && session.webId) { - me = $rdf.sym(session.webId) - } else { - me = null - } - if ((me && box.me !== me.uri) || (!me && box.me)) { - widgets.clearElement(box) - if (me) { - box.appendChild(logoutButton(me, options)) + solidAuthClient.currentSession().then( + session => { + if (session && session.webId) { + me = $rdf.sym(session.webId) } else { - box.appendChild(signInOrSignUpBox(dom, setIt, options)) + me = null + } + 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 + }, + err => { + alert('loginStatusBox: ' + err) } - box.me = me ? me.uri : null - }, err => { - alert('loginStatusBox: ' + err) - }) + ) } if (solidAuthClient.trackSession) { @@ -1057,7 +1244,7 @@ function loginStatusBox (dom, listener, options) { // 20190630 }) } - box.me = '99999' // Force refresh + box.me = '99999' // Force refresh box.refresh() return box } @@ -1093,7 +1280,9 @@ function selectWorkspace (dom, appDetails, callbackWS) { var box = dom.createElement('div') var context = { me: me, dom: dom, div: box } - var say = function (s) { box.appendChild(UI.widgets.errorMessageBlock(dom, s)) } + var say = function (s) { + box.appendChild(UI.widgets.errorMessageBlock(dom, s)) + } var figureOutBase = function (ws) { var newBase = kb.any(ws, UI.ns.space('uriPrefix')) @@ -1118,27 +1307,42 @@ function selectWorkspace (dom, appDetails, callbackWS) { var newBase = null // A workspace specifically defined in the private preferences file: - var w = kb.statementsMatching(id, UI.ns.space('workspace'), // Only trust prefs file here - undefined, preferencesFile).map(function (st) { return st.object }) + var w = kb + .statementsMatching( + id, + UI.ns.space('workspace'), // Only trust prefs file here + undefined, + preferencesFile + ) + .map(function (st) { + return st.object + }) // A workspace in a storage in the public profile: - var storages = kb.each(id, UI.ns.space('storage')) // @@ No provenance requirement at the moment + var storages = kb.each(id, UI.ns.space('storage')) // @@ No provenance requirement at the moment storages.map(function (s) { w = w.concat(kb.each(s, UI.ns.ldp('contains'))) }) if (w.length === 1) { - say('Workspace used: ' + w[0].uri) // @@ allow user to see URI + say('Workspace used: ' + w[0].uri) // @@ allow user to see URI newBase = figureOutBase(w[0]) // callbackWS(w[0], newBase) } else if (w.length === 0) { - say("You don't seem to have any workspaces. You have " + storages.length + ' storages.') + say( + "You don't seem to have any workspaces. You have " + + storages.length + + ' storages.' + ) } // Prompt for ws selection or creation // say( w.length + " workspaces for " + id + "Chose one."); var table = dom.createElement('table') - table.setAttribute('style', 'border-collapse:separate; border-spacing: 0.5em;') + table.setAttribute( + 'style', + 'border-collapse:separate; border-spacing: 0.5em;' + ) // var popup = window.open(undefined, '_blank', { height: 300, width:400 }, false) box.appendChild(table) @@ -1149,14 +1353,18 @@ function selectWorkspace (dom, appDetails, callbackWS) { box.appendChild(dom.createElement('hr')) // @@ var p = box.appendChild(dom.createElement('p')) - p.textContent = 'Where would you like to store the data for the ' + noun + '? ' + + p.textContent = + 'Where would you like to store the data for the ' + + noun + + '? ' + 'Give the URL of the directory where you would like the data stored.' var baseField = box.appendChild(dom.createElement('input')) baseField.setAttribute('type', 'text') baseField.size = 80 // really a string baseField.label = 'base URL' baseField.autocomplete = 'on' - if (newBase) { // set to default + if (newBase) { + // set to default baseField.value = newBase } @@ -1166,7 +1374,7 @@ function selectWorkspace (dom, appDetails, callbackWS) { var button = box.appendChild(dom.createElement('button')) button.textContent = 'Start new ' + noun + ' at this URI' - button.addEventListener('click', function (e) { + button.addEventListener('click', function (_event) { var newBase = baseField.value if (newBase.slice(-1) !== '/') { newBase += '/' @@ -1178,11 +1386,15 @@ function selectWorkspace (dom, appDetails, callbackWS) { // var row = 0 w = w.filter(function (x) { - return !(kb.holds(x, UI.ns.rdf('type'), // Ignore master workspaces - UI.ns.space('MasterWorkspace'))) + return !kb.holds( + x, + UI.ns.rdf('type'), // Ignore master workspaces + UI.ns.space('MasterWorkspace') + ) }) var col1, col2, col3, tr, ws, style, comment - var cellStyle = 'height: 3em; margin: 1em; padding: 1em white; border-radius: 0.3em;' + var cellStyle = + 'height: 3em; margin: 1em; padding: 1em white; border-radius: 0.3em;' var deselectedStyle = cellStyle + 'border: 0px;' // var selectedStyle = cellStyle + 'border: 1px solid black;' for (var i = 0; i < w.length; i++) { @@ -1199,8 +1411,14 @@ function selectWorkspace (dom, appDetails, callbackWS) { style = kb.any(ws, UI.ns.ui('style')) if (style) { style = style.value - } else { // Otherise make up arbitrary colour - var hash = function (x) { return x.split('').reduce(function (a, b) { a = ((a << 5) - a) + b.charCodeAt(0); return a & a }, 0) } + } else { + // Otherise make up arbitrary colour + var hash = function (x) { + return x.split('').reduce(function (a, b) { + a = (a << 5) - a + b.charCodeAt(0) + return a & a + }, 0) + } var bgcolor = '#' + ((hash(ws.uri) & 0xffffff) | 0xc0c0c0).toString(16) // c0c0c0 forces pale style = 'color: black ; background-color: ' + bgcolor + ';' } @@ -1222,11 +1440,15 @@ function selectWorkspace (dom, appDetails, callbackWS) { table.appendChild(tr) var addMyListener = function (container, detail, style, ws1) { - container.addEventListener('click', function (e) { - col3.textContent = detail - col3.setAttribute('style', style) - col3.appendChild(addContinueButton(ws1)) - }, true) // capture vs bubble + container.addEventListener( + 'click', + function (_event) { + col3.textContent = detail + col3.setAttribute('style', style) + col3.appendChild(addContinueButton(ws1)) + }, + true + ) // capture vs bubble } var addContinueButton = function (selectedWorkspace) { @@ -1236,17 +1458,26 @@ function selectWorkspace (dom, appDetails, callbackWS) { var newBase = figureOutBase(selectedWorkspace) baseField.value = newBase // show user proposed URI - button.addEventListener('click', function (e) { - button.disabled = true - callbackWS(selectedWorkspace, newBase) - button.textContent = '---->' - }, true) // capture vs bubble + button.addEventListener( + 'click', + function (_event) { + button.disabled = true + callbackWS(selectedWorkspace, newBase) + button.textContent = '---->' + }, + true + ) // capture vs bubble return button } comment = kb.any(ws, UI.ns.rdfs('comment')) comment = comment ? comment.value : 'Use this workspace' - addMyListener(col2, comment ? comment.value : '', deselectedStyle + style, ws) + addMyListener( + col2, + comment ? comment.value : '', + deselectedStyle + style, + ws + ) } // last line with "Make new workspace" @@ -1259,13 +1490,13 @@ function selectWorkspace (dom, appDetails, callbackWS) { table.appendChild(trLast) } // displayOptions - logInLoadPreferences(context) // kick off async operation + logInLoadPreferences(context) // kick off async operation .then(displayOptions) .catch(err => { box.appendChild(UI.widgets.errorMessageBlock(err)) }) - return box // return the box element, while login proceeds + return box // return the box element, while login proceeds } // selectWorkspace /** @@ -1290,32 +1521,49 @@ function newAppInstance (dom, appDetails, callback) { b.setAttribute('type', 'button') div.appendChild(b) b.innerHTML = 'Make new ' + appDetails.noun - b.addEventListener('click', (e) => { - div.appendChild(selectWorkspace(dom, appDetails, gotWS)) - }, false) + b.addEventListener( + 'click', + _event => { + div.appendChild(selectWorkspace(dom, appDetails, gotWS)) + }, + false + ) div.appendChild(b) return div } async function getUserRoles () { try { - const { me, preferencesFile, preferencesFileError } = await logInLoadPreferences({}) + const { + me, + preferencesFile, + preferencesFileError + } = await logInLoadPreferences({}) if (preferencesFileError) { throw new Error(preferencesFileError) } return UI.store.each(me, ns.rdf('type'), null, preferencesFile.doc()) } catch (error) { - console.warn('Unable to fetch your preferences - this was the error: ', error) + console.warn( + 'Unable to fetch your preferences - this was the error: ', + error + ) } return [] } async function filterAvailablePanes (panes) { const userRoles = await getUserRoles() - return Object.values(panes).filter(pane => isMatchingAudience(pane, userRoles)) + return Object.values(panes).filter(pane => + isMatchingAudience(pane, userRoles) + ) } function isMatchingAudience (pane, userRoles) { const audience = pane.audience || [] - return audience.reduce((isMatch, audienceRole) => isMatch && userRoles.find(role => role.equals(audienceRole)), true) + return audience.reduce( + (isMatch, audienceRole) => + isMatch && userRoles.find(role => role.equals(audienceRole)), + true + ) } diff --git a/src/store.js b/src/store.js index 1e9a4608e..f6ab92c3b 100644 --- a/src/store.js +++ b/src/store.js @@ -2,7 +2,7 @@ // var rdf = require('rdflib') -var store = module.exports = rdf.graph() // Make a Quad store +var store = (module.exports = rdf.graph()) // Make a Quad store rdf.fetcher(store) // Attach a web I/O module, store.fetcher store.updater = new rdf.UpdateManager(store) // Add real-time live updates store.updater diff --git a/src/style.js b/src/style.js index eda4b912e..31746e7c1 100644 --- a/src/style.js +++ b/src/style.js @@ -5,11 +5,13 @@ // These must all end with semicolon so they can be appended to. module.exports = { - textInputStyle: 'background-color: #eef; padding: 0.5em; border: .5em solid white; font-size: 100%;', - buttonStyle: 'background-color: #fff; padding: 0.5em; border: .01em solid white; font-size: 100%;', // 'background-color: #eef; -// The width of the text field must bot be 100% or it switches to overlapping - messageBodyStyle: 'white-space: pre-wrap; width: 99%; font-size:100%; border: 0.07em solid #eee; padding: .3em 0.5em; margin: 0.1em;', + textInputStyle: + 'background-color: #eef; padding: 0.5em; border: .5em solid white; font-size: 100%;', + buttonStyle: + 'background-color: #fff; padding: 0.5em; border: .01em solid white; font-size: 100%;', // 'background-color: #eef; + // The width of the text field must bot be 100% or it switches to overlapping + messageBodyStyle: + 'white-space: pre-wrap; width: 99%; font-size:100%; border: 0.07em solid #eee; padding: .3em 0.5em; margin: 0.1em;', pendingeditModifier: 'color: #bbb;', highlightColor: '#7C4DFF' // Solid lavendar https://design.inrupt.com/atomic-core/?cat=Core - } diff --git a/src/table.js b/src/table.js index 9ae5f3b14..7ae2b1f85 100644 --- a/src/table.js +++ b/src/table.js @@ -103,7 +103,7 @@ module.exports = function renderTableViewPane (doc, options) { // Save a refresh function for use by caller resultDiv.refresh = function () { runQuery(table.query, table.logicalRows, table.columns, table) - // updateTable(givenQuery, mostCommonType) // This could be a lot more incremental and efficient + // updateTable(givenQuery, mostCommonType) // This could be a lot more incremental and efficient } // A specifically asked-for query @@ -115,10 +115,10 @@ module.exports = function renderTableViewPane (doc, options) { // Find the most common type and select it by default var s = calculateTable() - allType = s[0]; types = s[1] + allType = s[0] + types = s[1] if (!tableClass) { - typeSelectorDiv.appendChild( - generateTypeSelector(allType, types)) + typeSelectorDiv.appendChild(generateTypeSelector(allType, types)) } mostCommonType = getMostCommonType(types) @@ -132,7 +132,7 @@ module.exports = function renderTableViewPane (doc, options) { return resultDiv // ///////////////////////////////////////////////////////////////// -/* + /* function closeDialog (dialog) { dialog.parentNode.removeChild(dialog) } @@ -242,9 +242,7 @@ module.exports = function renderTableViewPane (doc, options) { } // _row a type - query.pat.add(rowVar, - UI.ns.rdf('type'), - queryType) + query.pat.add(rowVar, UI.ns.rdf('type'), queryType) } // Generate OPTIONAL column selectors. @@ -257,9 +255,7 @@ module.exports = function renderTableViewPane (doc, options) { var formula = kb.formula() - formula.add(rowVar, - column.predicate, - column.getVariable()) + formula.add(rowVar, column.predicate, column.getVariable()) query.pat.optional.push(formula) } @@ -419,7 +415,11 @@ module.exports = function renderTableViewPane (doc, options) { this.checkValue = function (term) { var termType = term.termType - if (this.possiblyLiteral && termType !== 'Literal' && termType !== 'NamedNode') { + if ( + this.possiblyLiteral && + termType !== 'Literal' && + termType !== 'NamedNode' + ) { this.possiblyNumber = false this.possiblyLiteral = false } else if (this.possiblyNumber) { @@ -467,17 +467,25 @@ module.exports = function renderTableViewPane (doc, options) { } this.setPredicate = function (predicate, inverse, other) { - if (inverse) { // variable is in the subject pos + if (inverse) { + // variable is in the subject pos this.inverse = predicate this.constraints = this.constraints.concat( - kb.each(predicate, UI.ns.rdfs('domain'))) - if (predicate.sameTerm(ns.rdfs('subClassOf')) && (other.termType === 'NamedNode')) { + kb.each(predicate, UI.ns.rdfs('domain')) + ) + if ( + predicate.sameTerm(ns.rdfs('subClassOf')) && + other.termType === 'NamedNode' + ) { this.superClass = other this.alternatives = kb.each(undefined, ns.rdfs('subClassOf'), other) } - } else { // variable is the object + } else { + // variable is the object this.predicate = predicate - this.constraints = this.constraints.concat(kb.each(predicate, UI.ns.rdfs('range'))) + this.constraints = this.constraints.concat( + kb.each(predicate, UI.ns.rdfs('range')) + ) } } @@ -494,7 +502,9 @@ module.exports = function renderTableViewPane (doc, options) { } this.isImageColumn = function () { - for (let i = 0; i < this.constraints.length; i++) { if (this.constraints[i].uri in IMAGE_TYPES) return true } + for (let i = 0; i < this.constraints.length; i++) { + if (this.constraints[i].uri in IMAGE_TYPES) return true + } return false } } @@ -504,7 +514,8 @@ module.exports = function renderTableViewPane (doc, options) { function objectToArray (obj, filter) { var result = [] - for (let property in obj) { // @@@ have to guard against methods + for (const property in obj) { + // @@@ have to guard against methods var value = obj[property] if (!filter || filter(property, value)) { @@ -537,21 +548,25 @@ module.exports = function renderTableViewPane (doc, options) { dropdown.appendChild(optionElement('All types', 'null')) - for (let uri in types) { + for (const uri in types) { dropdown.appendChild(optionElement(types[uri].getLabel(), uri)) } - dropdown.addEventListener('click', function () { - var type + dropdown.addEventListener( + 'click', + function () { + var type - if (dropdown.value === 'null') { - type = allType - } else { - type = types[dropdown.value] - } + if (dropdown.value === 'null') { + type = allType + } else { + type = types[dropdown.value] + } - typeSelectorChanged(type) - }, false) + typeSelectorChanged(type) + }, + false + ) resultDiv.appendChild(dropdown) @@ -598,14 +613,18 @@ module.exports = function renderTableViewPane (doc, options) { // Invoke callback when the dropdown is changed, to add // the column and reload the table. - dropdown.addEventListener('click', function () { - var columnIndex = Number(dropdown.value) + dropdown.addEventListener( + 'click', + function () { + var columnIndex = Number(dropdown.value) - if (columnIndex >= 0) { - type.addColumn(unusedColumns[columnIndex]) - buildFilteredTable(type) - } - }, false) + if (columnIndex >= 0) { + type.addColumn(unusedColumns[columnIndex]) + buildFilteredTable(type) + } + }, + false + ) } return resultDiv @@ -654,21 +673,24 @@ module.exports = function renderTableViewPane (doc, options) { // Get a list of statements that match: ? rdfs:type ? // From this we can get a list of subjects and types. - var subjectList = kb.statementsMatching(undefined, + var subjectList = kb.statementsMatching( + undefined, UI.ns.rdf('type'), tableClass, // can be undefined OR - sourceDocument) // can be undefined + sourceDocument + ) // can be undefined // Subjects for later lookup. This is a mapping of type URIs to - // lists of subjects (it is necessary to record the type of - // a subject). + // lists of subjects (it is necessary to record the type of + // a subject). var subjects = {} for (let i = 0; i < subjectList.length; ++i) { var type = subjectList[i].object - if (type.termType !== 'NamedNode') { // @@ no bnodes? + if (type.termType !== 'NamedNode') { + // @@ no bnodes? continue } @@ -682,7 +704,7 @@ module.exports = function renderTableViewPane (doc, options) { typeObj.addUse() } - return [ subjects, types ] + return [subjects, types] } // Get columns for the given subject. @@ -690,10 +712,12 @@ module.exports = function renderTableViewPane (doc, options) { function getSubjectProperties (subject, columns) { // Get a list of properties of this subject. - var properties = kb.statementsMatching(subject, + var properties = kb.statementsMatching( + subject, undefined, undefined, - sourceDocument) + sourceDocument + ) var result = {} @@ -726,7 +750,7 @@ module.exports = function renderTableViewPane (doc, options) { for (let i = 0; i < subjects.length; ++i) { var columns = getSubjectProperties(subjects[i], allColumns) - for (let predicateUri in columns) { + for (const predicateUri in columns) { var column = columns[predicateUri] column.addUse() @@ -749,9 +773,10 @@ module.exports = function renderTableViewPane (doc, options) { var subjects, types var s = discoverTypes() - subjects = s[0]; types = s[1] // no [ ] on LHS + subjects = s[0] + types = s[1] // no [ ] on LHS - for (let typeUrl in subjects) { + for (const typeUrl in subjects) { var subjectList = subjects[typeUrl] var type = types[typeUrl] @@ -763,7 +788,7 @@ module.exports = function renderTableViewPane (doc, options) { var allType = new SubjectType(null) - return [ allType, objectToArray(types) ] + return [allType, objectToArray(types)] } // Sort the list of columns by the most common columns. @@ -783,10 +808,14 @@ module.exports = function renderTableViewPane (doc, options) { button.appendChild(doc.createTextNode('[x]')) - button.addEventListener('click', function () { - type.removeColumn(column) - buildFilteredTable(type) - }, false) + button.addEventListener( + 'click', + function () { + type.removeColumn(column) + buildFilteredTable(type) + }, + false + ) return button } @@ -965,16 +994,24 @@ module.exports = function renderTableViewPane (doc, options) { var sort1 = doc.createElement('span') sort1.appendChild(doc.createTextNode('\u25BC')) - sort1.addEventListener('click', function () { - literalSort(rows, column, false) - }, false) + sort1.addEventListener( + 'click', + function () { + literalSort(rows, column, false) + }, + false + ) result.appendChild(sort1) var sort2 = doc.createElement('span') sort2.appendChild(doc.createTextNode('\u25B2')) - sort2.addEventListener('click', function () { - literalSort(rows, column, true) - }, false) + sort2.addEventListener( + 'click', + function () { + literalSort(rows, column, true) + }, + false + ) result.appendChild(sort2) var substring = null @@ -1002,15 +1039,19 @@ module.exports = function renderTableViewPane (doc, options) { } } - textBox.addEventListener('keyup', function () { - if (textBox.value !== '') { - substring = textBox.value.toLowerCase() - } else { - substring = null - } + textBox.addEventListener( + 'keyup', + function () { + if (textBox.value !== '') { + substring = textBox.value.toLowerCase() + } else { + substring = null + } - applyColumnFilters(rows, columns) - }, false) + applyColumnFilters(rows, columns) + }, + false + ) return result } @@ -1042,8 +1083,8 @@ module.exports = function renderTableViewPane (doc, options) { else dropdown.appendChild(optionElement('(All)', '-1')) for (let i = 0; i < list.length; ++i) { - let value = list[i] - let ele = optionElement(utils.label(value), i) + const value = list[i] + const ele = optionElement(utils.label(value), i) if (searchValue[value.uri]) ele.selected = true dropdown.appendChild(ele) } @@ -1052,30 +1093,33 @@ module.exports = function renderTableViewPane (doc, options) { // Select based on an enum value. column.filterFunction = function (colValue) { - return !searchValue || - (colValue && searchValue[colValue.uri]) - } - - dropdown.addEventListener('click', function () { - if (doMultiple) { - searchValue = {} - let opt = dropdown.options - for (let i = 0; i < opt.length; i++) { - let option = opt[i] - let index = Number(option.value) - if (opt[i].selected) searchValue[list[index].uri] = true - } - } else { - let index = Number(dropdown.value) // adjusted in Standard tweaks 2018-01 - if (index < 0) { - searchValue = null - } else { + return !searchValue || (colValue && searchValue[colValue.uri]) + } + + dropdown.addEventListener( + 'click', + function () { + if (doMultiple) { searchValue = {} - searchValue[list[index].uri] = true + const opt = dropdown.options + for (let i = 0; i < opt.length; i++) { + const option = opt[i] + const index = Number(option.value) + if (opt[i].selected) searchValue[list[index].uri] = true + } + } else { + const index = Number(dropdown.value) // adjusted in Standard tweaks 2018-01 + if (index < 0) { + searchValue = null + } else { + searchValue = {} + searchValue[list[index].uri] = true + } } - } - applyColumnFilters(rows, columns) - }, true) + applyColumnFilters(rows, columns) + }, + true + ) return result } @@ -1169,7 +1213,9 @@ module.exports = function renderTableViewPane (doc, options) { // this predicate. // If this is a class which can be one of various sibling classes? - if (column.superClass && (column.alternatives.length > 0)) { return renderEnumSelector(rows, columns, column, column.alternatives) } + if (column.superClass && column.alternatives.length > 0) { + return renderEnumSelector(rows, columns, column, column.alternatives) + } var cs = column.getConstraints() var range @@ -1180,8 +1226,10 @@ module.exports = function renderTableViewPane (doc, options) { // Alternatively, is this an rdf:Literal type where all of // the values match as numbers? - if ((column.checkedAnyValues && column.possiblyNumber) || - (range.uri in XSD_NUMBER_TYPES)) { + if ( + (column.checkedAnyValues && column.possiblyNumber) || + range.uri in XSD_NUMBER_TYPES + ) { return renderNumberSelector(rows, columns, column) } @@ -1196,7 +1244,9 @@ module.exports = function renderTableViewPane (doc, options) { // Also ToDo: @@@ Handle membership of classes whcih are disjointUnions var choices = kb.each(range, UI.ns.owl('oneOf')) - if (choices.length > 0) { return renderEnumSelector(rows, columns, column, choices.elements) } + if (choices.length > 0) { + return renderEnumSelector(rows, columns, column, choices.elements) + } } return fallbackRenderTableSelector(rows, columns, column) } @@ -1240,17 +1290,20 @@ module.exports = function renderTableViewPane (doc, options) { result.setAttribute('href', uri) result.appendChild(doc.createTextNode(linkText)) if (!linkFunction) { - result.addEventListener('click', - UI.widgets.openHrefInOutlineMode, true) + result.addEventListener('click', UI.widgets.openHrefInOutlineMode, true) } else { - result.addEventListener('click', function (e) { - e.preventDefault() - e.stopPropagation() - var target = utils.getTarget(e) - var uri = target.getAttribute('href') - if (!uri) console.log('No href found \n') - linkFunction(uri) - }, true) + result.addEventListener( + 'click', + function (e) { + e.preventDefault() + e.stopPropagation() + var target = utils.getTarget(e) + var uri = target.getAttribute('href') + if (!uri) console.log('No href found \n') + linkFunction(uri) + }, + true + ) } return result } @@ -1284,20 +1337,26 @@ module.exports = function renderTableViewPane (doc, options) { // in a table cell. function getHints (column) { - if (options && options.hints && column.variable && options.hints[column.variable.toNT()]) { + if ( + options && + options.hints && + column.variable && + options.hints[column.variable.toNT()] + ) { return options.hints[column.variable.toNT()] } return {} } - function renderValue (obj, column) { // hint + function renderValue (obj, column) { + // hint var hints = getHints(column) var cellFormat = hints.cellFormat if (cellFormat) { switch (cellFormat) { case 'shortDate': return doc.createTextNode(UI.widgets.shortDate(obj.value)) - // break + // break default: // drop through } @@ -1307,7 +1366,7 @@ module.exports = function renderTableViewPane (doc, options) { if (XSD_DATE_TYPES[obj.datatype.uri]) { return doc.createTextNode(UI.widgets.shortDate(obj.value)) } else if (XSD_NUMBER_TYPES[obj.datatype.uri]) { - let span = doc.createElement('span') + const span = doc.createElement('span') span.textContent = obj.value span.setAttribute('style', 'text-align: right') return span @@ -1319,7 +1378,7 @@ module.exports = function renderTableViewPane (doc, options) { } else if (obj.termType === 'NamedNode' || obj.termType === 'BlankNode') { return linkToObject(obj, hints) } else if (obj.termType === 'Collection') { - let span = doc.createElement('span') + const span = doc.createElement('span') span.appendChild(doc.createTextNode('[')) obj.elements.map(function (x) { span.appendChild(renderValue(x, column)) @@ -1338,7 +1397,7 @@ module.exports = function renderTableViewPane (doc, options) { // Note that unlike other functions, this renders into a provided // row () element. - function renderTableRowInto (tr, row, columns, downstream) { + function renderTableRowInto (tr, row, columns, _downstream) { /* Link column, for linking to this subject. */ var linkTd = doc.createElement('td') @@ -1369,8 +1428,11 @@ module.exports = function renderTableViewPane (doc, options) { } for (let j = 0; j < objects.length; ++j) { var obj = objects[j] - if (row.originalValues && row.originalValues[columnKey] && - row.originalValues[columnKey].length > j) { + if ( + row.originalValues && + row.originalValues[columnKey] && + row.originalValues[columnKey].length > j + ) { orig = row.originalValues[columnKey][j] if (obj.toString() !== orig.toString()) { different = true @@ -1416,8 +1478,7 @@ module.exports = function renderTableViewPane (doc, options) { var i for (i = 0; i < list.length; ++i) { - if (list[i].termType === value.termType && - list[i][key] === value[key]) { + if (list[i].termType === value.termType && list[i][key] === value[key]) { return true } } @@ -1492,12 +1553,13 @@ module.exports = function renderTableViewPane (doc, options) { for (let i = 0; i < rows.length; i++) { rows[i].original = true - if (!rows[i].originalValues) { // remember first set + if (!rows[i].originalValues) { + // remember first set rows[i].originalValues = rows[i].values } rows[i].values = {} - // oldStyle = rows[i]._htmlRow.getAttribute('style') || '' - // rows[i]._htmlRow.style.background = '#ffe'; //setAttribute('style', ' background-color: #ffe;')// yellow + // oldStyle = rows[i]._htmlRow.getAttribute('style') || '' + // rows[i]._htmlRow.style.background = '#ffe'; //setAttribute('style', ' background-color: #ffe;')// yellow } var onResult = function (values) { @@ -1513,7 +1575,7 @@ module.exports = function renderTableViewPane (doc, options) { // If the query has a row key, use it to look up the row. - if ((keyVariable) in values) { + if (keyVariable in values) { rowKey = values[keyVariable] rowKeyId = getSubjectId(rowKey) @@ -1549,15 +1611,22 @@ module.exports = function renderTableViewPane (doc, options) { } var onDone = function () { - if (progressMessage && progressMessage.parentNode && progressMessage.parentNode.removeChild) { + if ( + progressMessage && + progressMessage.parentNode && + progressMessage.parentNode.removeChild + ) { progressMessage.parentNode.removeChild(progressMessage) progressMessage = null } var elapsedTimeMS = Date.now() - startTime - console.log('Query done: ' + rows.length + ' rows, ' + elapsedTimeMS + 'ms') + console.log( + 'Query done: ' + rows.length + ' rows, ' + elapsedTimeMS + 'ms' + ) // Delete rows which were from old values not new - for (let i = rows.length - 1; i >= 0; i--) { // backwards + for (let i = rows.length - 1; i >= 0; i--) { + // backwards if (rows[i].original) { console.log(' deleting row ' + rows[i]._subject) var tr = rows[i]._htmlRow @@ -1598,19 +1667,23 @@ module.exports = function renderTableViewPane (doc, options) { // If so, we can use the predicate as the predicate for the // column used for the specified variable. - if (statement.predicate.termType === 'NamedNode' && - statement.object.termType === 'Variable') { + if ( + statement.predicate.termType === 'NamedNode' && + statement.object.termType === 'Variable' + ) { var variable = statement.object.toString() if (variable in columns) { var column = columns[variable] column.setPredicate(statement.predicate, false, statement.subject) } } - if (statement.predicate.termType === 'NamedNode' && - statement.subject.termType === 'Variable') { - let variable = statement.subject.toString() + if ( + statement.predicate.termType === 'NamedNode' && + statement.subject.termType === 'Variable' + ) { + const variable = statement.subject.toString() if (variable in columns) { - let column = columns[variable] + const column = columns[variable] column.setPredicate(statement.predicate, true, statement.object) } } @@ -1691,7 +1764,8 @@ module.exports = function renderTableViewPane (doc, options) { var bestCount = -1 var best = null - for (let typeUri in types) { + let typeUri + for (typeUri in types) { var type = types[typeUri] if (type.useCount > bestCount) { @@ -1705,7 +1779,7 @@ module.exports = function renderTableViewPane (doc, options) { // Filter list of columns to only those columns used in the // specified rows. -/* + /* function filterColumns (columns, rows) { var filteredColumns = {} diff --git a/src/tabs.js b/src/tabs.js index ee82cd641..3fbc19caf 100644 --- a/src/tabs.js +++ b/src/tabs.js @@ -1,4 +1,3 @@ - // SOLID-compaible Tabs widget // // - Any Orientation = top, left, bottom, right @@ -61,7 +60,7 @@ UI.tabs.tabWidget = function (options) { res = ca * (1.0 - mix) + cb * mix // @@@ rounding var res2 = parseInt(('' + res).split('.')[0]) // @@ ugh var h = parseInt(('' + res2 / 16).split('.')[0]) // @@ ugh - var l = parseInt(('' + res2 % 16).split('.')[0]) // @@ ugh + var l = parseInt(('' + (res2 % 16)).split('.')[0]) // @@ ugh str += hex[h] + hex[l] } // console.log('Blending colors ' + a + ' with ' + mix + ' of ' + b + ' to give ' + str) @@ -76,8 +75,10 @@ UI.tabs.tabWidget = function (options) { selectedColor = colorBlend(backgroundColor, '#000000', 0.3) color = '#ffffff' } - var bodyDivStyle = 'resize: both; overflow: scroll; margin:0; border: 0.5em; border-style: solid; border-color: ' + - selectedColor + '; padding: 1em; min-width: 30em; min-height: 450px; width:100%;' + var bodyDivStyle = + 'resize: both; overflow: scroll; margin:0; border: 0.5em; border-style: solid; border-color: ' + + selectedColor + + '; padding: 1em; min-width: 30em; min-height: 450px; width:100%;' if (vertical) { var onlyTR = wholetable.appendChild(dom.createElement('tr')) @@ -96,7 +97,8 @@ UI.tabs.tabWidget = function (options) { tabElement = 'tr' // tabBar = tabTD // drop zone // mainTD.appendChild(bodyDiv) - } else { // horizontal + } else { + // horizontal tabContainer = dom.createElement('tr') mainTR = wholetable.appendChild(dom.createElement('tr')) if (flipped) { @@ -117,7 +119,8 @@ UI.tabs.tabWidget = function (options) { var getItems = function () { if (options.items) return options.items - if (options.ordered !== false) { // default to true + if (options.ordered !== false) { + // default to true var list = kb.the(subject, options.predicate) return list.elements } else { @@ -135,8 +138,13 @@ UI.tabs.tabWidget = function (options) { var tabStyle = corners + 'padding: 0.7em; max-width: 20em;' // border: 0.05em 0 0.5em 0.05em; border-color: grey; tabStyle += 'color: ' + color + ';' - var unselectedStyle = tabStyle + 'opacity: 50%; margin: 0.3em; background-color: ' + backgroundColor + ';' // @@ rotate border - var selectedStyle = tabStyle + margins + ' background-color: ' + selectedColor + ';' + var unselectedStyle = + tabStyle + + 'opacity: 50%; margin: 0.3em; background-color: ' + + backgroundColor + + ';' // @@ rotate border + var selectedStyle = + tabStyle + margins + ' background-color: ' + selectedColor + ';' var shownStyle = '' var hiddenStyle = shownStyle + 'display: none;' @@ -206,7 +214,10 @@ UI.tabs.tabWidget = function (options) { // Find how many match at each end for (left = 0; left < tabContainer.children.length; left++) { slot = tabContainer.children[left] - if (left >= items.length || (slot.subject && !slot.subject.sameTerm(items[left]))) { + if ( + left >= items.length || + (slot.subject && !slot.subject.sameTerm(items[left])) + ) { differ = true break } @@ -222,8 +233,12 @@ UI.tabs.tabWidget = function (options) { } } // The elements left ... right in tabContainer.children do not match - var insertables = items.slice(left, right - tabContainer.children.length + items.length + 1) - while (right >= left) { // remove extra + var insertables = items.slice( + left, + right - tabContainer.children.length + items.length + 1 + ) + while (right >= left) { + // remove extra tabContainer.removeChild(tabContainer.children[left]) bodyContainer.removeChild(bodyContainer.children[left]) right -= 1 @@ -234,7 +249,8 @@ UI.tabs.tabWidget = function (options) { // var newBodyDiv = newBodyTR.appendChild(dom.createElement('div')) newSlot.bodyTR = newBodyTR dom.createElement('tr') - if (left === tabContainer.children.length) { // None left of original on right + if (left === tabContainer.children.length) { + // None left of original on right tabContainer.appendChild(newSlot) bodyContainer.appendChild(newBodyTR) // console.log(' appending new ' + insertables[i]) @@ -305,13 +321,20 @@ UI.tabs.tabWidget = function (options) { box.refresh = sync sync() -// From select-tabs branch by hand - if (!options.startEmpty && tabContainer.children.length && options.selectedTab) { + // From select-tabs branch by hand + if ( + !options.startEmpty && + tabContainer.children.length && + options.selectedTab + ) { var tab var found = false for (var i = 0; i < tabContainer.children.length; i++) { tab = tabContainer.children[i] - if (tab.firstChild && tab.firstChild.dataset.name === options.selectedTab) { + if ( + tab.firstChild && + tab.firstChild.dataset.name === options.selectedTab + ) { tab.firstChild.click() found = true } diff --git a/src/test/test-matrix.js b/src/test/test-matrix.js index f4154001e..1b88b204b 100644 --- a/src/test/test-matrix.js +++ b/src/test/test-matrix.js @@ -1,6 +1,7 @@ +/* global $rdf */ document.addEventListener('DOMContentLoaded', function () { - /// /////////////////////////////////////////// + /// /////////////////////////////////////////// var UI = require('mashlib') var kb = UI.store @@ -11,37 +12,37 @@ document.addEventListener('DOMContentLoaded', function () { var DC = $rdf.Namespace('http://purl.org/dc/elements/1.1/') var uri = window.location.href - var base = window.document.title = uri.slice(0, uri.lastIndexOf('/') + 1) + var base = (window.document.title = uri.slice(0, uri.lastIndexOf('/') + 1)) var testDocURI = base + 'test.ttl' // imaginary doc - just use its URL var testDoc = $rdf.sym(testDocURI) var subjectURI = testDocURI + '#event1' var meURI = testDocURI + '#a0' var me = kb.sym(meURI) -// var forms_uri = window.document.title = base+ 'forms.ttl'; + // var forms_uri = window.document.title = base+ 'forms.ttl'; var subject = kb.sym(subjectURI) var div = dom.getElementById('UITestArea') var showResults = function () { - // Now the form for responsing to the poll - // + // Now the form for responsing to the poll + // - // div.appendChild(dom.createElement('hr')) + // div.appendChild(dom.createElement('hr')) var invitation = subject var query = new $rdf.Query('Responses') - var v = {}; - ['time', 'author', 'value', 'resp', 'cell'].map(function (x) { - query.vars.push(v[x] = $rdf.variable(x)) + var v = {} + ;['time', 'author', 'value', 'resp', 'cell'].map(function (x) { + query.vars.push((v[x] = $rdf.variable(x))) }) query.pat.add(invitation, SCHED('response'), v.resp) query.pat.add(v.resp, DC('author'), v.author) query.pat.add(v.resp, SCHED('cell'), v.cell) query.pat.add(v.cell, SCHED('availabilty'), v.value) query.pat.add(v.cell, ICAL('dtstart'), v.time) - /* + /* var prologue = " @prefix foaf: .\n\ @prefix sched: .\n\ @prefix ical: .\n\ @@ -49,8 +50,8 @@ document.addEventListener('DOMContentLoaded', function () { */ var prologue = dom.getElementById('Prologue').textContent - // var config = dom.getElementById('Config').textContent; - // $rdf.parse(prologue + config, kb, testDocURI, 'text/turtle') // str, kb, base, contentType + // var config = dom.getElementById('Config').textContent; + // $rdf.parse(prologue + config, kb, testDocURI, 'text/turtle') // str, kb, base, contentType var tests = dom.getElementById('TestData').children var inputText = function (tr) { @@ -66,10 +67,14 @@ document.addEventListener('DOMContentLoaded', function () { var setAxes = function () { options.set_x = kb.each(subject, SCHED('option')) // @@@@@ option -> dtstart in future - options.set_x = options.set_x.map(function (opt) { return kb.any(opt, ICAL('dtstart')) }) + options.set_x = options.set_x.map(function (opt) { + return kb.any(opt, ICAL('dtstart')) + }) options.set_y = kb.each(subject, SCHED('response')) - options.set_y = options.set_y.map(function (resp) { return kb.any(resp, DC('author')) }) + options.set_y = options.set_y.map(function (resp) { + return kb.any(resp, DC('author')) + }) } setAxes() @@ -77,43 +82,73 @@ document.addEventListener('DOMContentLoaded', function () { // .map(function (opt) { return kb.any(opt, ICAL('dtstart')) }) var displayTheMatrix = function () { - var matrix = div.appendChild(UI.matrix.matrixForQuery( - dom, query, v.time, v.author, v.value, options, function () {})) + var matrix = div.appendChild( + UI.matrix.matrixForQuery( + dom, + query, + v.time, + v.author, + v.value, + options, + function () {} + ) + ) matrix.setAttribute('class', 'matrix') var refreshButton = dom.createElement('button') refreshButton.textContent = 'refresh' - refreshButton.addEventListener('click', function (e) { - matrix.refresh() - }, false) + refreshButton.addEventListener( + 'click', + function (_event) { + matrix.refresh() + }, + false + ) return matrix } - // @@ Give other combos too-- see schedule ontology - var possibleAvailabilities = [ SCHED('No'), SCHED('Maybe'), SCHED('Yes') ] + // @@ Give other combos too-- see schedule ontology + var possibleAvailabilities = [SCHED('No'), SCHED('Maybe'), SCHED('Yes')] var dataPointForNT = [] // var doc = testDoc - options.set_y = options.set_y.filter(function (z) { return (!z.sameTerm(me)) }) + options.set_y = options.set_y.filter(function (z) { + return !z.sameTerm(me) + }) options.set_y.push(me) // Put me on the end options.cellFunction = function (cell, x, y, value) { var refreshColor = function () { var bg = kb.any(value, UI.ns.ui('backgroundColor')) - if (bg) cell.setAttribute('style', 'text-align: center; background-color: ' + bg + ';') + if (bg) { + cell.setAttribute( + 'style', + 'text-align: center; background-color: ' + bg + ';' + ) + } } if (value !== null) { refreshColor() } if (y.sameTerm(me)) { - var callback = function () { refreshColor() } // @@ may need that + var callback = function () { + refreshColor() + } // @@ may need that var selectOptions = {} var predicate = SCHED('availabilty') var cellSubject = dataPointForNT[x.toNT()] - var selector = UI.widgets.makeSelectForOptions(dom, kb, cellSubject, predicate, - possibleAvailabilities, selectOptions, testDoc, callback) + var selector = UI.widgets.makeSelectForOptions( + dom, + kb, + cellSubject, + predicate, + possibleAvailabilities, + selectOptions, + testDoc, + callback + ) cell.appendChild(selector) } else if (value !== null) { cell.textContent = UI.utils.label(value) @@ -125,14 +160,14 @@ document.addEventListener('DOMContentLoaded', function () { var agenda = [] var nextTest = function nextTest () { - // First take a copy of the DOM the klast test produced + // First take a copy of the DOM the klast test produced output(tests[t]).appendChild(matrix.cloneNode(true)) t += 1 var test = tests[t] if (!test) return - kb.removeMany(undefined, undefined, undefined, testDoc) // Flush out previous test data + kb.removeMany(undefined, undefined, undefined, testDoc) // Flush out previous test data $rdf.parse(prologue + inputText(tests[t]), kb, testDocURI, 'text/turtle') setAxes() matrix.refresh() @@ -142,7 +177,9 @@ document.addEventListener('DOMContentLoaded', function () { agenda.push(nextTest) - setTimeout(function () { agenda.shift()() }, 2000) + setTimeout(function () { + agenda.shift()() + }, 2000) } // showResults showResults() diff --git a/src/test/test-tabs.js b/src/test/test-tabs.js index ee8ca3c93..e8ea49ce0 100644 --- a/src/test/test-tabs.js +++ b/src/test/test-tabs.js @@ -1,20 +1,21 @@ +/* global panes, $rdf */ document.addEventListener('DOMContentLoaded', function () { - /// /////////////////////////////////////////// + /// /////////////////////////////////////////// var UI = panes.UI var kb = UI.store var dom = document var uri = window.location.href - var base = window.document.title = uri.slice(0, uri.lastIndexOf('/') + 1) + var base = (window.document.title = uri.slice(0, uri.lastIndexOf('/') + 1)) var testDocURI = base + 'test.ttl' // imaginary doc - just use its URL var testDoc = $rdf.sym(testDocURI) // var subject_uri = testDocURI + '#event1' // var me_uri = testDocURI + '#a0' // var me = kb.sym(me_uri) -// var forms_uri = window.document.title = base+ 'forms.ttl'; + // var forms_uri = window.document.title = base+ 'forms.ttl'; // var subject = kb.sym(subject_uri) var div = dom.getElementById('UITestArea') @@ -48,13 +49,13 @@ document.addEventListener('DOMContentLoaded', function () { options.subject = kb.the(target, UI.ns.ui('subject')) options.ordered = kb.the(target, UI.ns.ui('ordered')).value === '1' options.orientation = kb.the(target, UI.ns.ui('orientation')).value - options.onClose = function(e) {} // Test it can make a close button is a good place - // todo: test both cases + options.onClose = function (_event) {} // Test it can make a close button is a good place + // todo: test both cases var tabs = div.appendChild(UI.tabs.tabWidget(options)) return tabs } - // @@ Give other combos too-- see schedule ontology + // @@ Give other combos too-- see schedule ontology // var dataPointForNT = [] // var doc = testDoc @@ -70,7 +71,10 @@ document.addEventListener('DOMContentLoaded', function () { } var iframe = container.appendChild(dom.createElement('iframe')) iframe.setAttribute('src', subject.uri) - iframe.setAttribute('style', 'border: 1em solid pink; margin: 2em; padding: 2em; padding-color: green;') + iframe.setAttribute( + 'style', + 'border: 1em solid pink; margin: 2em; padding: 2em; padding-color: green;' + ) tabContentCache[subject.uri] = iframe } @@ -79,16 +83,21 @@ document.addEventListener('DOMContentLoaded', function () { var agenda = [] var nextTest = function nextTest () { - // First take a copy of the DOM the klast test produced + // First take a copy of the DOM the klast test produced output(tests[t]).appendChild(tabs.cloneNode(true)) t += 1 var test = tests[t] if (!test) return // var tClass = - kb.removeMany(undefined, undefined, undefined, testDoc) // Flush out previous test data + kb.removeMany(undefined, undefined, undefined, testDoc) // Flush out previous test data try { - $rdf.parse(prologue + inputText(tests[t]), kb, testDocURI, 'text/turtle') + $rdf.parse( + prologue + inputText(tests[t]), + kb, + testDocURI, + 'text/turtle' + ) } catch (e) { output(test).textContent = e } @@ -104,7 +113,9 @@ document.addEventListener('DOMContentLoaded', function () { agenda.push(nextTest) - setTimeout(function () { agenda.shift()() }, 2000) + setTimeout(function () { + agenda.shift()() + }, 2000) } // showResults showResults() diff --git a/src/utils.js b/src/utils.js index 235a993f5..b684297dc 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,4 @@ +/* global tabulator */ // Solid-UI general Utilities // ========================== // @@ -5,7 +6,7 @@ // module.exports = { - addLoadEvent, // not used anywhere + addLoadEvent, // not used anywhere AJARImage, ancestor, beep, @@ -63,10 +64,12 @@ if (typeof AudioContext !== 'undefined') { } function beep () { - if (!audioContext) { return } // Safari 2015 + if (!audioContext) { + return + } // Safari 2015 - let ContextClass = audioContext - let ctx = new ContextClass() + const ContextClass = audioContext + const ctx = new ContextClass() return function (duration, frequency, type, finishedCallback) { duration = +(duration || 0.3) @@ -93,14 +96,20 @@ function beep () { // NOT USED ANYWHERE function hashColor (who) { who = who.uri || who - var hash = function (x) { return x.split('').reduce(function (a, b) { a = ((a << 5) - a) + b.charCodeAt(0); return a & a }, 0) } + var hash = function (x) { + return x.split('').reduce(function (a, b) { + a = (a << 5) - a + b.charCodeAt(0) + return a & a + }, 0) + } return '#' + ((hash(who) & 0xffffff) | 0xc0c0c0).toString(16) // c0c0c0 or 808080 forces pale } -function genUuid () { // http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript +function genUuid () { + // http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0 - var v = c === 'x' ? r : (r & 0x3 | 0x8) + var r = (Math.random() * 16) | 0 + var v = c === 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) } @@ -112,7 +121,7 @@ function genUuid () { // http://stackoverflow.com/questions/105034/create-guid-u * @param {function({NamedNode})} createNewRow(thing) returns a TR table row for a new thing * * Tolerates out of order elements but puts new ones in order. -*/ + */ function syncTableToArray (table, things, createNewRow) { let foundOne let row @@ -136,12 +145,12 @@ function syncTableToArray (table, things, createNewRow) { } } if (!foundOne) { - let newRow = createNewRow(thing) + const newRow = createNewRow(thing) // Insert new row in position g in the table to match array if (g >= table.children.length) { table.appendChild(newRow) } else { - let ele = table.children[g] + const ele = table.children[g] table.insertBefore(newRow, ele) } newRow.subject = thing @@ -157,17 +166,17 @@ function syncTableToArray (table, things, createNewRow) { } // syncTableToArray /* Error stack to string for better diagnotsics -** -** See http://snippets.dzone.com/posts/show/6632 -*/ + ** + ** See http://snippets.dzone.com/posts/show/6632 + */ function stackString (e) { let str = '' + e + '\n' let i if (!e.stack) { return str + 'No stack available.\n' } - let lines = e.stack.toString().split('\n') - let toPrint = [] + const lines = e.stack.toString().split('\n') + const toPrint = [] for (i = 0; i < lines.length; i++) { let line = lines[i] if (line.indexOf('ecmaunit.js') > -1) { @@ -177,7 +186,7 @@ function stackString (e) { if (line.charAt(0) === '(') { line = 'function' + line } - let chunks = line.split('@') + const chunks = line.split('@') toPrint.push(chunks) } // toPrint.reverse(); No - I prefer the latest at the top by the error message -tbl @@ -189,8 +198,8 @@ function stackString (e) { } function emptyNode (node) { - let nodes = node.childNodes - let len = nodes.length + const nodes = node.childNodes + const len = nodes.length let i for (i = len - 1; i >= 0; i--) node.removeChild(nodes[i]) return node @@ -201,7 +210,8 @@ function getTarget (e) { e = e || window.event if (e.target) target = e.target else if (e.srcElement) target = e.srcElement - if (target.nodeType === 3) { // defeat Safari bug [sic] + if (target.nodeType === 3) { + // defeat Safari bug [sic] target = target.parentNode } // UI.log.debug("Click on: " + target.tagName) @@ -214,7 +224,8 @@ function ancestor (target, tagName) { // UI.log.debug("looking for "+tagName+" Level: "+level+" "+level.tagName) try { if (level.tagName === tagName) return level - } catch (e) { // can hit "TypeError: can't access dead object" in ffox + } catch (e) { + // can hit "TypeError: can't access dead object" in ffox return undefined } } @@ -223,7 +234,11 @@ function ancestor (target, tagName) { function getAbout (kb, target) { var level, aa - for (level = target; level && (level.nodeType === 1); level = level.parentNode) { + for ( + level = target; + level && level.nodeType === 1; + level = level.parentNode + ) { // UI.log.debug("Level "+level + ' '+level.nodeType + ': '+level.tagName) aa = level.getAttribute('about') if (aa) { @@ -257,10 +272,16 @@ function getTerm (target) { case 'selected': // header TD return getAbout(UI.store, target) // kb to be changed case 'undetermined selected': - return (target.nextSibling) ? st.predicate : ((!statementTr.AJAR_inverse) ? st.object : st.subject) + return target.nextSibling + ? st.predicate + : getUndeterminedSelection(statementTr, st) } } +function getUndeterminedSelection (statementTr, st) { + return !statementTr.AJAR_inverse ? st.object : st.subject +} + function include (document, linkstr) { var lnk = document.createElement('script') lnk.setAttribute('type', 'text/javascript') @@ -283,7 +304,8 @@ function addLoadEvent (func) { } // addLoadEvent // Find the position of an object relative to the window -function findPos (obj) { // C&P from http://www.quirksmode.org/js/findpos.html +function findPos (obj) { + // C&P from http://www.quirksmode.org/js/findpos.html var myDocument = obj.ownerDocument var DocBox = myDocument.documentElement.getBoundingClientRect() var box = obj.getBoundingClientRect() @@ -296,7 +318,12 @@ function getEyeFocus (element, instantly, isBottom, myWindow) { var totalScroll = elementPosY - 52 - myWindow.scrollY // magic number 52 for web-based version if (instantly) { if (isBottom) { - myWindow.scrollBy(0, elementPosY + element.clientHeight - (myWindow.scrollY + myWindow.innerHeight)) + myWindow.scrollBy( + 0, + elementPosY + + element.clientHeight - + (myWindow.scrollY + myWindow.innerHeight) + ) return } myWindow.scrollBy(0, totalScroll) @@ -337,12 +364,12 @@ function AJARImage (src, alt, tt, doc) { function shortName (uri) { let p = uri if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1) - let namespaces = [] - for (let ns in this.prefixes) { + const namespaces = [] + for (const ns in this.prefixes) { namespaces[this.prefixes[ns]] = ns // reverse index } let pok - let canUse = function canUse (pp) { + const canUse = function canUse (pp) { // if (!__Serializer.prototype.validPrefix.test(pp)) return false; // bad format if (pp === 'ns') return false // boring // if (pp in this.namespaces) return false; // already used @@ -353,14 +380,15 @@ function shortName (uri) { } let i - let hash = p.lastIndexOf('#') + const hash = p.lastIndexOf('#') if (hash >= 0) p = p.slice(hash - 1) // lop off localid for (;;) { - let slash = p.lastIndexOf('/') + const slash = p.lastIndexOf('/') if (slash >= 0) p = p.slice(slash + 1) i = 0 while (i < p.length) { - if (this.prefixchars.indexOf(p[i])) i++; else break + if (this.prefixchars.indexOf(p[i])) i++ + else break } p = p.slice(0, i) if (p.length < 6 && canUse(p)) return pok // exact i sbest @@ -390,7 +418,7 @@ function ontologyLabel (term) { return term.uri + '?!' // strange should have # or / } } - for (let ns in UI.ns) { + for (const ns in UI.ns) { namespaces[UI.ns[ns]] = ns // reverse index } try { @@ -404,7 +432,7 @@ function ontologyLabel (term) { if (i >= 0) { part = s.slice(i + 1) s = s.slice(0, i) - if ((part !== 'ns') && ('0123456789'.indexOf(part[0]) < 0)) { + if (part !== 'ns' && '0123456789'.indexOf(part[0]) < 0) { return part } } else { @@ -414,11 +442,9 @@ function ontologyLabel (term) { } function labelWithOntology (x, initialCap) { - let t = UI.store.findTypeURIs(x) - if (t[UI.ns.rdf('Predicate').uri] || - t[UI.ns.rdfs('Class').uri]) { - return label(x, initialCap) + - ' (' + ontologyLabel(x) + ')' + const t = UI.store.findTypeURIs(x) + if (t[UI.ns.rdf('Predicate').uri] || t[UI.ns.rdfs('Class').uri]) { + return label(x, initialCap) + ' (' + ontologyLabel(x) + ')' } return label(x, initialCap) } @@ -429,7 +455,8 @@ function labelWithOntology (x, initialCap) { // // @returns string // -function label (x, initialCap) { // x is an object +function label (x, initialCap) { + // x is an object function doCap (s) { // s = s.toString() if (initialCap) return s.slice(0, 1).toUpperCase() + s.slice(1) @@ -444,9 +471,11 @@ function label (x, initialCap) { // x is an object continue } s2 += s1[i] - if (i + 1 < s1.length && + if ( + i + 1 < s1.length && s1[i].toUpperCase() !== s1[i] && - s1[i + 1].toLowerCase() !== s1[i + 1]) { + s1[i + 1].toLowerCase() !== s1[i + 1] + ) { s2 += ' ' } } @@ -468,7 +497,8 @@ function label (x, initialCap) { // x is an object // @@ TBD: Add subproperties of rdfs:label var kb = UI.store - var lab1 = kb.any(x, UI.ns.link('message')) || + var lab1 = + kb.any(x, UI.ns.link('message')) || kb.any(x, UI.ns.vcard('fn')) || kb.any(x, UI.ns.foaf('name')) || kb.any(x, UI.ns.dct('title')) || @@ -498,12 +528,23 @@ function label (x, initialCap) { // x is an object // The idea was to clean up eg URIs encoded in query strings // Also encoded character in what was filenames like @ [] {} try { - s = s.split('/').map(decodeURIComponent).join('/') // If it is properly encoded - } catch (e) { // try individual decoding of ASCII code points + s = s + .split('/') + .map(decodeURIComponent) + .join('/') // If it is properly encoded + } catch (e) { + // try individual decoding of ASCII code points for (var i = s.length - 3; i > 0; i--) { const hex = '0123456789abcefABCDEF' // The while upacks multiple layers of encoding - while (s[i] === '%' && hex.indexOf(s[i + 1]) >= 0 && hex.indexOf(s[i + 2]) >= 0) { - s = s.slice(0, i) + String.fromCharCode(parseInt(s.slice(i + 1, i + 3), 16)) + s.slice(i + 3) + while ( + s[i] === '%' && + hex.indexOf(s[i + 1]) >= 0 && + hex.indexOf(s[i + 2]) >= 0 + ) { + s = + s.slice(0, i) + + String.fromCharCode(parseInt(s.slice(i + 1, i + 3), 16)) + + s.slice(i + 3) } } } @@ -518,7 +559,7 @@ function label (x, initialCap) { // x is an object // Eh? Why not do this? e.g. dc:title needs it only trim URIs, not rdfs:labels var slash = s.lastIndexOf('/', s.length - 2) // (len-2) excludes trailing slash - if ((slash >= 0) && (slash < x.uri.length)) return cleanUp(s.slice(slash + 1)) + if (slash >= 0 && slash < x.uri.length) return cleanUp(s.slice(slash + 1)) return doCap(decodeURIComponent(x.uri)) } @@ -535,7 +576,8 @@ function labelForXML (x) { // As above but for predicate, possibly inverse function predicateLabelForXML (p, inverse) { var lab - if (inverse) { // If we know an inverse predicate, use its label + if (inverse) { + // If we know an inverse predicate, use its label var ip = UI.store.any(p, UI.ns.owl('inverseOf')) if (!ip) ip = UI.store.any(undefined, UI.ns.owl('inverseOf'), p) if (ip) return labelForXML(ip) @@ -571,7 +613,8 @@ function predParentOf (node) { } else if (n.previousSibling && n.previousSibling.nodeName === 'TR') { n = n.previousSibling } else { - UI.log.error('Could not find predParent'); return node + UI.log.error('Could not find predParent') + return node } } } diff --git a/src/widgets/buttons.js b/src/widgets/buttons.js index 4bb7fcd8d..04f406dea 100644 --- a/src/widgets/buttons.js +++ b/src/widgets/buttons.js @@ -1,7 +1,9 @@ /* UI Widgets such as buttons -*/ + */ /* global alert */ +const $rdf = require('rdflib') + module.exports = {} var buttons = {} @@ -83,15 +85,33 @@ buttons.extractLogURI = function (fullURI) { // noTime - only give date, no time, buttons.shortDate = function (str, noTime) { if (!str) return '???' - var month = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] + var month = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec' + ] try { var nowZ = new Date().toISOString() // var nowZ = $rdf.term(now).value // var n = now.getTimezoneOffset() // Minutes - if (str.slice(0, 10) === nowZ.slice(0, 10) && !noTime) return str.slice(11, 16) + if (str.slice(0, 10) === nowZ.slice(0, 10) && !noTime) { + return str.slice(11, 16) + } if (str.slice(0, 4) === nowZ.slice(0, 4)) { - return (month[parseInt(str.slice(5, 7), 10) - 1] + ' ' + parseInt(str.slice(8, 10), 10)) + return ( + month[parseInt(str.slice(5, 7), 10) - 1] + + ' ' + + parseInt(str.slice(8, 10), 10) + ) } return str.slice(0, 10) } catch (e) { @@ -100,19 +120,31 @@ buttons.shortDate = function (str, noTime) { } buttons.formatDateTime = function (date, format) { - return format.split('{').map(function (s) { - var k = s.split('}')[0] - var width = {'Milliseconds': 3, 'FullYear': 4} - var d = {'Month': 1} - return s ? ('000' + (date['get' + k]() + (d[k] || 0))).slice(-(width[k] || 2)) + s.split('}')[1] : '' - }).join('') + return format + .split('{') + .map(function (s) { + var k = s.split('}')[0] + var width = { Milliseconds: 3, FullYear: 4 } + var d = { Month: 1 } + return s + ? ('000' + (date['get' + k]() + (d[k] || 0))).slice(-(width[k] || 2)) + + s.split('}')[1] + : '' + }) + .join('') } buttons.timestamp = function () { - return buttons.formatDateTime(new Date(), '{FullYear}-{Month}-{Date}T{Hours}:{Minutes}:{Seconds}.{Milliseconds}') + return buttons.formatDateTime( + new Date(), + '{FullYear}-{Month}-{Date}T{Hours}:{Minutes}:{Seconds}.{Milliseconds}' + ) } buttons.shortTime = function () { - return buttons.formatDateTime(new Date(), '{Hours}:{Minutes}:{Seconds}.{Milliseconds}') + return buttons.formatDateTime( + new Date(), + '{Hours}:{Minutes}:{Seconds}.{Milliseconds}' + ) } // ///////////////////// Handy UX widgets @@ -123,15 +155,18 @@ buttons.setName = function (element, x) { var kb = UI.store var ns = UI.ns var findName = function (x) { - var name = kb.any(x, ns.vcard('fn')) || kb.any(x, ns.foaf('name')) || + var name = + kb.any(x, ns.vcard('fn')) || + kb.any(x, ns.foaf('name')) || kb.any(x, ns.vcard('organization-name')) return name ? name.value : null } var name = x.sameTerm(ns.foaf('Agent')) ? 'Everyone' : findName(x) element.textContent = name || utils.label(x) - if (!name && x.uri) { // Note this is only a fetch, not a lookUP of all sameAs etc - kb.fetcher.nowOrWhenFetched(x.doc(), undefined, function (ok) { - element.textContent = (findName(x) || utils.label(x)) // had: (ok ? '' : '? ') + + if (!name && x.uri) { + // Note this is only a fetch, not a lookUP of all sameAs etc + kb.fetcher.nowOrWhenFetched(x.doc(), undefined, function (_ok) { + element.textContent = findName(x) || utils.label(x) // had: (ok ? '' : '? ') + }) } } @@ -139,17 +174,19 @@ buttons.setName = function (element, x) { // Set of suitable images buttons.imagesOf = function (x, kb) { var ns = UI.ns - return (kb.each(x, ns.sioc('avatar')) + return kb + .each(x, ns.sioc('avatar')) .concat(kb.each(x, ns.foaf('img'))) .concat(kb.each(x, ns.vcard('logo'))) .concat(kb.each(x, ns.vcard('photo'))) - .concat(kb.each(x, ns.foaf('depiction')))) + .concat(kb.each(x, ns.foaf('depiction'))) } // Best logo or avater or photo etc to represent someone or some group etc // -buttons.iconForClass = { // Potentially extendable by other apps, panes, etc - // Relative URIs to the iconBase +buttons.iconForClass = { + // Potentially extendable by other apps, panes, etc + // Relative URIs to the iconBase 'solid:AppProviderClass': 'noun_144.svg', // @@ classs name should not contain 'Class' 'solid:AppProvider': 'noun_15177.svg', // @@ 'vcard:Group': 'noun_339237.svg', @@ -168,13 +205,15 @@ buttons.iconForClass = { // Potentially extendable by other apps, panes, etc 'ui:Form': 'noun_122196.svg' } -var tempSite = function (x) { // use only while one in rdflib fails with origins 2019 +var tempSite = function (x) { + // use only while one in rdflib fails with origins 2019 var str = x.uri.split('#')[0] var p = str.indexOf('//') if (p < 0) throw new Error('This URI does not have a web site part (origin)') var q = str.indexOf('/', p + 2) - if (q < 0) { // no third slash? - return str.slice(0) + '/' // Add slash to a bare origin + if (q < 0) { + // no third slash? + return str.slice(0) + '/' // Add slash to a bare origin } else { return str.slice(0, q + 1) } @@ -189,18 +228,23 @@ buttons.findImageByClass = function findImageByClass (x) { return iconDir + 'noun_15177.svg' // App } if (x.uri) { - if (x.uri.split('/').length === 4 && !(x.uri.split('/')[1]) && !(x.uri.split('/')[3])) { + if ( + x.uri.split('/').length === 4 && + !x.uri.split('/')[1] && + !x.uri.split('/')[3] + ) { return iconDir + 'noun_15177.svg' // App -- this is an origin } // Non-HTTP URI types imply types - if (x.uri.startsWith('message:') || x.uri.startsWith('mid:')) { // message: is aapple bug-- should be mid: + if (x.uri.startsWith('message:') || x.uri.startsWith('mid:')) { + // message: is aapple bug-- should be mid: return iconDir + 'noun_480183.svg' // envelope noun_567486 } if (x.uri.startsWith('mailto:')) { return iconDir + 'noun_567486.svg' // mailbox - an email desitination } // For HTTP(s) documents, we could look at the MIME type if we know it. - if (x.uri.startsWith('https:') && (x.uri.indexOf('#') < 0)) { + if (x.uri.startsWith('https:') && x.uri.indexOf('#') < 0) { return tempSite(x) + 'favicon.ico' // was x.site().uri + ... // Todo: make the docuent icon a fallback for if the favicon does not exist // todo: pick up a possible favicon for the web page istelf from a link @@ -208,26 +252,28 @@ buttons.findImageByClass = function findImageByClass (x) { } } - ns['prov'] = $rdf.Namespace('http://www.w3.org/ns/prov#') // In case not yet there + ns.prov = $rdf.Namespace('http://www.w3.org/ns/prov#') // In case not yet there for (var k in buttons.iconForClass) { - let pref = k.split(':')[0] - let id = k.split(':')[1] - let klass = ns[pref](id) - if (klass.uri in types || klass.uri === x.uri) { // Allow full URI in new additions + const pref = k.split(':')[0] + const id = k.split(':')[1] + const klass = ns[pref](id) + if (klass.uri in types || klass.uri === x.uri) { + // Allow full URI in new additions return $rdf.uri.join(buttons.iconForClass[k], UI.icons.iconBase) } } return iconDir + 'noun_10636_grey.svg' // Grey Circle - some thing } -buttons.findImage = (thing) => { +buttons.findImage = thing => { const kb = UI.store const ns = UI.ns const iconDir = UI.icons.iconBase if (thing.sameTerm(ns.foaf('Agent')) || thing.sameTerm(ns.rdf('Resource'))) { return iconDir + 'noun_98053.svg' // Globe } - const image = kb.any(thing, ns.sioc('avatar')) || + const image = + kb.any(thing, ns.sioc('avatar')) || kb.any(thing, ns.foaf('img')) || kb.any(thing, ns.vcard('logo')) || kb.any(thing, ns.vcard('hasPhoto')) || @@ -244,7 +290,10 @@ buttons.setImage = function (element, profile) { element.setAttribute('src', uri || buttons.findImageByClass(profile)) if (!uri && profile.uri) { kb.fetcher.nowOrWhenFetched(profile.doc(), undefined, () => { - element.setAttribute('src', buttons.findImage(profile) || buttons.findImageByClass(profile)) + element.setAttribute( + 'src', + buttons.findImage(profile) || buttons.findImageByClass(profile) + ) }) } } @@ -256,11 +305,13 @@ var faviconOrDefault = function (dom, x) { var isOrigin = function (x) { if (!x.uri) return false var parts = x.uri.split('/') - return (parts.length === 3 || (parts.length === 4 && parts[3] === '')) + return parts.length === 3 || (parts.length === 4 && parts[3] === '') } - image.setAttribute('src', UI.icons.iconBase + - (isOrigin(x) ? 'noun_15177.svg' : 'noun_681601.svg')) - if (x.uri && x.uri.startsWith('https:') && (x.uri.indexOf('#') < 0)) { + image.setAttribute( + 'src', + UI.icons.iconBase + (isOrigin(x) ? 'noun_15177.svg' : 'noun_681601.svg') + ) + if (x.uri && x.uri.startsWith('https:') && x.uri.indexOf('#') < 0) { var res = dom.createElement('object') // favico with a fallback of a default image if no favicon res.setAttribute('data', tempSite(x) + 'favicon.ico') res.setAttribute('type', 'image/x-icon') @@ -276,7 +327,12 @@ var faviconOrDefault = function (dom, x) { // // @@ Supress check if command key held down? // -buttons.deleteButtonWithCheck = function (dom, container, noun, deleteFunction) { +buttons.deleteButtonWithCheck = function ( + dom, + container, + noun, + deleteFunction +) { var minusIconURI = UI.icons.iconBase + 'noun_2188_red.svg' // white minus in red #cc0000 circle // var delButton = dom.createElement('button') @@ -291,29 +347,41 @@ buttons.deleteButtonWithCheck = function (dom, container, noun, deleteFunction) container.setAttribute('class', 'hoverControl') // See tabbedtab.css (sigh global CSS) delButton.setAttribute('class', 'hoverControlHide') // delButton.setAttribute('style', 'color: red; margin-right: 0.3em; foat:right; text-align:right') - delButton.addEventListener('click', function (e) { - container.removeChild(delButton) // Ask -- are you sure? - var cancelButton = dom.createElement('button') - // cancelButton.textContent = 'cancel' - cancelButton.setAttribute('style', UI.style.buttonStyle) - var img = cancelButton.appendChild(dom.createElement('img')) - img.setAttribute('src', cancelIconURI) - img.setAttribute('style', UI.style.buttonStyle) - - container.appendChild(cancelButton).addEventListener('click', function (e) { - container.removeChild(sureButton) - container.removeChild(cancelButton) - container.appendChild(delButton) - }, false) - var sureButton = dom.createElement('button') - sureButton.textContent = 'Delete ' + noun - sureButton.setAttribute('style', UI.style.buttonStyle) - container.appendChild(sureButton).addEventListener('click', function (e) { - container.removeChild(sureButton) - container.removeChild(cancelButton) - deleteFunction() - }, false) - }, false) + delButton.addEventListener( + 'click', + function (_event) { + container.removeChild(delButton) // Ask -- are you sure? + var cancelButton = dom.createElement('button') + // cancelButton.textContent = 'cancel' + cancelButton.setAttribute('style', UI.style.buttonStyle) + var img = cancelButton.appendChild(dom.createElement('img')) + img.setAttribute('src', cancelIconURI) + img.setAttribute('style', UI.style.buttonStyle) + + container.appendChild(cancelButton).addEventListener( + 'click', + function (_event) { + container.removeChild(sureButton) + container.removeChild(cancelButton) + container.appendChild(delButton) + }, + false + ) + var sureButton = dom.createElement('button') + sureButton.textContent = 'Delete ' + noun + sureButton.setAttribute('style', UI.style.buttonStyle) + container.appendChild(sureButton).addEventListener( + 'click', + function (_event) { + container.removeChild(sureButton) + container.removeChild(cancelButton) + deleteFunction() + }, + false + ) + }, + false + ) return delButton } @@ -325,7 +393,7 @@ buttons.deleteButtonWithCheck = function (dom, container, noun, deleteFunction) * @param handler - A handler to called when button is clicked * * @returns - the button -*/ + */ buttons.button = function (dom, iconURI, text, handler) { var button = dom.createElement('button') button.setAttribute('type', 'button') @@ -352,9 +420,10 @@ buttons.continueButton = function (dom, handler) { * * Form to get the name of a new thing before we create it * @returns: a promise of (a name or null if cancelled) -*/ + */ buttons.askName = function (dom, kb, container, predicate, klass, noun) { - return new Promise(function (resolve, reject) { + // eslint-disable-next-line promise/param-names + return new Promise(function (resolve, _reject) { var form = dom.createElement('div') // form is broken as HTML behaviour can resurface on js error // classLabel = utils.label(ns.vcard('Individual')) predicate = predicate || UI.ns.foaf('name') // eg 'name' in user's language @@ -376,24 +445,36 @@ buttons.askName = function (dom, kb, container, predicate, klass, noun) { resolve(namefield.value.trim()) } - namefield.addEventListener('keyup', function (e) { - if (e.keyCode === 13) { - gotName() - } - }, false) + namefield.addEventListener( + 'keyup', + function (e) { + if (e.keyCode === 13) { + gotName() + } + }, + false + ) form.appendChild(dom.createElement('br')) const cancel = form.appendChild(buttons.cancelButton(dom)) - cancel.addEventListener('click', function (e) { - form.parentNode.removeChild(form) - resolve(null) - }, false) + cancel.addEventListener( + 'click', + function (_event) { + form.parentNode.removeChild(form) + resolve(null) + }, + false + ) const continueButton = form.appendChild(buttons.continueButton(dom)) - continueButton.addEventListener('click', function (e) { - gotName() - }, false) + continueButton.addEventListener( + 'click', + function (_event) { + gotName() + }, + false + ) namefield.focus() }) // Promise } @@ -406,11 +487,15 @@ buttons.askName = function (dom, kb, container, predicate, klass, noun) { buttons.linkIcon = function (dom, subject, iconURI) { var anchor = dom.createElement('a') anchor.setAttribute('href', subject.uri) - if (subject.uri.startsWith('http')) { // If diff web page + if (subject.uri.startsWith('http')) { + // If diff web page anchor.setAttribute('target', '_blank') // open in a new tab or window } // as mailboxes and mail messages do not need new browser window var img = anchor.appendChild(dom.createElement('img')) - img.setAttribute('src', iconURI || (UI.icons.originalIconBase + 'go-to-this.png')) + img.setAttribute( + 'src', + iconURI || UI.icons.originalIconBase + 'go-to-this.png' + ) img.setAttribute('style', 'margin: 0.3em;') return anchor } @@ -430,24 +515,40 @@ buttons.personTR = function (dom, pred, obj, options) { // var image = td1.appendChild(dom.createElement('img')) var image = faviconOrDefault(dom, obj) - td1.setAttribute('style', 'vertical-align: middle; width:2.5em; padding:0.5em; height: 2.5em;') + td1.setAttribute( + 'style', + 'vertical-align: middle; width:2.5em; padding:0.5em; height: 2.5em;' + ) td2.setAttribute('style', 'vertical-align: middle; text-align:left;') - td3.setAttribute('style', 'vertical-align: middle; width:2em; padding:0.5em; height: 4em;') - image.setAttribute('style', 'width: 3em; height: 3em; margin: 0.1em; border-radius: 1em;') + td3.setAttribute( + 'style', + 'vertical-align: middle; width:2em; padding:0.5em; height: 4em;' + ) + image.setAttribute( + 'style', + 'width: 3em; height: 3em; margin: 0.1em; border-radius: 1em;' + ) td1.appendChild(image) // buttons.setImage(image, obj) buttons.setName(td2, obj) if (options.deleteFunction) { - buttons.deleteButtonWithCheck(dom, td3, options.noun || 'one', options.deleteFunction) + buttons.deleteButtonWithCheck( + dom, + td3, + options.noun || 'one', + options.deleteFunction + ) } - if (obj.uri) { // blank nodes need not apply + if (obj.uri) { + // blank nodes need not apply if (options.link !== false) { var anchor = td3.appendChild(buttons.linkIcon(dom, obj)) anchor.classList.add('HoverControlHide') td3.appendChild(dom.createElement('br')) } - if (options.draggable !== false) { // default is on + if (options.draggable !== false) { + // default is on image.setAttribute('draggable', 'false') // Stop the image being dragged instead - just the TR dragAndDrop.makeDraggable(tr, obj) } @@ -475,7 +576,7 @@ buttons.attachmentList = function (dom, subject, div, options) { var doc = options.doc || subject.doc() if (options.modify === undefined) options.modify = true var modify = options.modify - var promptIcon = options.promptIcon || (UI.icons.iconBase + 'noun_748003.svg') // target + var promptIcon = options.promptIcon || UI.icons.iconBase + 'noun_748003.svg' // target // var promptIcon = options.promptIcon || (UI.icons.iconBase + 'noun_25830.svg') // paperclip var predicate = options.predicate || UI.ns.wf('attachment') var noun = options.noun || 'attachment' @@ -490,7 +591,12 @@ buttons.attachmentList = function (dom, subject, div, options) { attachmentTable.appendChild(dom.createElement('tr')) // attachmentTableTop var deleteAttachment = function (target) { - kb.updater.update($rdf.st(subject, predicate, target, doc), [], function (uri, ok, errorBody, xhr) { + kb.updater.update($rdf.st(subject, predicate, target, doc), [], function ( + uri, + ok, + errorBody, + _xhr + ) { if (ok) { refresh() } else { @@ -500,17 +606,19 @@ buttons.attachmentList = function (dom, subject, div, options) { } var createNewRow = function (target) { var theTarget = target - var opt = {noun: noun} + var opt = { noun: noun } if (modify) { - opt.deleteFunction = function () { deleteAttachment(theTarget) } + opt.deleteFunction = function () { + deleteAttachment(theTarget) + } } return buttons.personTR(dom, predicate, target, opt) } - var refresh = attachmentTable.refresh = function () { + var refresh = (attachmentTable.refresh = function () { var things = kb.each(subject, predicate) things.sort() utils.syncTableToArray(attachmentTable, things, createNewRow) - } + }) attachmentOuter.refresh = refresh // Participate in downstream changes refresh() @@ -521,7 +629,7 @@ buttons.attachmentList = function (dom, subject, div, options) { console.log('Dropped on attachemnt ' + u) // icon was: UI.icons.iconBase + 'noun_25830.svg' ins.push($rdf.st(subject, predicate, target, doc)) }) - kb.updater.update([], ins, function (uri, ok, errorBody, xhr) { + kb.updater.update([], ins, function (uri, ok, errorBody, _xhr) { if (ok) { refresh() } else { @@ -555,13 +663,21 @@ buttons.openHrefInOutlineMode = function (e) { if (!uri) return console.log('openHrefInOutlineMode: No href found!\n') const dom = window.document if (dom.outlineManager) { - dom.outlineManager.GotoSubject(UI.store.sym(uri), true, undefined, true, undefined) + dom.outlineManager.GotoSubject( + UI.store.sym(uri), + true, + undefined, + true, + undefined + ) } else if (window && window.panes && window.panes.getOutliner) { - window.panes.getOutliner().GotoSubject(UI.store.sym(uri), true, undefined, true, undefined) + window.panes + .getOutliner() + .GotoSubject(UI.store.sym(uri), true, undefined, true, undefined) } else { console.log("ERROR: Can't access outline manager in this config") } -// dom.outlineManager.GotoSubject(UI.store.sym(uri), true, undefined, true, undefined) + // dom.outlineManager.GotoSubject(UI.store.sym(uri), true, undefined, true, undefined) } // We make a URI in the annotation store out of the URI of the thing to be annotated. @@ -574,7 +690,8 @@ buttons.defaultAnnotationStore = function (subject) { if (s.slice(0, 7) !== 'http://') return undefined s = s.slice(7) // Remove var hash = s.indexOf('#') - if (hash >= 0) s = s.slice(0, hash) // Strip trailing + if (hash >= 0) s = s.slice(0, hash) + // Strip trailing else { var slash = s.lastIndexOf('/') if (slash < 0) return undefined @@ -585,15 +702,22 @@ buttons.defaultAnnotationStore = function (subject) { buttons.allClassURIs = function () { var set = {} - UI.store.statementsMatching(undefined, UI.ns.rdf('type'), undefined) - .map(function (st) { if (st.object.uri) set[st.object.uri] = true }) - UI.store.statementsMatching(undefined, UI.ns.rdfs('subClassOf'), undefined) + UI.store + .statementsMatching(undefined, UI.ns.rdf('type'), undefined) + .map(function (st) { + if (st.object.uri) set[st.object.uri] = true + }) + UI.store + .statementsMatching(undefined, UI.ns.rdfs('subClassOf'), undefined) .map(function (st) { if (st.object.uri) set[st.object.uri] = true if (st.subject.uri) set[st.subject.uri] = true }) - UI.store.each(undefined, UI.ns.rdf('type'), UI.ns.rdfs('Class')) - .map(function (c) { if (c.uri) set[c.uri] = true }) + UI.store + .each(undefined, UI.ns.rdf('type'), UI.ns.rdfs('Class')) + .map(function (c) { + if (c.uri) set[c.uri] = true + }) return set } @@ -623,17 +747,29 @@ buttons.propertyTriage = function () { for (var i = 0; i < ps.length; i++) { p = ps[i].toNT() UI.log.debug('propertyTriage: unknown: ' + p) - if (!op[p] && !dp[p]) { dp[p] = true; op[p] = true; nu++ } + if (!op[p] && !dp[p]) { + dp[p] = true + op[p] = true + nu++ + } } possibleProperties.op = op possibleProperties.dp = dp - UI.log.info('propertyTriage: ' + no + ' non-lit, ' + nd + ' literal. ' + nu + ' unknown.') + UI.log.info( + 'propertyTriage: ' + + no + + ' non-lit, ' + + nd + + ' literal. ' + + nu + + ' unknown.' + ) return possibleProperties } /* General purpose widgets -** -*/ + ** + */ // A button for jumping // @@ -641,10 +777,14 @@ buttons.linkButton = function (dom, object) { var b = dom.createElement('button') b.setAttribute('type', 'button') b.textContent = 'Goto ' + utils.label(object) - b.addEventListener('click', function (e) { - // b.parentNode.removeChild(b) - dom.outlineManager.GotoSubject(object, true, undefined, true, undefined) - }, true) + b.addEventListener( + 'click', + function (_event) { + // b.parentNode.removeChild(b) + dom.outlineManager.GotoSubject(object, true, undefined, true, undefined) + }, + true + ) return b } @@ -652,9 +792,13 @@ buttons.removeButton = function (dom, element) { var b = dom.createElement('button') b.setAttribute('type', 'button') b.textContent = '✕' // MULTIPLICATION X - b.addEventListener('click', function (e) { - element.parentNode.removeChild(element) - }, true) + b.addEventListener( + 'click', + function (_event) { + element.parentNode.removeChild(element) + }, + true + ) return b } @@ -695,26 +839,61 @@ buttons.headerButtons = function (dom, kb, name, words) { // // @param inverse means this is the object rather than the subject // -buttons.selectorPanel = function (dom, kb, type, - predicate, inverse, possible, options, callbackFunction, linkCallback) { - return buttons.selectorPanelRefresh(dom.createElement('div'), - dom, kb, type, predicate, inverse, possible, options, callbackFunction, linkCallback) +buttons.selectorPanel = function ( + dom, + kb, + type, + predicate, + inverse, + possible, + options, + callbackFunction, + linkCallback +) { + return buttons.selectorPanelRefresh( + dom.createElement('div'), + dom, + kb, + type, + predicate, + inverse, + possible, + options, + callbackFunction, + linkCallback + ) } -buttons.selectorPanelRefresh = function (list, dom, kb, type, - predicate, inverse, possible, options, callbackFunction, linkCallback) { - var style0 = 'border: 0.1em solid #ddd; border-bottom: none; width: 95%; height: 2em; padding: 0.5em;' +buttons.selectorPanelRefresh = function ( + list, + dom, + kb, + type, + predicate, + inverse, + possible, + options, + callbackFunction, + linkCallback +) { + var style0 = + 'border: 0.1em solid #ddd; border-bottom: none; width: 95%; height: 2em; padding: 0.5em;' var selected = null list.innerHTML = '' - var refreshItem = function (box, x) { // Scope to hold item and x + var refreshItem = function (box, x) { + // Scope to hold item and x var item, image var setStyle = function () { - var already = (inverse) ? kb.each(undefined, predicate, x) + var already = inverse + ? kb.each(undefined, predicate, x) : kb.each(x, predicate) iconDiv.setAttribute('class', already.length === 0 ? 'hideTillHover' : '') // See tabbedtab.css - image.setAttribute('src', options.connectIcon || (UI.icons.iconBase + 'noun_25830.svg')) + image.setAttribute( + 'src', + options.connectIcon || UI.icons.iconBase + 'noun_25830.svg' + ) image.setAttribute('title', already.length ? already.length : 'attach') } var f = buttons.index.twoLine.widgetForClass(type) @@ -732,28 +911,43 @@ buttons.selectorPanelRefresh = function (list, dom, kb, type, box.appendChild(nav) var iconDiv = dom.createElement('div') - iconDiv.setAttribute('style', (inverse ? 'float:left;' : 'float:right;') + ' width:30px;') + iconDiv.setAttribute( + 'style', + (inverse ? 'float:left;' : 'float:right;') + ' width:30px;' + ) image = dom.createElement('img') setStyle() iconDiv.appendChild(image) box.appendChild(iconDiv) - item.addEventListener('click', function (event) { - if (selected === item) { // deselect - item.setAttribute('style', style0) - selected = null - } else { - if (selected) selected.setAttribute('style', style0) - item.setAttribute('style', style0 + 'background-color: #ccc; color:black;') - selected = item - } - callbackFunction(x, event, selected === item) - setStyle() - }, false) - - image.addEventListener('click', function (event) { - linkCallback(x, event, inverse, setStyle) - }, false) + item.addEventListener( + 'click', + function (event) { + if (selected === item) { + // deselect + item.setAttribute('style', style0) + selected = null + } else { + if (selected) selected.setAttribute('style', style0) + item.setAttribute( + 'style', + style0 + 'background-color: #ccc; color:black;' + ) + selected = item + } + callbackFunction(x, event, selected === item) + setStyle() + }, + false + ) + + image.addEventListener( + 'click', + function (event) { + linkCallback(x, event, inverse, setStyle) + }, + false + ) box.appendChild(item) return box @@ -780,9 +974,10 @@ buttons.index.twoLine = {} // Approx 40em * 2.4em // // These should be moved to type-dependeent UI code. Related panes maybe -buttons.index.twoLine[''] = function (dom, x) { // Default +buttons.index.twoLine[''] = function (dom, x) { + // Default var box = dom.createElement('div') - box.textContent = (utils.label(x)) + box.textContent = utils.label(x) return box } @@ -798,7 +993,9 @@ buttons.index.twoLine.widgetForClass = function (c) { return buttons.index.twoLine[''] } -buttons.index.twoLine['http://www.w3.org/2000/10/swap/pim/qif#Transaction'] = function (dom, x) { +buttons.index.twoLine[ + 'http://www.w3.org/2000/10/swap/pim/qif#Transaction' +] = function (dom, x) { var failed = '' var enc = function (p) { var y = UI.store.any(x, UI.ns.qu(p)) @@ -806,26 +1003,41 @@ buttons.index.twoLine['http://www.w3.org/2000/10/swap/pim/qif#Transaction'] = fu return y ? utils.escapeForXML(y.value) : '?' // @@@@ } var box = dom.createElement('table') - box.innerHTML = '' + enc('payee') + - '\n' + enc('date').slice(0, 10) + - '' + enc('amount') + '' + box.innerHTML = + '' + + enc('payee') + + '\n' + + enc('date').slice(0, 10) + + '' + + enc('amount') + + '' if (failed) { - box.innerHTML = '' + - utils.escapeForXML(failed) + '' + box.innerHTML = + '' + + utils.escapeForXML(failed) + + '' } return box } -buttons.index.twoLine['http://www.w3.org/ns/pim/trip#Trip'] = function (dom, x) { +buttons.index.twoLine['http://www.w3.org/ns/pim/trip#Trip'] = function ( + dom, + x +) { var enc = function (p) { var y = UI.store.any(x, p) return y ? utils.escapeForXML(y.value) : '?' } var box = dom.createElement('table') - box.innerHTML = '' + enc(UI.ns.dc('title')) + + box.innerHTML = + '' + + enc(UI.ns.dc('title')) + '\n' + - enc(UI.ns.cal('dtstart')) + '' + enc(UI.ns.cal('dtend')) + + enc(UI.ns.cal('dtstart')) + + '' + + enc(UI.ns.cal('dtend')) + '' return box } @@ -834,8 +1046,12 @@ buttons.index.twoLine['http://www.w3.org/ns/pim/trip#Trip'] = function (dom, x) buttons.addStyleSheet = function (dom, href) { var links = dom.querySelectorAll('link') for (var i = 0; i < links.length; i++) { - if ((links[i].getAttribute('rel') || '') === 'stylesheet' && - (links[i].getAttribute('href') || '') === href) return + if ( + (links[i].getAttribute('rel') || '') === 'stylesheet' && + (links[i].getAttribute('href') || '') === href + ) { + return + } } var link = dom.createElement('link') link.setAttribute('rel', 'stylesheet') @@ -853,9 +1069,10 @@ buttons.isVideo = function (file) { return buttons.isImage(file, 'video') } buttons.isImage = function (file, kind) { - var dcCLasses = { 'audio': 'http://purl.org/dc/dcmitype/Sound', - 'image': 'http://purl.org/dc/dcmitype/Image', - 'video': 'http://purl.org/dc/dcmitype/MovingImage' + var dcCLasses = { + audio: 'http://purl.org/dc/dcmitype/Sound', + image: 'http://purl.org/dc/dcmitype/Image', + video: 'http://purl.org/dc/dcmitype/MovingImage' } var what = kind || 'image' var typeURIs = UI.store.findTypeURIs(file) @@ -868,33 +1085,47 @@ buttons.isImage = function (file, kind) { } /** File upload button -** + ** * @param dom The DOM aka document * @param display:none - Same handler function as drop, takes array of file objects * @returns {Element} - a div with a button and a inout in it * The input is hidden, as it is uglky - the user clicks on the nice icons and fires the input. */ // See https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications -buttons.fileUploadButtonDiv = function fileUploadButtonDiv (dom, droppedFileHandler) { +buttons.fileUploadButtonDiv = function fileUploadButtonDiv ( + dom, + droppedFileHandler +) { const div = dom.createElement('div') const input = div.appendChild(dom.createElement('input')) input.setAttribute('type', 'file') input.setAttribute('multiple', 'true') - input.addEventListener('change', event => { - console.log('File drop event: ', event) - if (event.files) { - droppedFileHandler(event.files) - } else if (event.target && event.target.files) { - droppedFileHandler(event.target.files) - } else { - alert('Sorry no files .. internal error?') - } - }, false) + input.addEventListener( + 'change', + event => { + console.log('File drop event: ', event) + if (event.files) { + droppedFileHandler(event.files) + } else if (event.target && event.target.files) { + droppedFileHandler(event.target.files) + } else { + alert('Sorry no files .. internal error?') + } + }, + false + ) input.style = 'display:none' - const button = div.appendChild(buttons.button(dom, UI.icons.iconBase + 'noun_Upload_76574_000000.svg', 'Upload files', event => { - input.click() - })) + const button = div.appendChild( + buttons.button( + dom, + UI.icons.iconBase + 'noun_Upload_76574_000000.svg', + 'Upload files', + _event => { + input.click() + } + ) + ) dragAndDrop.makeDropTarget(button, null, droppedFileHandler) // Can also just drop on button return div } diff --git a/src/widgets/dragAndDrop.js b/src/widgets/dragAndDrop.js index e979dae10..137ae0756 100644 --- a/src/widgets/dragAndDrop.js +++ b/src/widgets/dragAndDrop.js @@ -1,5 +1,5 @@ /* Drag and drop common functionality -*/ + */ const mime = require('mime-types') /* global FileReader alert */ @@ -18,7 +18,8 @@ function makeDropTarget (ele, droppedURIHandler, droppedFileHandler) { var dragenterListener = function (e) { console.log('dragenter event dropEffect: ' + e.dataTransfer.dropEffect) - if (this.style) { // necessary not sure when + if (this.style) { + // necessary not sure when if (!this.savedStyle) { this.savedStyle = {} this.savedStyle.border = this.style.border @@ -48,7 +49,10 @@ function makeDropTarget (ele, droppedURIHandler, droppedFileHandler) { var dropListener = function (e) { if (e.preventDefault) e.preventDefault() // stops the browser from redirecting off to the text. console.log('Drop event. dropEffect: ' + e.dataTransfer.dropEffect) - console.log('Drop event. types: ' + (e.dataTransfer.types ? e.dataTransfer.types.join(', ') : 'NOPE')) + console.log( + 'Drop event. types: ' + + (e.dataTransfer.types ? e.dataTransfer.types.join(', ') : 'NOPE') + ) var uris = null var text @@ -63,11 +67,19 @@ function makeDropTarget (ele, droppedURIHandler, droppedFileHandler) { } else if (type === 'Files' && droppedFileHandler) { var files = e.dataTransfer.files // FileList object. for (let i = 0; files[i]; i++) { - let f = files[i] - console.log('Filename: ' + f.name + ', type: ' + (f.type || 'n/a') + - ' size: ' + f.size + ' bytes, last modified: ' + - (f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a') - ) + const f = files[i] + console.log( + 'Filename: ' + + f.name + + ', type: ' + + (f.type || 'n/a') + + ' size: ' + + f.size + + ' bytes, last modified: ' + + (f.lastModifiedDate + ? f.lastModifiedDate.toLocaleDateString() + : 'n/a') + ) } droppedFileHandler(files) } @@ -78,7 +90,7 @@ function makeDropTarget (ele, droppedURIHandler, droppedFileHandler) { } } else { // ... however, if we're IE, we don't have the .types property, so we'll just get the Text value - uris = [ e.dataTransfer.getData('Text') ] + uris = [e.dataTransfer.getData('Text')] console.log('WARNING non-standard drop event: ' + uris[0]) } console.log('Dropped URI list (2): ' + uris) @@ -108,45 +120,65 @@ function makeDropTarget (ele, droppedURIHandler, droppedFileHandler) { function makeDraggable (tr, obj) { tr.setAttribute('draggable', 'true') // Stop the image being dragged instead - just the TR - tr.addEventListener('dragstart', function (e) { - tr.style.fontWeight = 'bold' - e.dataTransfer.setData('text/uri-list', obj.uri) - e.dataTransfer.setData('text/plain', obj.uri) - e.dataTransfer.setData('text/html', tr.outerHTML) - console.log('Dragstart: ' + tr + ' -> ' + obj + 'de: ' + e.dataTransfer.dropEffect) - }, false) + tr.addEventListener( + 'dragstart', + function (e) { + tr.style.fontWeight = 'bold' + e.dataTransfer.setData('text/uri-list', obj.uri) + e.dataTransfer.setData('text/plain', obj.uri) + e.dataTransfer.setData('text/html', tr.outerHTML) + console.log( + 'Dragstart: ' + tr + ' -> ' + obj + 'de: ' + e.dataTransfer.dropEffect + ) + }, + false + ) - tr.addEventListener('drag', function (e) { - e.preventDefault() - e.stopPropagation() - // console.log('Drag: dropEffect: ' + e.dataTransfer.dropEffect) - }, false) + tr.addEventListener( + 'drag', + function (e) { + e.preventDefault() + e.stopPropagation() + // console.log('Drag: dropEffect: ' + e.dataTransfer.dropEffect) + }, + false + ) - tr.addEventListener('dragend', function (e) { - tr.style.fontWeight = 'normal' - console.log('Dragend dropeffect: ' + e.dataTransfer.dropEffect) - console.log('Dragend: ' + tr + ' -> ' + obj) - }, false) + tr.addEventListener( + 'dragend', + function (e) { + tr.style.fontWeight = 'normal' + console.log('Dragend dropeffect: ' + e.dataTransfer.dropEffect) + console.log('Dragend: ' + tr + ' -> ' + obj) + }, + false + ) } /* uploadFiles -** -** Generic uploader of local files to the web -** typically called from dropped file handler -** Params -** fetcher instance of class Fetcher as in kb.fetcher -** files Array of file objects -** fileBase URI of folder in which to put files (except images) (no trailing slash) -** imageBase URI of folder in which to put images -** successHandler(file, uploadedURI) Called after each success upload -** With file object an final URI as params -*/ + ** + ** Generic uploader of local files to the web + ** typically called from dropped file handler + ** Params + ** fetcher instance of class Fetcher as in kb.fetcher + ** files Array of file objects + ** fileBase URI of folder in which to put files (except images) (no trailing slash) + ** imageBase URI of folder in which to put images + ** successHandler(file, uploadedURI) Called after each success upload + ** With file object an final URI as params + */ function uploadFiles (fetcher, files, fileBase, imageBase, successHandler) { for (var i = 0; files[i]; i++) { - let f = files[i] - console.log(' dropped: Filename: ' + f.name + ', type: ' + (f.type || 'n/a') + - ' size: ' + f.size + ' bytes, last modified: ' + - (f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a') + const f = files[i] + console.log( + ' dropped: Filename: ' + + f.name + + ', type: ' + + (f.type || 'n/a') + + ' size: ' + + f.size + + ' bytes, last modified: ' + + (f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a') ) // See e.g. https://www.html5rocks.com/en/tutorials/file/dndfiles/ // @@ Add: progress bar(s) @@ -157,10 +189,13 @@ function uploadFiles (fetcher, files, fileBase, imageBase, successHandler) { var suffix = '' console.log(' File read byteLength : ' + data.byteLength) var contentType = theFile.type - if (!theFile.type || theFile.type === '') { // Not known by browser + if (!theFile.type || theFile.type === '') { + // Not known by browser contentType = mime.lookup(theFile.name) if (!contentType) { - let msg = 'Filename needs to have an extension which gives a type we know: ' + theFile.name + const msg = + 'Filename needs to have an extension which gives a type we know: ' + + theFile.name console.log(msg) alert(msg) throw new Error(msg) @@ -172,20 +207,32 @@ function uploadFiles (fetcher, files, fileBase, imageBase, successHandler) { console.log('MIME TYPE MISMATCH -- adding extension: ' + suffix) } } - var folderName = theFile.type.startsWith('image/') ? imageBase || fileBase : fileBase - var destURI = folderName + (folderName.endsWith('/') ? '' : '/') + encodeURIComponent(theFile.name) + suffix + var folderName = theFile.type.startsWith('image/') + ? imageBase || fileBase + : fileBase + var destURI = + folderName + + (folderName.endsWith('/') ? '' : '/') + + encodeURIComponent(theFile.name) + + suffix - fetcher.webOperation('PUT', destURI, { data: data, contentType: contentType }) - .then(response => { - console.log(' Upload: put OK: ' + destURI) - successHandler(theFile, destURI) - }, + fetcher + .webOperation('PUT', destURI, { + data: data, + contentType: contentType + }) + .then( + _response => { + console.log(' Upload: put OK: ' + destURI) + successHandler(theFile, destURI) + }, error => { - let msg = ' Upload: FAIL ' + destURI + ', Error: ' + error + const msg = ' Upload: FAIL ' + destURI + ', Error: ' + error console.log(msg) alert(msg) throw new Error(msg) - }) + } + ) } })(f) reader.readAsArrayBuffer(f) diff --git a/src/widgets/error.js b/src/widgets/error.js index 386ff5f3c..9b39dafbb 100644 --- a/src/widgets/error.js +++ b/src/widgets/error.js @@ -2,8 +2,12 @@ module.exports.errorMessageBlock = errorMessageBlock function errorMessageBlock (dom, msg, backgroundColor) { var div = dom.createElement('div') - div.setAttribute('style', 'margin: 0.1em; padding: 0.5em; border: 0.05em solid gray; background-color: ' + - (backgroundColor || '#fee') + '; color:black;') + div.setAttribute( + 'style', + 'margin: 0.1em; padding: 0.5em; border: 0.05em solid gray; background-color: ' + + (backgroundColor || '#fee') + + '; color:black;' + ) div.textContent = msg return div } diff --git a/src/widgets/forms.js b/src/widgets/forms.js index 1a4b4fe04..555e7d86e 100644 --- a/src/widgets/forms.js +++ b/src/widgets/forms.js @@ -1,5 +1,7 @@ /* -*/ + */ + +const $rdf = require('rdflib') module.exports = {} @@ -26,86 +28,102 @@ const dashCharacter = '-' // /////////////////////////////////////////////////////////////////////// /* Form Field implementations -** -*/ + ** + */ /* Group of different fields -** -*/ -forms.field[UI.ns.ui('Form').uri] = - forms.field[UI.ns.ui('Group').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { - var kb = UI.store - var box = dom.createElement('div') - box.setAttribute('style', 'padding-left: 2em; border: 0.05em solid brown;') // Indent a group - var ui = UI.ns.ui - container.appendChild(box) - - // Prevent loops - var key = subject.toNT() + '|' + form.toNT() - if (already[key]) { // been there done that - box.appendChild(dom.createTextNode('Group: see above ' + key)) - var plist = [$rdf.st(subject, UI.ns.owl('sameAs'), subject)] // @@ need prev subject - dom.outlineManager.appendPropertyTRs(box, plist) - return box - } - // box.appendChild(dom.createTextNode('Group: first time, key: '+key)) - var already2 = {} - for (var x in already) already2[x] = 1 - already2[key] = 1 - - var parts = kb.any(form, ui('parts')) - var p2 - if (parts) { - p2 = parts.elements - } else { - parts = kb.each(form, ui('part')) // Warning: unordered - p2 = forms.sortBySequence(parts) - } - if (!parts) { - box.appendChild(error.errorMessageBlock(dom, - 'No parts to form! ')) - return dom + ** + */ +forms.field[UI.ns.ui('Form').uri] = forms.field[ + UI.ns.ui('Group').uri +] = function (dom, container, already, subject, form, store, callbackFunction) { + var kb = UI.store + var box = dom.createElement('div') + box.setAttribute('style', 'padding-left: 2em; border: 0.05em solid brown;') // Indent a group + var ui = UI.ns.ui + container.appendChild(box) + + // Prevent loops + var key = subject.toNT() + '|' + form.toNT() + if (already[key]) { + // been there done that + box.appendChild(dom.createTextNode('Group: see above ' + key)) + var plist = [$rdf.st(subject, UI.ns.owl('sameAs'), subject)] // @@ need prev subject + dom.outlineManager.appendPropertyTRs(box, plist) + return box + } + // box.appendChild(dom.createTextNode('Group: first time, key: '+key)) + var already2 = {} + for (var x in already) already2[x] = 1 + already2[key] = 1 + + var parts = kb.any(form, ui('parts')) + var p2 + if (parts) { + p2 = parts.elements + } else { + parts = kb.each(form, ui('part')) // Warning: unordered + p2 = forms.sortBySequence(parts) + } + if (!parts) { + box.appendChild(error.errorMessageBlock(dom, 'No parts to form! ')) + return dom + } + var eles = [] + var original = [] + for (var i = 0; i < p2.length; i++) { + var field = p2[i] + var t = forms.bottomURI(field) // Field type + if (t === ui('Options').uri) { + var dep = kb.any(field, ui('dependingOn')) + if (dep && kb.any(subject, dep)) original[i] = kb.any(subject, dep).toNT() } - var eles = [] - var original = [] - for (var i = 0; i < p2.length; i++) { - var field = p2[i] - var t = forms.bottomURI(field) // Field type - if (t === ui('Options').uri) { - var dep = kb.any(field, ui('dependingOn')) - if (dep && kb.any(subject, dep)) original[i] = kb.any(subject, dep).toNT() - } - var fn = forms.fieldFunction(dom, field) + var fn = forms.fieldFunction(dom, field) - var itemChanged = function (ok, body) { - if (ok) { - for (var j = 0; j < p2.length; j++) { // This is really messy. - var field = (p2[j]) - var t = forms.bottomURI(field) // Field type - if (t === ui('Options').uri) { - var dep = kb.any(field, ui('dependingOn')) - var newOne = fn(dom, box, already, subject, field, store, callbackFunction) - box.removeChild(newOne) - box.insertBefore(newOne, eles[j]) - box.removeChild(eles[j]) - original[j] = kb.any(subject, dep).toNT() - eles[j] = newOne - } + var itemChanged = function (ok, body) { + if (ok) { + for (var j = 0; j < p2.length; j++) { + // This is really messy. + var field = p2[j] + var t = forms.bottomURI(field) // Field type + if (t === ui('Options').uri) { + var dep = kb.any(field, ui('dependingOn')) + var newOne = fn( + dom, + box, + already, + subject, + field, + store, + callbackFunction + ) + box.removeChild(newOne) + box.insertBefore(newOne, eles[j]) + box.removeChild(eles[j]) + original[j] = kb.any(subject, dep).toNT() + eles[j] = newOne } } - callbackFunction(ok, body) } - eles.push(fn(dom, box, already2, subject, field, store, itemChanged)) + callbackFunction(ok, body) } - return box + eles.push(fn(dom, box, already2, subject, field, store, itemChanged)) } + return box +} /* Options: Select one or more cases -** -*/ + ** + */ forms.field[UI.ns.ui('Options').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { var kb = UI.store var box = dom.createElement('div') // box.setAttribute('style', 'padding-left: 2em; border: 0.05em dotted purple;') // Indent Options @@ -118,8 +136,7 @@ forms.field[UI.ns.ui('Options').uri] = function ( } // @@ default to type (do we want defaults?) var cases = kb.each(form, ui('case')) if (!cases) { - box.appendChild(error.errorMessageBlock(dom, - 'No cases to Options form. ')) + box.appendChild(error.errorMessageBlock(dom, 'No cases to Options form. ')) } var values if (dependingOn.sameTerm(UI.ns.rdf('type'))) { @@ -127,8 +144,12 @@ forms.field[UI.ns.ui('Options').uri] = function ( } else { var value = kb.any(subject, dependingOn) if (value === undefined) { - box.appendChild(error.errorMessageBlock(dom, - "Can't select subform as no value of: " + dependingOn)) + box.appendChild( + error.errorMessageBlock( + dom, + "Can't select subform as no value of: " + dependingOn + ) + ) } else { values = {} values[value.uri] = true @@ -142,11 +163,23 @@ forms.field[UI.ns.ui('Options').uri] = function ( if (values[tests[j].uri]) { var field = kb.the(c, ui('use')) if (!field) { - box.appendChild(error.errorMessageBlock(dom, - 'No "use" part for case in form ' + form)) + box.appendChild( + error.errorMessageBlock( + dom, + 'No "use" part for case in form ' + form + ) + ) return box } else { - forms.appendForm(dom, box, already, subject, field, store, callbackFunction) + forms.appendForm( + dom, + box, + already, + subject, + field, + store, + callbackFunction + ) } break } @@ -156,10 +189,17 @@ forms.field[UI.ns.ui('Options').uri] = function ( } /* Multiple similar fields (unordered) -** -*/ + ** + */ forms.field[UI.ns.ui('Multiple').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { // var plusIcon = UI.icons.originalIconBase + 'tango/22-list-add.png' // blue plus var plusIconURI = UI.icons.iconBase + 'noun_19460_green.svg' // white plus in green circle @@ -172,8 +212,9 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( container.appendChild(box) var property = kb.any(form, ui('property')) if (!property) { - box.appendChild(error.errorMessageBlock(dom, - 'No property to multiple: ' + form)) // used for arcs in the data + box.appendChild( + error.errorMessageBlock(dom, 'No property to multiple: ' + form) + ) // used for arcs in the data return box } var min = kb.any(form, ui('min')) // This is the minimum number -- default 0 @@ -183,7 +224,9 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( var element = kb.any(form, ui('part')) // This is the form to use for each one if (!element) { - box.appendChild(error.errorMessageBlock(dom, 'No part to multiple: ' + form)) + box.appendChild( + error.errorMessageBlock(dom, 'No part to multiple: ' + form) + ) return box } @@ -191,20 +234,22 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( var body = box.appendChild(dom.createElement('tr')) var tail = box.appendChild(dom.createElement('tr')) - var addItem = function (e, object) { UI.log.debug('Multiple add: ' + object) // ++count if (!object) object = forms.newThing(store) var tr = box.insertBefore(dom.createElement('tr'), tail) var itemDone = function (uri, ok, message) { - if (ok) { // @@@ Check IT hasnt alreday been written in + if (ok) { + // @@@ Check IT hasnt alreday been written in if (!kb.holds(subject, property, object, store)) { var ins = [$rdf.st(subject, property, object, store)] kb.updater.update([], ins, linkDone) } } else { - tr.appendChild(error.errorMessageBlock(dom, 'Multiple: item failed: ' + body)) + tr.appendChild( + error.errorMessageBlock(dom, 'Multiple: item failed: ' + body) + ) callbackFunction(ok, message) } } @@ -223,13 +268,23 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( if (ok) { body.removeChild(subField) } else { - body.appendChild(error.errorMessageBlock(dom, 'Multiple: delete failed: ' + message)) + body.appendChild( + error.errorMessageBlock( + dom, + 'Multiple: delete failed: ' + message + ) + ) } }) } } if (kb.updater.editable(store.uri)) { - buttons.deleteButtonWithCheck(dom, subField, utils.label(property), deleteItem) + buttons.deleteButtonWithCheck( + dom, + subField, + utils.label(property), + deleteItem + ) } } @@ -240,12 +295,15 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( img.setAttribute('style', 'margin: 0.2em; width: 1em; height:1em') img.title = 'Click to add one or more ' + utils.label(property) var prompt = tail.appendChild(dom.createElement('span')) - prompt.textContent = (values.length === 0 ? 'Add one or more ' : 'Add more ') + + prompt.textContent = + (values.length === 0 ? 'Add one or more ' : 'Add more ') + utils.label(property) tail.addEventListener('click', addItem, true) // img.addEventListener('click', addItem, true) } - values.map(function (obj) { addItem(null, obj) }) + values.map(function (obj) { + addItem(null, obj) + }) var extra = min - values.length for (var j = 0; j < extra; j++) { console.log('Adding extra: min ' + min) @@ -255,8 +313,8 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( } /* Text field -** -*/ + ** + */ // For possible date popups see e.g. http://www.dynamicdrive.com/dynamicindex7/jasoncalendar.htm // or use HTML5: http://www.w3.org/TR/2011/WD-html-markup-20110113/input.date.html // @@ -264,227 +322,317 @@ forms.field[UI.ns.ui('Multiple').uri] = function ( forms.fieldParams = {} forms.fieldParams[UI.ns.ui('ColorField').uri] = { - 'size': 9, 'type': 'color', dt: 'color' } // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color -forms.fieldParams[UI.ns.ui('ColorField').uri].pattern = - /^\s*#[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]([0-9a-f][0-9a-f])?\s*$/ + size: 9, + type: 'color', + dt: 'color' +} // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color +forms.fieldParams[ + UI.ns.ui('ColorField').uri +].pattern = /^\s*#[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]([0-9a-f][0-9a-f])?\s*$/ forms.fieldParams[UI.ns.ui('DateField').uri] = { - 'size': 20, 'type': 'date', 'dt': 'date'} -forms.fieldParams[UI.ns.ui('DateField').uri].pattern = - /^\s*[0-9][0-9][0-9][0-9](-[0-1]?[0-9]-[0-3]?[0-9])?Z?\s*$/ + size: 20, + type: 'date', + dt: 'date' +} +forms.fieldParams[ + UI.ns.ui('DateField').uri +].pattern = /^\s*[0-9][0-9][0-9][0-9](-[0-1]?[0-9]-[0-3]?[0-9])?Z?\s*$/ forms.fieldParams[UI.ns.ui('DateTimeField').uri] = { - 'size': 20, 'type': 'date', 'dt': 'dateTime'} -forms.fieldParams[UI.ns.ui('DateTimeField').uri].pattern = - /^\s*[0-9][0-9][0-9][0-9](-[0-1]?[0-9]-[0-3]?[0-9])?(T[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?)?Z?\s*$/ + size: 20, + type: 'date', + dt: 'dateTime' +} +forms.fieldParams[ + UI.ns.ui('DateTimeField').uri +].pattern = /^\s*[0-9][0-9][0-9][0-9](-[0-1]?[0-9]-[0-3]?[0-9])?(T[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?)?Z?\s*$/ forms.fieldParams[UI.ns.ui('TimeField').uri] = { - 'size': 10, 'type': 'time', 'dt': 'time'} -forms.fieldParams[UI.ns.ui('TimeField').uri].pattern = - /^\s*([0-2]?[0-9]:[0-5][0-9](:[0-5][0-9])?)\s*$/ + size: 10, + type: 'time', + dt: 'time' +} +forms.fieldParams[ + UI.ns.ui('TimeField').uri +].pattern = /^\s*([0-2]?[0-9]:[0-5][0-9](:[0-5][0-9])?)\s*$/ forms.fieldParams[UI.ns.ui('IntegerField').uri] = { - 'size': 12, 'style': 'text-align: right', 'dt': 'integer' } -forms.fieldParams[UI.ns.ui('IntegerField').uri].pattern = - /^\s*-?[0-9]+\s*$/ + size: 12, + style: 'text-align: right', + dt: 'integer' +} +forms.fieldParams[UI.ns.ui('IntegerField').uri].pattern = /^\s*-?[0-9]+\s*$/ forms.fieldParams[UI.ns.ui('DecimalField').uri] = { - 'size': 12, 'style': 'text-align: right', 'dt': 'decimal' } -forms.fieldParams[UI.ns.ui('DecimalField').uri].pattern = - /^\s*-?[0-9]*(\.[0-9]*)?\s*$/ + size: 12, + style: 'text-align: right', + dt: 'decimal' +} +forms.fieldParams[ + UI.ns.ui('DecimalField').uri +].pattern = /^\s*-?[0-9]*(\.[0-9]*)?\s*$/ forms.fieldParams[UI.ns.ui('FloatField').uri] = { - 'size': 12, 'style': 'text-align: right', 'dt': 'float' } -forms.fieldParams[UI.ns.ui('FloatField').uri].pattern = - /^\s*-?[0-9]*(\.[0-9]*)?((e|E)-?[0-9]*)?\s*$/ - -forms.fieldParams[UI.ns.ui('SingleLineTextField').uri] = { } -forms.fieldParams[UI.ns.ui('NamedNodeURIField').uri] = {namedNode: true} -forms.fieldParams[UI.ns.ui('TextField').uri] = { } - -forms.fieldParams[UI.ns.ui('PhoneField').uri] = { 'size': 20, 'uriPrefix': 'tel:' } -forms.fieldParams[UI.ns.ui('PhoneField').uri].pattern = - /^\+?[\d-]+[\d]*$/ - -forms.fieldParams[UI.ns.ui('EmailField').uri] = { 'size': 30, 'uriPrefix': 'mailto:' } -forms.fieldParams[UI.ns.ui('EmailField').uri].pattern = - /^\s*.*@.*\..*\s*$/ // @@ Get the right regexp here - -forms.field[UI.ns.ui('PhoneField').uri] = - forms.field[UI.ns.ui('EmailField').uri] = - forms.field[UI.ns.ui('ColorField').uri] = - forms.field[UI.ns.ui('DateField').uri] = - forms.field[UI.ns.ui('DateTimeField').uri] = - forms.field[UI.ns.ui('TimeField').uri] = - forms.field[UI.ns.ui('NumericField').uri] = - forms.field[UI.ns.ui('IntegerField').uri] = - forms.field[UI.ns.ui('DecimalField').uri] = - forms.field[UI.ns.ui('FloatField').uri] = - forms.field[UI.ns.ui('TextField').uri] = - forms.field[UI.ns.ui('SingleLineTextField').uri] = - forms.field[UI.ns.ui('NamedNodeURIField').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { - var ui = UI.ns.ui - var kb = UI.store - - var box = dom.createElement('tr') - container.appendChild(box) - var lhs = dom.createElement('td') - lhs.setAttribute('class', 'formFieldName') - lhs.setAttribute('style', ' vertical-align: middle;') - box.appendChild(lhs) - var rhs = dom.createElement('td') - rhs.setAttribute('class', 'formFieldValue') - box.appendChild(rhs) - - var property = kb.any(form, ui('property')) - if (!property) { - box.appendChild(dom.createTextNode('Error: No property given for text field: ' + form)) - return box - } - lhs.appendChild(forms.fieldLabel(dom, property, form)) - var uri = forms.bottomURI(form) - var params = forms.fieldParams[uri] - if (params === undefined) params = {} // non-bottom field types can do this - var style = params.style || 'font-size: 100%; margin: 0.1em; padding: 0.1em;' - // box.appendChild(dom.createTextNode(' uri='+uri+', pattern='+ params.pattern)) - var field = dom.createElement('input') - rhs.appendChild(field) - field.setAttribute('type', params.type ? params.type : 'text') - - var size = kb.any(form, ui('size')) // Form has precedence - field.setAttribute('size', size ? '' + size : (params.size ? '' + params.size : '20')) - var maxLength = kb.any(form, ui('maxLength')) - field.setAttribute('maxLength', maxLength ? '' + maxLength : '4096') - - store = store || forms.fieldStore(subject, property, store) - - var obj = kb.any(subject, property, undefined, store) - if (!obj) { - obj = kb.any(form, ui('default')) - } - if (obj && obj.uri && params.uriPrefix) { // eg tel: or mailto: - field.value = decodeURIComponent(obj.uri.replace(params.uriPrefix, '')) // should have no spaces but in case - .replace(/ /g, '') - } else if (obj) { - field.value = obj.value || obj.uri || '' - } - field.setAttribute('style', style) - - if (!kb.updater.editable(store.uri)) { - field.disabled = true - return box - } - ///////// read-write: - - field.addEventListener('keyup', function (e) { - if (params.pattern) { - field.setAttribute('style', style + ( - field.value.match(params.pattern) - ? 'color: green;' : 'color: red;')) - } - }, true) - field.addEventListener('change', function (e) { // i.e. lose focus with changed data - if (params.pattern && !field.value.match(params.pattern)) return - field.disabled = true // See if this stops getting two dates from fumbling e.g the chrome datepicker. - field.setAttribute('style', style + 'color: gray;') // pending - var ds = kb.statementsMatching(subject, property) // remove any multiple values - var result - if (params.namedNode) { - result = kb.sym(field.value) - } else if (params.uriPrefix) { - result = encodeURIComponent(field.value.replace(/ /g, '')) - result = kb.sym(params.uriPrefix + field.value) - } else { - if (params.dt) { - result = new $rdf.Literal(field.value.trim(), undefined, UI.ns.xsd(params.dt)) - } else { - result = new $rdf.Literal(field.value) - } - } - var is = ds.map(st => $rdf.st(st.subject, st.predicate, result, st.why)) // can include >1 doc - if (is.length === 0) { // or none - is = [$rdf.st(subject, property, result, store)] - } - - function updateMany (ds, is, callback) { - var docs = [] - is.forEach(st => { - if (!docs.includes(st.why.uri)) docs.push(st.why.uri) - }) - ds.forEach(st => { - if (!docs.includes(st.why.uri)) docs.push(st.why.uri) - }) - if (docs.length === 0) throw new Error('updateMany has no docs to patch') - if (docs.length === 1) return kb.updater.update(ds, is, callback) - console.log('Update many: ' + docs) - let doc = docs.pop() - let is1 = is.filter(st => st.why.uri === doc) - let is2 = is.filter(st => st.why.uri !== doc) - let ds1 = ds.filter(st => st.why.uri === doc) - let ds2 = ds.filter(st => st.why.uri !== doc) - kb.updater.update(ds1, is1, function (uri, ok, body) { - if (ok) { - updateMany(ds2, is2, callback) - } else { - console.log('Update many failed on: ' + doc) - callback(uri, ok, body) - } - }) - } - - updateMany(ds, is, function (uri, ok, body) { - // kb.updater.update(ds, is, function (uri, ok, body) { - if (ok) { - field.disabled = false - field.setAttribute('style', style) - } else { - box.appendChild(error.errorMessageBlock(dom, body)) - } - callbackFunction(ok, body) - }) - }, true) - return box - } + size: 12, + style: 'text-align: right', + dt: 'float' +} +forms.fieldParams[ + UI.ns.ui('FloatField').uri +].pattern = /^\s*-?[0-9]*(\.[0-9]*)?((e|E)-?[0-9]*)?\s*$/ + +forms.fieldParams[UI.ns.ui('SingleLineTextField').uri] = {} +forms.fieldParams[UI.ns.ui('NamedNodeURIField').uri] = { namedNode: true } +forms.fieldParams[UI.ns.ui('TextField').uri] = {} + +forms.fieldParams[UI.ns.ui('PhoneField').uri] = { size: 20, uriPrefix: 'tel:' } +forms.fieldParams[UI.ns.ui('PhoneField').uri].pattern = /^\+?[\d-]+[\d]*$/ + +forms.fieldParams[UI.ns.ui('EmailField').uri] = { + size: 30, + uriPrefix: 'mailto:' +} +forms.fieldParams[UI.ns.ui('EmailField').uri].pattern = /^\s*.*@.*\..*\s*$/ // @@ Get the right regexp here + +forms.field[UI.ns.ui('PhoneField').uri] = forms.field[ + UI.ns.ui('EmailField').uri +] = forms.field[UI.ns.ui('ColorField').uri] = forms.field[ + UI.ns.ui('DateField').uri +] = forms.field[UI.ns.ui('DateTimeField').uri] = forms.field[ + UI.ns.ui('TimeField').uri +] = forms.field[UI.ns.ui('NumericField').uri] = forms.field[ + UI.ns.ui('IntegerField').uri +] = forms.field[UI.ns.ui('DecimalField').uri] = forms.field[ + UI.ns.ui('FloatField').uri +] = forms.field[UI.ns.ui('TextField').uri] = forms.field[ + UI.ns.ui('SingleLineTextField').uri +] = forms.field[UI.ns.ui('NamedNodeURIField').uri] = function ( + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { + var ui = UI.ns.ui + var kb = UI.store + + var box = dom.createElement('tr') + container.appendChild(box) + var lhs = dom.createElement('td') + lhs.setAttribute('class', 'formFieldName') + lhs.setAttribute('style', ' vertical-align: middle;') + box.appendChild(lhs) + var rhs = dom.createElement('td') + rhs.setAttribute('class', 'formFieldValue') + box.appendChild(rhs) + + var property = kb.any(form, ui('property')) + if (!property) { + box.appendChild( + dom.createTextNode('Error: No property given for text field: ' + form) + ) + return box + } + lhs.appendChild(forms.fieldLabel(dom, property, form)) + var uri = forms.bottomURI(form) + var params = forms.fieldParams[uri] + if (params === undefined) params = {} // non-bottom field types can do this + var style = params.style || 'font-size: 100%; margin: 0.1em; padding: 0.1em;' + // box.appendChild(dom.createTextNode(' uri='+uri+', pattern='+ params.pattern)) + var field = dom.createElement('input') + rhs.appendChild(field) + field.setAttribute('type', params.type ? params.type : 'text') + + var size = kb.any(form, ui('size')) // Form has precedence + field.setAttribute( + 'size', + size ? '' + size : params.size ? '' + params.size : '20' + ) + var maxLength = kb.any(form, ui('maxLength')) + field.setAttribute('maxLength', maxLength ? '' + maxLength : '4096') + + store = store || forms.fieldStore(subject, property, store) + + var obj = kb.any(subject, property, undefined, store) + if (!obj) { + obj = kb.any(form, ui('default')) + } + if (obj && obj.uri && params.uriPrefix) { + // eg tel: or mailto: + field.value = decodeURIComponent(obj.uri.replace(params.uriPrefix, '')) // should have no spaces but in case + .replace(/ /g, '') + } else if (obj) { + field.value = obj.value || obj.uri || '' + } + field.setAttribute('style', style) + + if (!kb.updater.editable(store.uri)) { + field.disabled = true + return box + } + // read-write: + + field.addEventListener( + 'keyup', + function (_event) { + if (params.pattern) { + field.setAttribute( + 'style', + style + + (field.value.match(params.pattern) + ? 'color: green;' + : 'color: red;') + ) + } + }, + true + ) + field.addEventListener( + 'change', + function (_event) { + // i.e. lose focus with changed data + if (params.pattern && !field.value.match(params.pattern)) return + field.disabled = true // See if this stops getting two dates from fumbling e.g the chrome datepicker. + field.setAttribute('style', style + 'color: gray;') // pending + var ds = kb.statementsMatching(subject, property) // remove any multiple values + var result + if (params.namedNode) { + result = kb.sym(field.value) + } else if (params.uriPrefix) { + result = encodeURIComponent(field.value.replace(/ /g, '')) + result = kb.sym(params.uriPrefix + field.value) + } else { + if (params.dt) { + result = new $rdf.Literal( + field.value.trim(), + undefined, + UI.ns.xsd(params.dt) + ) + } else { + result = new $rdf.Literal(field.value) + } + } + var is = ds.map(st => $rdf.st(st.subject, st.predicate, result, st.why)) // can include >1 doc + if (is.length === 0) { + // or none + is = [$rdf.st(subject, property, result, store)] + } + + function updateMany (ds, is, callback) { + var docs = [] + is.forEach(st => { + if (!docs.includes(st.why.uri)) { + docs.push(st.why.uri) + } + }) + ds.forEach(st => { + if (!docs.includes(st.why.uri)) { + docs.push(st.why.uri) + } + }) + if (docs.length === 0) { + throw new Error('updateMany has no docs to patch') + } + if (docs.length === 1) { + return kb.updater.update(ds, is, callback) + } + console.log('Update many: ' + docs) + const doc = docs.pop() + const is1 = is.filter(st => st.why.uri === doc) + const is2 = is.filter(st => st.why.uri !== doc) + const ds1 = ds.filter(st => st.why.uri === doc) + const ds2 = ds.filter(st => st.why.uri !== doc) + kb.updater.update(ds1, is1, function (uri, ok, body) { + if (ok) { + updateMany(ds2, is2, callback) + } else { + console.log('Update many failed on: ' + doc) + callback(uri, ok, body) + } + }) + } + + updateMany(ds, is, function (uri, ok, body) { + // kb.updater.update(ds, is, function (uri, ok, body) { + if (ok) { + field.disabled = false + field.setAttribute('style', style) + } else { + box.appendChild(error.errorMessageBlock(dom, body)) + } + callbackFunction(ok, body) + }) + }, + true + ) + return box +} /* Multiline Text field -** -*/ + ** + */ forms.field[UI.ns.ui('MultiLineTextField').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { var ui = UI.ns.ui var kb = UI.store var property = kb.any(form, ui('property')) if (!property) { - return error.errorMessageBlock(dom, - 'No property to text field: ' + form) + return error.errorMessageBlock(dom, 'No property to text field: ' + form) } container.appendChild(forms.fieldLabel(dom, property, form)) store = forms.fieldStore(subject, property, store) - var box = forms.makeDescription(dom, kb, subject, property, store, callbackFunction) + var box = forms.makeDescription( + dom, + kb, + subject, + property, + store, + callbackFunction + ) // box.appendChild(dom.createTextNode('<-@@ subj:'+subject+', prop:'+property)) container.appendChild(box) return box } /* Boolean field and Tri-state version (true/false/null) -** -*/ + ** + */ function booleanField ( - dom, container, already, subject, form, store, callbackFunction, tristate) { + dom, + container, + already, + subject, + form, + store, + callbackFunction, + tristate +) { var ui = UI.ns.ui var kb = UI.store var property = kb.any(form, ui('property')) if (!property) { - return container.appendChild(error.errorMessageBlock(dom, - 'No property to boolean field: ' + form)) + return container.appendChild( + error.errorMessageBlock(dom, 'No property to boolean field: ' + form) + ) } var lab = kb.any(form, ui('label')) if (!lab) lab = utils.label(property, true) // Init capital store = forms.fieldStore(subject, property, store) var state = kb.any(subject, property) - if (state === undefined) { state = false } // @@ sure we want that -- or three-state? + if (state === undefined) { + state = false + } // @@ sure we want that -- or three-state? // UI.log.debug('store is '+store) var ins = $rdf.st(subject, property, true, store) var del = $rdf.st(subject, property, false, store) @@ -493,24 +641,64 @@ function booleanField ( return box } forms.field[UI.ns.ui('BooleanField').uri] = function ( - dom, container, already, subject, form, store, callbackFunction, tristate) { - return booleanField(dom, container, already, subject, form, store, callbackFunction, false) + dom, + container, + already, + subject, + form, + store, + callbackFunction, + _tristate +) { + return booleanField( + dom, + container, + already, + subject, + form, + store, + callbackFunction, + false + ) } forms.field[UI.ns.ui('TristateField').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { - return booleanField(dom, container, already, subject, form, store, callbackFunction, true) + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { + return booleanField( + dom, + container, + already, + subject, + form, + store, + callbackFunction, + true + ) } /* Classifier field -** -** Nested categories -** -** @@ To do: If a classification changes, then change any dependent Options fields. -*/ + ** + ** Nested categories + ** + ** @@ To do: If a classification changes, then change any dependent Options fields. + */ forms.field[UI.ns.ui('Classifier').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { var kb = UI.store var ui = UI.ns.ui var category = kb.any(form, ui('category')) @@ -530,25 +718,39 @@ forms.field[UI.ns.ui('Classifier').uri] = function ( */ return callbackFunction(ok, body) } - var box = forms.makeSelectForNestedCategory(dom, kb, subject, category, store, checkOptions) + var box = forms.makeSelectForNestedCategory( + dom, + kb, + subject, + category, + store, + checkOptions + ) container.appendChild(box) return box } /* Choice field -** -** Not nested. Generates a link to something from a given class. -** Optional subform for the thing selected. -** Alternative implementatons caould be: -** -- pop-up menu (as here) -** -- radio buttons -** -- auto-complete typing -** -** Todo: Deal with multiple. Maybe merge with multiple code. -*/ + ** + ** Not nested. Generates a link to something from a given class. + ** Optional subform for the thing selected. + ** Alternative implementatons caould be: + ** -- pop-up menu (as here) + ** -- radio buttons + ** -- auto-complete typing + ** + ** Todo: Deal with multiple. Maybe merge with multiple code. + */ forms.field[UI.ns.ui('Choice').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { + dom, + container, + already, + subject, + form, + store, + callbackFunction +) { var ui = UI.ns.ui var ns = UI.ns var kb = UI.store @@ -573,16 +775,16 @@ forms.field[UI.ns.ui('Choice').uri] = function ( var possible = [] var possibleProperties var np = '--' + utils.label(property) + '-?' - var opts = { 'multiple': multiple, 'nullLabel': np, 'disambiguate': false } + var opts = { multiple: multiple, nullLabel: np, disambiguate: false } possible = kb.each(undefined, ns.rdf('type'), from) for (var x in kb.findMembersNT(from)) { possible.push(kb.fromNT(x)) - // box.appendChild(dom.createTextNode("RDFS: adding "+x)) + // box.appendChild(dom.createTextNode("RDFS: adding "+x)) } // Use rdfs // UI.log.debug("%%% Choice field: possible.length 1 = "+possible.length) if (from.sameTerm(ns.rdfs('Class'))) { for (p in forms.allClassURIs()) possible.push(kb.sym(p)) - // UI.log.debug("%%% Choice field: possible.length 2 = "+possible.length) + // UI.log.debug("%%% Choice field: possible.length 2 = "+possible.length) } else if (from.sameTerm(ns.rdf('Property'))) { possibleProperties = forms.propertyTriage() for (p in possibleProperties.op) possible.push(kb.fromNT(p)) @@ -598,20 +800,34 @@ forms.field[UI.ns.ui('Choice').uri] = function ( opts.disambiguate = true } var object = kb.any(subject, property) - function addSubForm (ok, body) { + function addSubForm (_ok, _body) { object = kb.any(subject, property) - forms.fieldFunction(dom, subForm)(dom, rhs, already, - object, subForm, store, callbackFunction) + forms.fieldFunction(dom, subForm)( + dom, + rhs, + already, + object, + subForm, + store, + callbackFunction + ) } // box.appendChild(dom.createTextNode('Choice: subForm='+subForm)) var possible2 = forms.sortByLabel(possible) if (kb.any(form, ui('canMintNew'))) { - opts['mint'] = '* New *' // @@ could be better - opts['subForm'] = subForm + opts.mint = '* New *' // @@ could be better + opts.subForm = subForm } var selector = forms.makeSelectForOptions( - dom, kb, subject, property, - possible2, opts, store, callbackFunction) + dom, + kb, + subject, + property, + possible2, + opts, + store, + callbackFunction + ) rhs.appendChild(selector) if (object && subForm) addSubForm(true, '') return box @@ -621,34 +837,49 @@ forms.field[UI.ns.ui('Choice').uri] = function ( // forms.fieldParams[UI.ns.ui('Comment').uri] = { - 'element': 'p', - 'style': 'padding: 0.1em 1.5em; color: brown; white-space: pre-wrap;'} + element: 'p', + style: 'padding: 0.1em 1.5em; color: brown; white-space: pre-wrap;' +} forms.fieldParams[UI.ns.ui('Heading').uri] = { - 'element': 'h3', 'style': 'font-size: 110%; color: brown;' } - -forms.field[UI.ns.ui('Comment').uri] = - forms.field[UI.ns.ui('Heading').uri] = function ( - dom, container, already, subject, form, store, callbackFunction) { - var ui = UI.ns.ui - var kb = UI.store - var contents = kb.any(form, ui('contents')) - if (!contents) contents = 'Error: No contents in comment field.' + element: 'h3', + style: 'font-size: 110%; color: brown;' +} - var uri = forms.bottomURI(form) - var params = forms.fieldParams[uri] - if (params === undefined) { params = {} }; // non-bottom field types can do this +forms.field[UI.ns.ui('Comment').uri] = forms.field[ + UI.ns.ui('Heading').uri +] = function ( + dom, + container, + already, + subject, + form, + _store, + _callbackFunction +) { + var ui = UI.ns.ui + var kb = UI.store + var contents = kb.any(form, ui('contents')) + if (!contents) contents = 'Error: No contents in comment field.' - var box = dom.createElement('div') - container.appendChild(box) - var p = box.appendChild(dom.createElement(params['element'])) - p.textContent = contents + var uri = forms.bottomURI(form) + var params = forms.fieldParams[uri] + if (params === undefined) { + params = {} + } // non-bottom field types can do this - var style = kb.any(form, ui('style')) - if (style === undefined) { style = params.style ? params.style : '' } - if (style) p.setAttribute('style', style) + var box = dom.createElement('div') + container.appendChild(box) + var p = box.appendChild(dom.createElement(params.element)) + p.textContent = contents - return box + var style = kb.any(form, ui('style')) + if (style === undefined) { + style = params.style ? params.style : '' } + if (style) p.setAttribute('style', style) + + return box +} /// ////////////// Form-related functions @@ -665,10 +896,15 @@ forms.bottomURI = function (x) { forms.fieldFunction = function (dom, field) { var uri = forms.bottomURI(field) var fun = forms.field[uri] - UI.log.debug('paneUtils: Going to implement field ' + field + ' of type ' + uri) + UI.log.debug( + 'paneUtils: Going to implement field ' + field + ' of type ' + uri + ) if (!fun) { return function () { - return error.errorMessageBlock(dom, 'No handler for field ' + field + ' of type ' + uri) + return error.errorMessageBlock( + dom, + 'No handler for field ' + field + ' of type ' + uri + ) } } return fun @@ -679,23 +915,59 @@ forms.fieldFunction = function (dom, field) { // When editing forms, make it yellow, when editing thr form form, pink // Help people understand how many levels down they are. // -forms.editFormButton = function (dom, container, form, store, callbackFunction) { +forms.editFormButton = function ( + dom, + container, + form, + store, + callbackFunction +) { var b = dom.createElement('button') b.setAttribute('type', 'button') b.innerHTML = 'Edit ' + utils.label(UI.ns.ui('Form')) - b.addEventListener('click', function (e) { - var ff = forms.appendForm(dom, container, - {}, form, UI.ns.ui('FormForm'), store, callbackFunction) - ff.setAttribute('style', UI.ns.ui('FormForm').sameTerm(form) - ? 'background-color: #fee;' : 'background-color: #ffffe7;') - container.removeChild(b) - }, true) + b.addEventListener( + 'click', + function (_event) { + var ff = forms.appendForm( + dom, + container, + {}, + form, + UI.ns.ui('FormForm'), + store, + callbackFunction + ) + ff.setAttribute( + 'style', + UI.ns.ui('FormForm').sameTerm(form) + ? 'background-color: #fee;' + : 'background-color: #ffffe7;' + ) + container.removeChild(b) + }, + true + ) return b } -forms.appendForm = function (dom, container, already, subject, form, store, itemDone) { +forms.appendForm = function ( + dom, + container, + already, + subject, + form, + store, + itemDone +) { return forms.fieldFunction(dom, form)( - dom, container, already, subject, form, store, itemDone) + dom, + container, + already, + subject, + form, + store, + itemDone + ) } // Find list of properties for class @@ -709,17 +981,25 @@ forms.appendForm = function (dom, container, already, subject, form, store, item forms.propertiesForClass = function (kb, c) { var ns = UI.ns var explicit = kb.each(undefined, ns.rdf('range'), c) - ;[ ns.rdfs('comment'), ns.dc('title'), // Generic things - ns.foaf('name'), ns.foaf('homepage')] - .map(function (x) { explicit.push(x) }) + ;[ + ns.rdfs('comment'), + ns.dc('title'), // Generic things + ns.foaf('name'), + ns.foaf('homepage') + ].map(function (x) { + explicit.push(x) + }) var members = kb.each(undefined, ns.rdf('type'), c) if (members.length > 60) members = members.slice(0, 60) // Array supports slice? var used = {} for (var i = 0; i < (members.length > 60 ? 60 : members.length); i++) { - kb.statementsMatching(members[i], undefined, undefined) - .map(function (st) { used[st.predicate.uri] = true }) + kb.statementsMatching(members[i], undefined, undefined).map(function (st) { + used[st.predicate.uri] = true + }) } - explicit.map(function (p) { used[p.uri] = true }) + explicit.map(function (p) { + used[p.uri] = true + }) var result = [] for (var uri in used) { result.push(kb.sym(uri)) @@ -755,14 +1035,20 @@ forms.formsFor = function (subject) { UI.log.debug('formsFor: subject=' + subject) var t = kb.findTypeURIs(subject) var t1 - for (t1 in t) { UI.log.debug(' type: ' + t1) } + for (t1 in t) { + UI.log.debug(' type: ' + t1) + } var bottom = kb.bottomTypeURIs(t) // most specific var candidates = [] for (var b in bottom) { // Find the most specific UI.log.debug('candidatesFor: trying bottom type =' + b) - candidates = candidates.concat(forms.findClosest(kb, b, ns.ui('creationForm'))) - candidates = candidates.concat(forms.findClosest(kb, b, ns.ui('annotationForm'))) + candidates = candidates.concat( + forms.findClosest(kb, b, ns.ui('creationForm')) + ) + candidates = candidates.concat( + forms.findClosest(kb, b, ns.ui('annotationForm')) + ) } return candidates } @@ -772,14 +1058,22 @@ forms.sortBySequence = function (list) { var k = UI.store.any(p, UI.ns.ui('sequence')) return [k || 9999, p] }) - p2.sort(function (a, b) { return a[0] - b[0] }) - return p2.map(function (pair) { return pair[1] }) + p2.sort(function (a, b) { + return a[0] - b[0] + }) + return p2.map(function (pair) { + return pair[1] + }) } forms.sortByLabel = function (list) { - var p2 = list.map(function (p) { return [utils.label(p).toLowerCase(), p] }) + var p2 = list.map(function (p) { + return [utils.label(p).toLowerCase(), p] + }) p2.sort() - return p2.map(function (pair) { return pair[1] }) + return p2.map(function (pair) { + return pair[1] + }) } // Button to add a new whatever using a form @@ -787,14 +1081,37 @@ forms.sortByLabel = function (list) { // @param form - optional form , else will look for one // @param store - optional store else will prompt for one (unimplemented) -forms.newButton = function (dom, kb, subject, predicate, theClass, form, store, callbackFunction) { +forms.newButton = function ( + dom, + kb, + subject, + predicate, + theClass, + form, + store, + callbackFunction +) { var b = dom.createElement('button') b.setAttribute('type', 'button') b.innerHTML = 'New ' + utils.label(theClass) - b.addEventListener('click', function (e) { - b.parentNode.appendChild(forms.promptForNew( - dom, kb, subject, predicate, theClass, form, store, callbackFunction)) - }, false) + b.addEventListener( + 'click', + function (_event) { + b.parentNode.appendChild( + forms.promptForNew( + dom, + kb, + subject, + predicate, + theClass, + form, + store, + callbackFunction + ) + ) + }, + false + ) return b } @@ -811,7 +1128,16 @@ forms.newButton = function (dom, kb, subject, predicate, theClass, form, store, // @param callbackFunction - takes (boolean ok, string errorBody) // @returns a dom object with the form DOM -forms.promptForNew = function (dom, kb, subject, predicate, theClass, form, store, callbackFunction) { +forms.promptForNew = function ( + dom, + kb, + subject, + predicate, + theClass, + form, + store, + callbackFunction +) { var ns = UI.ns var box = dom.createElement('form') @@ -819,15 +1145,27 @@ forms.promptForNew = function (dom, kb, subject, predicate, theClass, form, stor var lists = forms.findClosest(kb, theClass.uri, ns.ui('creationForm')) if (lists.length === 0) { var p = box.appendChild(dom.createElement('p')) - p.textContent = 'I am sorry, you need to provide information about a ' + - utils.label(theClass) + " but I don't know enough information about those to ask you." + p.textContent = + 'I am sorry, you need to provide information about a ' + + utils.label(theClass) + + " but I don't know enough information about those to ask you." var b = box.appendChild(dom.createElement('button')) b.setAttribute('type', 'button') b.setAttribute('style', 'float: right;') b.innerHTML = 'Goto ' + utils.label(theClass) - b.addEventListener('click', function (e) { - dom.outlineManager.GotoSubject(theClass, true, undefined, true, undefined) - }, false) + b.addEventListener( + 'click', + function (_event) { + dom.outlineManager.GotoSubject( + theClass, + true, + undefined, + true, + undefined + ) + }, + false + ) return box } UI.log.debug('lists[0] is ' + lists[0]) @@ -855,10 +1193,9 @@ forms.promptForNew = function (dom, kb, subject, predicate, theClass, form, stor callbackFunction(true, body) } if (!gotButton) { - gotButton = box.appendChild( - forms.linkButton(dom, object)) + gotButton = box.appendChild(forms.linkButton(dom, object)) } - // tabulator.outline.GotoSubject(object, true, undefined, true, undefined) + // tabulator.outline.GotoSubject(object, true, undefined, true, undefined) } var linkDone = function (uri, ok, body) { return callbackFunction(ok, body) @@ -871,13 +1208,22 @@ forms.promptForNew = function (dom, kb, subject, predicate, theClass, form, stor return box } -forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFunction) { +forms.makeDescription = function ( + dom, + kb, + subject, + predicate, + store, + callbackFunction +) { var group = dom.createElement('div') var sts = kb.statementsMatching(subject, predicate, undefined) // Only one please if (sts.length > 1) { - return error.errorMessageBlock(dom, - 'Should not be ' + sts.length + ' i.e. >1 ' + predicate + ' of ' + subject) + return error.errorMessageBlock( + dom, + 'Should not be ' + sts.length + ' i.e. >1 ' + predicate + ' of ' + subject + ) } var desc = sts.length ? sts[0].object.value : undefined @@ -885,7 +1231,8 @@ forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFu group.appendChild(field) field.rows = desc ? desc.split('\n').length + 2 : 2 field.cols = 80 - var style = 'font-size:100%; white-space: pre-wrap; background-color: white;' + + var style = + 'font-size:100%; white-space: pre-wrap; background-color: white;' + ' border: 0.07em solid gray; padding: 1em 0.5em; margin: 1em 1em;' field.setAttribute('style', style) if (sts.length) { @@ -898,12 +1245,12 @@ forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFu group.refresh = function () { var v = kb.any(subject, predicate) - if (v && (v.value !== field.value)) { + if (v && v.value !== field.value) { field.value = v.value // don't touch widget if no change - // @@ this is the place to color the field from the user who chanaged it + // @@ this is the place to color the field from the user who chanaged it } } - function saveChange (e) { + function saveChange (_event) { submit.disabled = true submit.setAttribute('style', 'visibility: hidden; float: right;') // Keep UI clean field.disabled = true @@ -915,10 +1262,16 @@ forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFu field.setAttribute('style', style + 'color: black;') field.disabled = false } else { - group.appendChild(error.errorMessageBlock(dom, - 'Error (while saving change to ' + store.uri + '): ' + body)) + group.appendChild( + error.errorMessageBlock( + dom, + 'Error (while saving change to ' + store.uri + '): ' + body + ) + ) + } + if (callbackFunction) { + callbackFunction(ok, body) } - if (callbackFunction) { callbackFunction(ok, body) } }) } @@ -934,13 +1287,18 @@ forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFu submit.value = 'Save ' + utils.label(predicate) // @@ I18n group.appendChild(submit) - field.addEventListener('keyup', function (e) { // Green means has been changed, not saved yet - field.setAttribute('style', style + 'color: green;') - if (submit) { - submit.disabled = false - submit.setAttribute('style', 'float: right;') // Remove visibility: hidden - } - }, true) + field.addEventListener( + 'keyup', + function (_event) { + // Green means has been changed, not saved yet + field.setAttribute('style', style + 'color: green;') + if (submit) { + submit.disabled = false + submit.setAttribute('style', 'float: right;') // Remove visibility: hidden + } + }, + true + ) field.addEventListener('change', saveChange, true) submit.addEventListener('click', saveChange, false) } else { @@ -962,8 +1320,16 @@ forms.makeDescription = function (dom, kb, subject, predicate, store, callbackFu // @param store - The web document being edited // @param callbackFunction - takes (boolean ok, string errorBody) -forms.makeSelectForOptions = function (dom, kb, subject, predicate, - possible, options, store, callbackFunction) { +forms.makeSelectForOptions = function ( + dom, + kb, + subject, + predicate, + possible, + options, + store, + callbackFunction +) { UI.log.debug('Select list length now ' + possible.length) var n = 0 var uris = {} // Count them @@ -973,11 +1339,18 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, var sub = possible[i] // UI.log.debug('Select element: '+ sub) if (sub.uri in uris) continue - uris[sub.uri] = true; n++ + uris[sub.uri] = true + n++ } // uris is now the set of possible options if (n === 0 && !options.mint) { - return error.errorMessageBlock(dom, - "Can't do selector with no options, subject= " + subject + ' property = ' + predicate + '.') + return error.errorMessageBlock( + dom, + "Can't do selector with no options, subject= " + + subject + + ' property = ' + + predicate + + '.' + ) } UI.log.debug('makeSelectForOptions: store=' + store) @@ -986,7 +1359,9 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, if (predicate.sameTerm(UI.ns.rdf('type'))) { actual = kb.findTypeURIs(subject) } else { - kb.each(subject, predicate).map(function (x) { actual[x.uri] = true }) + kb.each(subject, predicate).map(function (x) { + actual[x.uri] = true + }) } return actual } @@ -994,7 +1369,7 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, // var newObject = null - var onChange = function (e) { + var onChange = function (_event) { select.disabled = true // until data written back - gives user feedback too var ds = [] var is = [] @@ -1008,26 +1383,39 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, if (opt.selected && opt.AJAR_mint) { var newObject if (options.mintClass) { - var thisForm = forms.promptForNew(dom, kb, subject, predicate, options.mintClass, null, store, function (ok, body) { - if (!ok) { - callbackFunction(ok, body) // @@ if ok, need some form of refresh of the select for the new thing + var thisForm = forms.promptForNew( + dom, + kb, + subject, + predicate, + options.mintClass, + null, + store, + function (ok, body) { + if (!ok) { + callbackFunction(ok, body) // @@ if ok, need some form of refresh of the select for the new thing + } } - }) + ) select.parentNode.appendChild(thisForm) newObject = thisForm.AJAR_subject } else { newObject = forms.newThing(store) } is.push($rdf.st(subject, predicate, newObject, store)) - if (options.mintStatementsFun) is = is.concat(options.mintStatementsFun(newObject)) + if (options.mintStatementsFun) { + is = is.concat(options.mintStatementsFun(newObject)) + } } if (!opt.AJAR_uri) continue // a prompt or mint - if (opt.selected && !(opt.AJAR_uri in actual)) { // new class + if (opt.selected && !(opt.AJAR_uri in actual)) { + // new class is.push($rdf.st(subject, predicate, kb.sym(opt.AJAR_uri), store)) } - if (!opt.selected && opt.AJAR_uri in actual) { // old class + if (!opt.selected && opt.AJAR_uri in actual) { + // old class removeValue(kb.sym(opt.AJAR_uri)) - // ds.push($rdf.st(subject, predicate, kb.sym(opt.AJAR_uri), store )) + // ds.push($rdf.st(subject, predicate, kb.sym(opt.AJAR_uri), store )) } if (opt.selected) select.currentURI = opt.AJAR_uri } @@ -1045,19 +1433,26 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, callbackFunction(ok, body) } UI.log.info('selectForOptions: stote = ' + store) - UI.store.updater.update(ds, is, - function (uri, ok, body) { - actual = getActual() // refresh - // kb.each(subject, predicate).map(function(x){actual[x.uri] = true}) - if (ok) { - select.disabled = false // data written back - if (newObject) { - var fn = forms.fieldFunction(dom, options.subForm) - fn(dom, select.parentNode, {}, newObject, options.subForm, store, doneNew) - } + UI.store.updater.update(ds, is, function (uri, ok, body) { + actual = getActual() // refresh + // kb.each(subject, predicate).map(function(x){actual[x.uri] = true}) + if (ok) { + select.disabled = false // data written back + if (newObject) { + var fn = forms.fieldFunction(dom, options.subForm) + fn( + dom, + select.parentNode, + {}, + newObject, + options.subForm, + store, + doneNew + ) } - if (callbackFunction) callbackFunction(ok, body) - }) + } + if (callbackFunction) callbackFunction(ok, body) + }) } var select = dom.createElement('select') @@ -1070,7 +1465,7 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, for (var i = 0; i < select.children.length; i++) { var option = select.children[i] if (option.AJAR_uri) { - option.selected = (option.AJAR_uri in actual) + option.selected = option.AJAR_uri in actual } } select.disabled = false // unlocked any conflict we had got into @@ -1084,13 +1479,21 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, } else { option.appendChild(dom.createTextNode(utils.label(c, true))) // Init. } - var backgroundColor = kb.any(c, kb.sym('http://www.w3.org/ns/ui#backgroundColor')) - if (backgroundColor) option.setAttribute('style', 'background-color: ' + backgroundColor.value + '; ') + var backgroundColor = kb.any( + c, + kb.sym('http://www.w3.org/ns/ui#backgroundColor') + ) + if (backgroundColor) { + option.setAttribute( + 'style', + 'background-color: ' + backgroundColor.value + '; ' + ) + } option.AJAR_uri = uri if (uri in actual) { option.setAttribute('selected', 'true') select.currentURI = uri - // dump("Already in class: "+ uri+"\n") + // dump("Already in class: "+ uri+"\n") } select.appendChild(option) } @@ -1100,7 +1503,7 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, mint.AJAR_mint = true // Flag it select.insertBefore(mint, select.firstChild) } - if ((select.currentURI == null) && !options.multiple) { + if (select.currentURI == null && !options.multiple) { var prompt = dom.createElement('option') prompt.appendChild(dom.createTextNode(options.nullLabel)) select.insertBefore(prompt, select.firstChild) @@ -1118,7 +1521,14 @@ forms.makeSelectForOptions = function (dom, kb, subject, predicate, // Failing that it will do a multiple selection of subclasses. // Callback takes (boolean ok, string errorBody) -forms.makeSelectForCategory = function (dom, kb, subject, category, store, callbackFunction) { +forms.makeSelectForCategory = function ( + dom, + kb, + subject, + category, + store, + callbackFunction +) { var log = UI.log var du = kb.any(category, UI.ns.owl('disjointUnionOf')) var subs @@ -1131,16 +1541,35 @@ forms.makeSelectForCategory = function (dom, kb, subject, category, store, callb } log.debug('Select list length ' + subs.length) if (subs.length === 0) { - return error.errorMessageBlock(dom, - "Can't do " + (multiple ? 'multiple ' : '') + 'selector with no subclasses of category: ' + category) + return error.errorMessageBlock( + dom, + "Can't do " + + (multiple ? 'multiple ' : '') + + 'selector with no subclasses of category: ' + + category + ) } if (subs.length === 1) { - return error.errorMessageBlock(dom, - "Can't do " + (multiple ? 'multiple ' : '') + - 'selector with only 1 subclass of category: ' + category + ':' + subs[1]) + return error.errorMessageBlock( + dom, + "Can't do " + + (multiple ? 'multiple ' : '') + + 'selector with only 1 subclass of category: ' + + category + + ':' + + subs[1] + ) } - return forms.makeSelectForOptions(dom, kb, subject, UI.ns.rdf('type'), subs, - { 'multiple': multiple, 'nullPrompt': '--classify--' }, store, callbackFunction) + return forms.makeSelectForOptions( + dom, + kb, + subject, + UI.ns.rdf('type'), + subs, + { multiple: multiple, nullPrompt: '--classify--' }, + store, + callbackFunction + ) } // Make SELECT element to select subclasses recurively @@ -1150,7 +1579,13 @@ forms.makeSelectForCategory = function (dom, kb, subject, category, store, callb // Callback takes (boolean ok, string errorBody) forms.makeSelectForNestedCategory = function ( - dom, kb, subject, category, store, callbackFunction) { + dom, + kb, + subject, + category, + store, + callbackFunction +) { var container = dom.createElement('span') // Container var child = null var select @@ -1159,7 +1594,13 @@ forms.makeSelectForNestedCategory = function ( callbackFunction(ok, body) } select = forms.makeSelectForCategory( - dom, kb, subject, category, store, onChange) + dom, + kb, + subject, + category, + store, + onChange + ) container.appendChild(select) var update = function () { // UI.log.info("Selected is now: "+select.currentURI) @@ -1167,9 +1608,18 @@ forms.makeSelectForNestedCategory = function ( container.removeChild(child) child = null } - if (select.currentURI && kb.any(kb.sym(select.currentURI), UI.ns.owl('disjointUnionOf'))) { + if ( + select.currentURI && + kb.any(kb.sym(select.currentURI), UI.ns.owl('disjointUnionOf')) + ) { child = forms.makeSelectForNestedCategory( - dom, kb, subject, kb.sym(select.currentURI), store, callbackFunction) + dom, + kb, + subject, + kb.sym(select.currentURI), + store, + callbackFunction + ) select.subSelect = child.firstChild select.subSelect.superSelect = select container.appendChild(child) @@ -1180,23 +1630,28 @@ forms.makeSelectForNestedCategory = function ( } /* Build a checkbox from a given statement(s) -** -** If the source document is editable, make the checkbox editable -** -** ins and sel are either statements *or arrays of statements* which should be -** made if the checkbox is checed and unchecked respectively. -** tristate: Allow ins, or del, or neither -*/ -function buildCheckboxForm (dom, kb, lab, del, ins, form, store, tristate) { // 20190115 + ** + ** If the source document is editable, make the checkbox editable + ** + ** ins and sel are either statements *or arrays of statements* which should be + ** made if the checkbox is checed and unchecked respectively. + ** tristate: Allow ins, or del, or neither + */ +function buildCheckboxForm (dom, kb, lab, del, ins, form, store, tristate) { + // 20190115 var box = dom.createElement('div') var tx = dom.createTextNode(lab) var editable = UI.store.updater.editable(store.uri) - tx.style = 'colour: black; font-size: 100%; padding-left: 0.5 em; padding-right: 0.5 em;' + tx.style = + 'colour: black; font-size: 100%; padding-left: 0.5 em; padding-right: 0.5 em;' box.appendChild(tx) var input input = dom.createElement('button') - input.setAttribute('style', 'font-size: 150%; height: 1.2em; width: 1.2em; background-color: #eef; margin: 0.1em') + input.setAttribute( + 'style', + 'font-size: 150%; height: 1.2em; width: 1.2em; background-color: #eef; margin: 0.1em' + ) box.appendChild(input) function fix (x) { @@ -1205,7 +1660,7 @@ function buildCheckboxForm (dom, kb, lab, del, ins, form, store, tristate) { // if (!x.why) { x.why = store // be back-compaitible with old code } - return [ x ] // one statements + return [x] // one statements } if (x instanceof Array) return x throw new Error('buildCheckboxForm: bad param ' + x) @@ -1214,7 +1669,9 @@ function buildCheckboxForm (dom, kb, lab, del, ins, form, store, tristate) { // del = fix(del) function holdsAll (a) { - let missing = a.filter(st => !kb.holds(st.subject, st.predicate, st.object, st.why)) + const missing = a.filter( + st => !kb.holds(st.subject, st.predicate, st.object, st.why) + ) return missing.length === 0 } function refresh () { @@ -1223,45 +1680,78 @@ function buildCheckboxForm (dom, kb, lab, del, ins, form, store, tristate) { // if (del.length) { var negation = holdsAll(del) if (state && negation) { - box.appendChild(UI.widgets.errorMessageBlock(dom, - 'Inconsistent data in store!\n' + ins + ' and\n' + del)) + box.appendChild( + UI.widgets.errorMessageBlock( + dom, + 'Inconsistent data in store!\n' + ins + ' and\n' + del + ) + ) return box } if (!state && !negation) { state = null - let defa = kb.any(form, UI.ns.ui('default')) + const defa = kb.any(form, UI.ns.ui('default')) displayState = defa ? defa.value === '1' : tristate ? null : false } } input.state = state - input.textContent = {true: checkMarkCharacter, false: cancelCharacter, null: dashCharacter}[displayState] + input.textContent = { + true: checkMarkCharacter, + false: cancelCharacter, + null: dashCharacter + }[displayState] } refresh() if (!editable) return box - var boxHandler = function (e) { + var boxHandler = function (_event) { tx.style = 'color: #bbb;' // grey -- not saved yet - var toDelete = (input.state === true ? ins : input.state === false ? del : []) - input.newState = input.state === null ? true : input.state === true ? false : tristate ? null : true - var toInsert = (input.newState === true ? ins : input.newState === false ? del : []) + var toDelete = input.state === true ? ins : input.state === false ? del : [] + + function getState (input, tristate) { + return input.state === true ? false : tristate ? null : true + } + + input.newState = input.state === null ? true : getState(input, tristate) + var toInsert = + input.newState === true ? ins : input.newState === false ? del : [] console.log(` Deleting ${toDelete}`) console.log(` Inserting ${toInsert}`) - UI.store.updater.update(toDelete, toInsert, function (uri, success, errorBody) { + UI.store.updater.update(toDelete, toInsert, function ( + uri, + success, + errorBody + ) { if (!success) { if (toDelete.why) { - var hmmm = kb.holds(toDelete.subject, toDelete.predicate, toDelete.object, toDelete.why) + var hmmm = kb.holds( + toDelete.subject, + toDelete.predicate, + toDelete.object, + toDelete.why + ) if (hmmm) { console.log(' @@@@@ weird if 409 - does hold statement') } } tx.style = 'color: #black; background-color: #fee;' - box.appendChild(error.errorMessageBlock(dom, - `Checkbox: Error updating store from ${input.state} to ${input.newState}:\n\n${errorBody}`)) + box.appendChild( + error.errorMessageBlock( + dom, + `Checkbox: Error updating store from ${input.state} to ${ + input.newState + }:\n\n${errorBody}` + ) + ) } else { tx.style = 'color: #black;' input.state = input.newState - input.textContent = {true: checkMarkCharacter, false: cancelCharacter, null: dashCharacter}[input.state] // @@ + input.textContent = { + true: checkMarkCharacter, + false: cancelCharacter, + null: dashCharacter + }[input.state] // @@ } }) } @@ -1273,7 +1763,9 @@ forms.buildCheckboxForm = buildCheckboxForm forms.fieldLabel = function (dom, property, form) { var lab = UI.store.any(form, UI.ns.ui('label')) if (!lab) lab = utils.label(property, true) // Init capital - if (property === undefined) { return dom.createTextNode('@@Internal error: undefined property') } + if (property === undefined) { + return dom.createTextNode('@@Internal error: undefined property') + } var anchor = dom.createElement('a') if (property.uri) anchor.setAttribute('href', property.uri) anchor.setAttribute('style', 'color: #3B5998; text-decoration: none;') // Not too blue and no underline @@ -1284,7 +1776,11 @@ forms.fieldLabel = function (dom, property, form) { forms.fieldStore = function (subject, predicate, def) { var sts = UI.store.statementsMatching(subject, predicate) if (sts.length === 0) return def // can used default as no data yet - if (sts.length > 0 && sts[0].why.uri && UI.store.updater.editable(sts[0].why.uri, UI.store)) { + if ( + sts.length > 0 && + sts[0].why.uri && + UI.store.updater.editable(sts[0].why.uri, UI.store) + ) { return UI.store.sym(sts[0].why.uri) } return def diff --git a/src/widgets/index.js b/src/widgets/index.js index 7e1e9b1d5..bbf6ca95d 100644 --- a/src/widgets/index.js +++ b/src/widgets/index.js @@ -1,14 +1,14 @@ /** -* General purpose utility functions used in the panes -* oshani@csail.mit.edu -* -* Includes form-oriented widgets timbl@w3.org -* -* sign-in sign-up widgets are in signin.js -* -* Note... For pointers to posssible text-editing code, see -* http://stackoverflow.com/questions/6756407/what-contenteditable-editors -*/ + * General purpose utility functions used in the panes + * oshani@csail.mit.edu + * + * Includes form-oriented widgets timbl@w3.org + * + * sign-in sign-up widgets are in signin.js + * + * Note... For pointers to posssible text-editing code, see + * http://stackoverflow.com/questions/6756407/what-contenteditable-editors + */ // var aclModule = require('./acl.js') @@ -20,9 +20,9 @@ // export widgets with the same name) var widgets = Object.assign( {}, - {PeoplePicker: require('./peoplePicker')}, - require('./dragAndDrop'), // uploadFiles etc - require('./error'), // UI.widgets.errorMessageBlock + { PeoplePicker: require('./peoplePicker') }, + require('./dragAndDrop'), // uploadFiles etc + require('./error'), // UI.widgets.errorMessageBlock require('./buttons'), require('./forms') ) diff --git a/src/widgets/peoplePicker.js b/src/widgets/peoplePicker.js index 99f7eba65..dbcf1aa01 100644 --- a/src/widgets/peoplePicker.js +++ b/src/widgets/peoplePicker.js @@ -43,7 +43,7 @@ export class PeoplePicker { new Group(selectedGroup, this.selectedgroup).render() const changeGroupButton = document.createElement('button') changeGroupButton.textContent = escape('Change group') - changeGroupButton.addEventListener('click', event => { + changeGroupButton.addEventListener('click', _event => { this.selectedgroup = null this.render() }) @@ -51,20 +51,22 @@ export class PeoplePicker { container.appendChild(changeGroupButton) } else { this.findAddressBook(this.typeIndex) - .then(({book}) => { + .then(({ book }) => { const chooseExistingGroupButton = document.createElement('button') - chooseExistingGroupButton.textContent = escape('Pick an existing group') + chooseExistingGroupButton.textContent = escape( + 'Pick an existing group' + ) chooseExistingGroupButton.style.margin = 'auto' - chooseExistingGroupButton.addEventListener('click', event => { + chooseExistingGroupButton.addEventListener('click', _event => { new GroupPicker(container, book, this.onSelectGroup).render() }) const createNewGroupButton = document.createElement('button') createNewGroupButton.textContent = escape('Create a new group') createNewGroupButton.style.margin = 'auto' - createNewGroupButton.addEventListener('click', event => { + createNewGroupButton.addEventListener('click', _event => { this.createNewGroup(book) - .then(({group}) => { + .then(({ group }) => { new GroupBuilder( this.element, book, @@ -74,7 +76,10 @@ export class PeoplePicker { }) .catch(errorBody => { this.element.appendChild( - errorMessageBlock(document, escape(`Error creating a new group. (${errorBody})`)) + errorMessageBlock( + document, + escape(`Error creating a new group. (${errorBody})`) + ) ) }) }) @@ -87,7 +92,10 @@ export class PeoplePicker { }) .catch(err => { this.element.appendChild( - errorMessageBlock(document, escape(`Could find your groups. (${err})`)) + errorMessageBlock( + document, + escape(`Could find your groups. (${err})`) + ) ) }) } @@ -103,51 +111,82 @@ export class PeoplePicker { if (!ok) { return reject(err) } - const bookRegistration = kb.any(null, ns.solid('forClass'), ns.vcard('AddressBook')) + const bookRegistration = kb.any( + null, + ns.solid('forClass'), + ns.vcard('AddressBook') + ) if (!bookRegistration) { - return reject(new Error('no address book registered in the solid type index ' + typeIndex)) + return reject( + new Error( + 'no address book registered in the solid type index ' + typeIndex + ) + ) } const book = kb.any(bookRegistration, ns.solid('instance')) if (!book) { return reject(new Error('incomplete address book registration')) } - kb.fetcher.load(book).then(function (xhr) { - return resolve({book}) - }).catch(function (err) { - return reject(new Error('Could not load address book ' + err)) - }) + kb.fetcher + .load(book) + .then(function (_xhr) { + return resolve({ book }) + }) + .catch(function (err) { + return reject(new Error('Could not load address book ' + err)) + }) }) }) } createNewGroup (book) { - const {groupIndex, groupContainer} = indexes(book) - const group = rdf.sym(`${groupContainer.uri}${uuid.v4().slice(0, 8)}.ttl#this`) + const { groupIndex, groupContainer } = indexes(book) + const group = rdf.sym( + `${groupContainer.uri}${uuid.v4().slice(0, 8)}.ttl#this` + ) const name = this.options.defaultNewGroupName || 'Untitled Group' // NOTE that order matters here. Unfortunately this type of update is // non-atomic in that solid requires us to send two PATCHes, either of which // might fail. - const patchPromises = [group.doc(), groupIndex] - .map(doc => { - const typeStatement = rdf.st(group, ns.rdf('type'), ns.vcard('Group'), doc) - const nameStatement = rdf.st(group, ns.vcard('fn'), name, group.doc(), doc) - const includesGroupStatement = rdf.st(book, ns.vcard('includesGroup'), group, doc) - const toIns = doc.equals(groupIndex) - ? [typeStatement, nameStatement, includesGroupStatement] - : [typeStatement, nameStatement] - return patch(doc.uri, {toIns}) - .then(() => { - toIns.forEach(st => { - kb.add(st) - }) - }) + const patchPromises = [group.doc(), groupIndex].map(doc => { + const typeStatement = rdf.st( + group, + ns.rdf('type'), + ns.vcard('Group'), + doc + ) + const nameStatement = rdf.st( + group, + ns.vcard('fn'), + name, + group.doc(), + doc + ) + const includesGroupStatement = rdf.st( + book, + ns.vcard('includesGroup'), + group, + doc + ) + const toIns = doc.equals(groupIndex) + ? [typeStatement, nameStatement, includesGroupStatement] + : [typeStatement, nameStatement] + return patch(doc.uri, { toIns }).then(() => { + toIns.forEach(st => { + kb.add(st) + }) }) + }) return Promise.all(patchPromises) - .then(() => ({group})) + .then(() => ({ group })) .catch(err => { console.log('Could not create new group. PATCH failed ' + err) - throw new Error(`Couldn't create new group. PATCH failed for (${err.xhr ? err.xhr.responseURL : ''} )`) + throw new Error( + `Couldn't create new group. PATCH failed for (${ + err.xhr ? err.xhr.responseURL : '' + } )` + ) }) } @@ -183,7 +222,10 @@ export class GroupPicker { }) .catch(err => { this.element.appendChild( - errorMessageBlock(document, escape(`There was an error loading your groups. (${err})`)) + errorMessageBlock( + document, + escape(`There was an error loading your groups. (${err})`) + ) ) }) return this @@ -191,7 +233,7 @@ export class GroupPicker { loadGroups () { return new Promise((resolve, reject) => { - const {groupIndex} = indexes(this.book) + const { groupIndex } = indexes(this.book) kb.fetcher.nowOrWhenFetched(groupIndex, (ok, err) => { if (!ok) { return reject(err) @@ -203,7 +245,7 @@ export class GroupPicker { } handleClickGroup (group) { - return event => { + return _event => { this.onSelectGroup(group) } } @@ -217,7 +259,8 @@ export class Group { render () { const container = document.createElement('div') - container.textContent = escape( // @@@@@ need to escape?? + container.textContent = escape( + // @@@@@ need to escape?? getWithDefault(this.group, ns.vcard('fn'), `[${this.group.value}]`) ) this.element.innerHTML = '' @@ -254,25 +297,30 @@ export class GroupBuilder { makeDropTarget(dropContainer, uris => { uris.map(uri => { - this.add(uri) - .catch(err => { - this.element.appendChild( - errorMessageBlock(document, escape(`Could not add the given WebId. (${err})`)) + this.add(uri).catch(err => { + this.element.appendChild( + errorMessageBlock( + document, + escape(`Could not add the given WebId. (${err})`) ) - }) + ) + }) }) }) const groupNameInput = document.createElement('input') groupNameInput.type = 'text' - groupNameInput.value = getWithDefault(this.group, ns.vcard('fn'), 'Untitled Group') + groupNameInput.value = getWithDefault( + this.group, + ns.vcard('fn'), + 'Untitled Group' + ) groupNameInput.addEventListener('change', event => { - this.setGroupName(event.target.value) - .catch(err => { - this.element.appendChild( - errorMessageBlock(document, `Error changing group name. (${err})`) - ) - }) + this.setGroupName(event.target.value).catch(err => { + this.element.appendChild( + errorMessageBlock(document, `Error changing group name. (${err})`) + ) + }) }) const groupNameLabel = document.createElement('label') groupNameLabel.textContent = escape('Group Name:') @@ -280,13 +328,12 @@ export class GroupBuilder { dropContainer.appendChild(groupNameLabel) if (kb.any(this.group, ns.vcard('hasMember'))) { - kb.match(this.group, ns.vcard('hasMember')) - .forEach(statement => { - const webIdNode = statement.object - const personDiv = document.createElement('div') - new Person(personDiv, webIdNode, this.handleRemove(webIdNode)).render() - dropContainer.appendChild(personDiv) - }) + kb.match(this.group, ns.vcard('hasMember')).forEach(statement => { + const webIdNode = statement.object + const personDiv = document.createElement('div') + new Person(personDiv, webIdNode, this.handleRemove(webIdNode)).render() + dropContainer.appendChild(personDiv) + }) } else { const copy = document.createElement('p') copy.textContent = escape` @@ -297,7 +344,7 @@ export class GroupBuilder { const doneBuildingButton = document.createElement('button') doneBuildingButton.textContent = escape('Done') - doneBuildingButton.addEventListener('click', event => { + doneBuildingButton.addEventListener('click', _event => { this.doneBuildingCb(this.group) }) dropContainer.appendChild(doneBuildingButton) @@ -319,7 +366,13 @@ export class GroupBuilder { const webIdNode = rdf.namedNode(webId) const rdfClass = kb.any(webIdNode, ns.rdf('type')) if (!rdfClass || !rdfClass.equals(ns.foaf('Person'))) { - return reject(new Error(`Only people supported right now. (tried to add something of type ${rdfClass.value})`)) + return reject( + new Error( + `Only people supported right now. (tried to add something of type ${ + rdfClass.value + })` + ) + ) } return resolve(webIdNode) }) @@ -328,20 +381,19 @@ export class GroupBuilder { if (kb.holdsStatement(statement)) { return webIdNode } - return patch(this.group.doc().uri, {toIns: [statement]}) - .then(() => { - statement.why = this.group.doc() - kb.add(statement) - this.onGroupChanged(null, 'added', webIdNode) - this.render() - }) + return patch(this.group.doc().uri, { toIns: [statement] }).then(() => { + statement.why = this.group.doc() + kb.add(statement) + this.onGroupChanged(null, 'added', webIdNode) + this.render() + }) }) } handleRemove (webIdNode) { - return event => { + return _event => { const statement = rdf.st(this.group, ns.vcard('hasMember'), webIdNode) - return patch(this.group.doc().uri, {toDel: [statement]}) + return patch(this.group.doc().uri, { toDel: [statement] }) .then(() => { kb.remove(statement) this.onGroupChanged(null, 'removed', webIdNode) @@ -350,27 +402,38 @@ export class GroupBuilder { }) .catch(err => { const name = kb.any(webIdNode, ns.foaf('name')) - const errorMessage = name && name.value - ? `Could not remove ${name.value}. (${err})` - : `Could not remove ${webIdNode.value}. (${err})` + const errorMessage = + name && name.value + ? `Could not remove ${name.value}. (${err})` + : `Could not remove ${webIdNode.value}. (${err})` throw new Error(errorMessage) }) } } setGroupName (name) { - const {groupIndex} = indexes(this.book) - const updatePromises = [this.group.doc(), groupIndex] - .map(namedGraph => { - const oldNameStatements = kb.match(this.group, ns.vcard('fn'), null, namedGraph) - const newNameStatement = rdf.st(this.group, ns.vcard('fn'), rdf.literal(name)) - return patch(namedGraph.value, {toDel: oldNameStatements, toIns: [newNameStatement]}) - .then(solidResponse => { - kb.removeStatements(oldNameStatements) - newNameStatement.why = namedGraph - kb.add(newNameStatement) - }) + const { groupIndex } = indexes(this.book) + const updatePromises = [this.group.doc(), groupIndex].map(namedGraph => { + const oldNameStatements = kb.match( + this.group, + ns.vcard('fn'), + null, + namedGraph + ) + const newNameStatement = rdf.st( + this.group, + ns.vcard('fn'), + rdf.literal(name) + ) + return patch(namedGraph.value, { + toDel: oldNameStatements, + toIns: [newNameStatement] + }).then(_solidResponse => { + kb.removeStatements(oldNameStatements) + newNameStatement.why = namedGraph + kb.add(newNameStatement) }) + }) return Promise.all(updatePromises) } } @@ -387,7 +450,11 @@ class Person { container.style.display = 'flex' // TODO: take a look at UI.widgets.setName - const imgSrc = getWithDefault(this.webIdNode, ns.foaf('img'), iconBase + 'noun_15059.svg') + const imgSrc = getWithDefault( + this.webIdNode, + ns.foaf('img'), + iconBase + 'noun_15059.svg' + ) const profileImg = document.createElement('img') profileImg.src = escape(imgSrc) profileImg.width = '50' @@ -395,7 +462,11 @@ class Person { profileImg.style.margin = '5px' // TODO: take a look at UI.widgets.setImage - const name = getWithDefault(this.webIdNode, ns.foaf('name'), `[${this.webIdNode}]`) + const name = getWithDefault( + this.webIdNode, + ns.foaf('name'), + `[${this.webIdNode}]` + ) const nameSpan = document.createElement('span') nameSpan.innerHTML = escape(name) nameSpan.style.flexGrow = '1' @@ -403,11 +474,11 @@ class Person { const removeButton = document.createElement('button') removeButton.textContent = 'Remove' - removeButton.addEventListener('click', event => this.handleRemove().catch(err => { - this.element.appendChild( - errorMessageBlock(document, escape(`${err}`)) - ) - })) + removeButton.addEventListener('click', _event => + this.handleRemove().catch(err => { + this.element.appendChild(errorMessageBlock(document, escape(`${err}`))) + }) + ) removeButton.style.margin = '5px' container.appendChild(profileImg) @@ -425,11 +496,13 @@ function getWithDefault (subject, predicate, defaultValue) { return object ? object.value : defaultValue } -function patch (url, {toDel, toIns}) { +function patch (url, { toDel, toIns }) { return new Promise((resolve, reject) => { kb.updater.update(toDel, toIns, (uri, success, errorMessage) => { if (!success) { - return reject(new Error(`PATCH failed for resource <${uri}>: ${errorMessage}`)) + return reject( + new Error(`PATCH failed for resource <${uri}>: ${errorMessage}`) + ) } resolve() }) diff --git a/tsconfig.json b/tsconfig.json index 4f7b6e8e5..bd2b2a4d9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,20 @@ { "compilerOptions": { /* Basic Options */ - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - "lib": ["dom", "es2015"], /* Specify library files to be included in the compilation. */ + "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, + "lib": [ + "dom", + "es2015" + ] /* Specify library files to be included in the compilation. */, // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */, + "sourceMap": true /* Generates corresponding '.map' file. */, // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "lib", /* Redirect output structure to the directory. */ + "outDir": "lib" /* Redirect output structure to the directory. */, // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "incremental": true, /* Enable incremental compilation */ @@ -23,7 +26,7 @@ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ @@ -44,9 +47,11 @@ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ + "typeRoots": [ + "node_modules/@types" + ] /* List of folders to include type definitions from. */, // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ /* Source Map Options */ @@ -59,7 +64,5 @@ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ }, - "include": [ - "src/**/*" - ] + "include": ["src/**/*"] }