From 1045d50a940963d1ae665c78d5b4585a0cf7753d Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Thu, 11 Jun 2020 15:14:46 -0500 Subject: [PATCH 01/11] abandoning work on setting up testing because almost all testing frameworks do not seem support esm and typescript together --- PROTOPAINT.code-workspace | 3 +- README.md | 2 +- dev-server.ts | 3 +- package-lock.json | 773 +++++++++++++++--- package.json | 12 +- .../js/ActionCommandBuilder.ts | 6 +- tsconfig.json | 8 +- 7 files changed, 697 insertions(+), 110 deletions(-) diff --git a/PROTOPAINT.code-workspace b/PROTOPAINT.code-workspace index e0ffe28..6e76f88 100644 --- a/PROTOPAINT.code-workspace +++ b/PROTOPAINT.code-workspace @@ -11,12 +11,13 @@ ], "settings": { "files.exclude": { - "**/node_modules": false, + // "**/node_modules": false, "**/.git": false, "**/.svn": true, "**/.hg": true, "**/.gitignore": false, "**/src": true, + "**/tests": true, "**/CVS": true, "**/.DS_Store": true, "**/*.js.m*": true, diff --git a/README.md b/README.md index a76235e..8d23186 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ProtoPaint [![time tracker](https://wakatime.com/badge/github/maxdevos49/ProtoPaint.svg)](https://wakatime.com/badge/github/maxdevos49/ProtoPaint) -[![Actions Status](https://github.com/maxdevos49/protopaint/workflows/build/badge.svg)](https://github.com/maxdevos49/protopaint/actions) +![CI](https://github.com/maxdevos49/ProtoPaint/workflows/CI/badge.svg?branch=master) A advanced Paint Application made with Typescript. This application is designed with extensibility, modularity, and maintainability as the top priority to create a application with desktop quality editing and power eventually. diff --git a/dev-server.ts b/dev-server.ts index 1ab087a..07344de 100644 --- a/dev-server.ts +++ b/dev-server.ts @@ -1,11 +1,12 @@ import http from "http"; import express from "express"; import ip from "ip"; +import path from "path"; const app: express.Application = express(); const server: http.Server = http.createServer(app); -app.use(express.static(__dirname + "/src")); +app.use(express.static(path.resolve() + "/src")); app.use((_, res) => { res.redirect("/index.html"); diff --git a/package-lock.json b/package-lock.json index 0cfecb2..acd2d2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,12 +83,25 @@ "@types/node": "*" } }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true, + "optional": true + }, "@types/mime": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==", "dev": true }, + "@types/mocha": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", + "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", + "dev": true + }, "@types/node": { "version": "14.0.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.9.tgz", @@ -127,12 +140,17 @@ "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, "requires": { "mime-types": "~2.1.24", "negotiator": "0.6.2" } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -148,16 +166,40 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "balanced-match": { @@ -166,11 +208,16 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, "requires": { "bytes": "3.1.0", "content-type": "~1.0.4", @@ -194,17 +241,30 @@ "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" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, "camelcase": { "version": "5.3.1", @@ -234,6 +294,22 @@ } } }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -287,7 +363,6 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, "requires": { "safe-buffer": "5.1.2" } @@ -295,20 +370,17 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "date-fns": { "version": "2.14.0", @@ -320,7 +392,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -331,17 +402,24 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, "diff": { "version": "4.0.2", @@ -352,8 +430,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "emoji-regex": { "version": "7.0.3", @@ -364,8 +441,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "error-ex": { "version": "1.3.2", @@ -376,11 +452,40 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", @@ -388,22 +493,21 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dev": true, "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", @@ -437,11 +541,19 @@ "vary": "~1.1.2" } }, + "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" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -461,17 +573,24 @@ "locate-path": "^3.0.0" } }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs.realpath": { "version": "1.0.0", @@ -479,6 +598,19 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -499,12 +631,48 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -515,7 +683,6 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -527,8 +694,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, @@ -536,7 +702,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -560,14 +725,12 @@ "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, "is-arrayish": { "version": "0.2.1", @@ -575,18 +738,110 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": 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": "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 }, + "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-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -603,6 +858,15 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "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" + } + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -612,38 +876,32 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "dev": true + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" }, "mime-types": { "version": "2.1.27", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dev": true, "requires": { "mime-db": "1.44.0" } @@ -657,17 +915,131 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "node": { + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/node/-/node-14.4.0.tgz", + "integrity": "sha512-uJ9LXT9OjBEZaFtyVxSPxLfVCPZ9TPUtyqqxSyDazj2Vj40S9sL3b1hKnctktnwTG8IMqDsUnQ6HOplDS1RuMQ==", + "requires": { + "node-bin-setup": "^1.0.0" + } + }, + "node-bin-setup": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.0.6.tgz", + "integrity": "sha512-uPIxXNis1CRbv1DwqAxkgBk5NFV3s7cMN/Gf556jSw6jBvV7ca4F9lRL/8cALcZecRibeqU+5dFYqFFmzv5a0Q==" + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } }, "normalize-package-data": { "version": "2.5.0", @@ -681,11 +1053,50 @@ "validate-npm-package-license": "^3.0.1" } }, + "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 + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "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 + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, "requires": { "ee-first": "1.1.1" } @@ -736,8 +1147,7 @@ "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-exists": { "version": "3.0.0", @@ -760,7 +1170,12 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, "pify": { @@ -773,7 +1188,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dev": true, "requires": { "forwarded": "~0.1.2", "ipaddr.js": "1.9.1" @@ -782,20 +1196,17 @@ "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, "requires": { "bytes": "3.1.0", "http-errors": "1.7.2", @@ -814,6 +1225,15 @@ "pify": "^3.0.0" } }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -847,14 +1267,12 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { "version": "5.7.1", @@ -866,7 +1284,6 @@ "version": "0.17.1", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dev": true, "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -886,8 +1303,7 @@ "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, @@ -895,7 +1311,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -912,20 +1327,17 @@ "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -969,11 +1381,16 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "string-width": { "version": "3.1.0", @@ -986,6 +1403,48 @@ "strip-ansi": "^5.1.0" } }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -995,6 +1454,19 @@ "ansi-regex": "^4.1.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "optional": 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=", + "dev": true + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -1004,11 +1476,19 @@ "has-flag": "^3.0.0" } }, + "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" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tree-kill": { "version": "1.2.2", @@ -1016,6 +1496,46 @@ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, + "ts-mocha": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-7.0.0.tgz", + "integrity": "sha512-7WfkQw1W6JZXG5m4E1w2e945uWzBoZqmnOHvpMu0v+zvyKLdUQeTtRMfcQsVEKsUnYL6nTyH4okRt2PZucmFXQ==", + "dev": true, + "requires": { + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + } + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } + }, "ts-nameof": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ts-nameof/-/ts-nameof-5.0.0.tgz", @@ -1040,6 +1560,19 @@ "yn": "3.1.1" } }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "optional": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, "tslib": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", @@ -1059,7 +1592,6 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -1074,14 +1606,12 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "validate-npm-package-license": { "version": "3.0.4", @@ -1096,8 +1626,16 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "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" + } }, "which-module": { "version": "2.0.0", @@ -1105,6 +1643,42 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "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 + }, + "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" + } + } + } + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -1156,6 +1730,17 @@ "decamelize": "^1.2.0" } }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 10701a3..beae3c6 100644 --- a/package.json +++ b/package.json @@ -3,25 +3,25 @@ "version": "0.0.1", "description": "Advanced Paint", "main": "index.js", + "type": "module", "devDependencies": { "@types/express": "^4.17.6", "@types/ip": "^1.1.0", "@types/ts-nameof": "^4.2.1", "concurrently": "^5.1.0", "ts-nameof": "^5.0.0", - "ts-node": "^8.10.1", "ttypescript": "^1.5.10", "typescript": "^3.8.3" }, "dependencies": { - "ip": "^1.1.5", "express": "^4.17.1", - "source-map-support": "^0.5.12", - "esm": "^3.2.25" + "ip": "^1.1.5", + "node": "^14.x", + "source-map-support": "^0.5.12" }, "scripts": { "build": "ttsc", - "start": "node -r esm -r source-map-support/register ./dev-server.js", + "start": "node -r source-map-support/register ./dev-server.js", "dev": "ttsc && concurrently \"ttsc -w\" \"nodemon\"" }, "nodemonConfig": { @@ -36,4 +36,4 @@ }, "author": "Maxwell DeVos", "license": "ISC" -} +} \ No newline at end of file diff --git a/src/lib/action-commander/js/ActionCommandBuilder.ts b/src/lib/action-commander/js/ActionCommandBuilder.ts index f214a82..87a796a 100644 --- a/src/lib/action-commander/js/ActionCommandBuilder.ts +++ b/src/lib/action-commander/js/ActionCommandBuilder.ts @@ -1,7 +1,7 @@ import { IConfiguration } from "./interfaces/IConfiguration.js"; import { IStartup } from "./interfaces/IStartup.js"; - import { ServiceCollection } from "../../dependency-injection/js/DependencyInjection.js"; - import { ActionCommander } from "./ActionCommander.js"; +import { ServiceCollection } from "../../dependency-injection/js/DependencyInjection.js"; +import { ActionCommander } from "./ActionCommander.js"; export const ActionCommanderBuilder = new class ActionCommanderBuilder { @@ -39,7 +39,7 @@ export const ActionCommanderBuilder = new class ActionCommanderBuilder { //init startup let startup = new this._startup(this._configuration); - //initilize services + //initialize services startup.configureServices(ServiceCollection); //construct actionCommander diff --git a/tsconfig.json b/tsconfig.json index 8d3dccb..1152297 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,8 +6,8 @@ "types/*", ], }, - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ - "module": "es6", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ "allowJs": false, /* Allow javascript files to be compiled. */ "sourceMap": true, /* Generates corresponding '.map' file. */ /* Strict Type-Checking Options */ @@ -24,7 +24,7 @@ /* Additional Checks */ "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, /* Module Resolution Options */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": false, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "experimentalDecorators": true, "emitDecoratorMetadata": true, @@ -33,7 +33,7 @@ "transform": "ts-nameof", "type": "raw" } - ] + ], }, "include": [ "src/**/*.ts", From 62f8a2670862dc9f7231315ef81f9527f0f49b0e Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Thu, 11 Jun 2020 16:42:33 -0500 Subject: [PATCH 02/11] starting notification panel --- dev-server.ts | 2 + package-lock.json | 668 ------------------ package.json | 2 +- src/index.html | 29 +- .../FooterConfiguration.ts | 0 src/js/index.ts | 2 +- 6 files changed, 31 insertions(+), 672 deletions(-) rename src/js/{extensions => configurations}/FooterConfiguration.ts (100%) diff --git a/dev-server.ts b/dev-server.ts index 07344de..ee80d70 100644 --- a/dev-server.ts +++ b/dev-server.ts @@ -6,6 +6,8 @@ import path from "path"; const app: express.Application = express(); const server: http.Server = http.createServer(app); +process.title = "ProtoPaint Development Server";//does nothing.... i think + app.use(express.static(path.resolve() + "/src")); app.use((_, res) => { diff --git a/package-lock.json b/package-lock.json index acd2d2f..22634c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,25 +83,12 @@ "@types/node": "*" } }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true, - "optional": true - }, "@types/mime": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==", "dev": true }, - "@types/mocha": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", - "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", - "dev": true - }, "@types/node": { "version": "14.0.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.9.tgz", @@ -145,12 +132,6 @@ "negotiator": "0.6.2" } }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -166,54 +147,17 @@ "color-convert": "^1.9.0" } }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -241,21 +185,6 @@ "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" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -294,22 +223,6 @@ } } }, - "chokidar": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", - "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" - } - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -402,15 +315,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -421,12 +325,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -452,36 +350,6 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -493,12 +361,6 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -541,15 +403,6 @@ "vary": "~1.1.2" } }, - "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" - } - }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -573,15 +426,6 @@ "locate-path": "^3.0.0" } }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -598,19 +442,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -631,48 +462,12 @@ "path-is-absolute": "^1.0.0" } }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -738,110 +533,18 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": 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": "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 }, - "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-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.0" - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -858,21 +561,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "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" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -915,99 +603,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", - "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "chokidar": "3.3.0", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.5", - "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "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.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1031,16 +626,6 @@ "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.0.6.tgz", "integrity": "sha512-uPIxXNis1CRbv1DwqAxkgBk5NFV3s7cMN/Gf556jSw6jBvV7ca4F9lRL/8cALcZecRibeqU+5dFYqFFmzv5a0Q==" }, - "node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -1053,46 +638,6 @@ "validate-npm-package-license": "^3.0.1" } }, - "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 - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "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 - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1172,12 +717,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -1225,15 +764,6 @@ "pify": "^3.0.0" } }, - "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", - "dev": true, - "requires": { - "picomatch": "^2.0.4" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1381,12 +911,6 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1403,48 +927,6 @@ "strip-ansi": "^5.1.0" } }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1454,19 +936,6 @@ "ansi-regex": "^4.1.0" } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "optional": 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=", - "dev": true - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -1476,15 +945,6 @@ "has-flag": "^3.0.0" } }, - "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" - } - }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -1496,46 +956,6 @@ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, - "ts-mocha": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-7.0.0.tgz", - "integrity": "sha512-7WfkQw1W6JZXG5m4E1w2e945uWzBoZqmnOHvpMu0v+zvyKLdUQeTtRMfcQsVEKsUnYL6nTyH4okRt2PZucmFXQ==", - "dev": true, - "requires": { - "ts-node": "7.0.1", - "tsconfig-paths": "^3.5.0" - }, - "dependencies": { - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", - "dev": true, - "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - } - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "dev": true - } - } - }, "ts-nameof": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ts-nameof/-/ts-nameof-5.0.0.tgz", @@ -1547,32 +967,6 @@ "glob": "^7.1.6" } }, - "ts-node": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", - "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", - "dev": true, - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "optional": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, "tslib": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", @@ -1628,57 +1022,12 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "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" - } - }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - }, - "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 - }, - "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" - } - } - } - }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -1729,23 +1078,6 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true } } } diff --git a/package.json b/package.json index beae3c6..21d0276 100644 --- a/package.json +++ b/package.json @@ -36,4 +36,4 @@ }, "author": "Maxwell DeVos", "license": "ISC" -} \ No newline at end of file +} diff --git a/src/index.html b/src/index.html index 70bcae6..4ba37f4 100644 --- a/src/index.html +++ b/src/index.html @@ -186,11 +186,36 @@
Notification Panel
  • - Filterable + Slide in from right and fade out when new notification. They stack upwards.
  • + + + +
  • +
    Configuration Support
    +
      +
    1. + + Allow for registering configuration files to be run after all services are started Just use a extension for this purpose. +
    2. +
    +
  • + +
  • +
    App load update
    +
    1. - Slide in from right and fade out when new notification. They stack upwards. + Add splash screen that is shown by default and covers the whole screen +
    2. +
    3. + + Splash screen is removed after all extensions, controllers, and + configurations are loaded +
    4. +
    5. + + A ProtoPaint logo is displayed and some sort of loading animation is displayed.
  • diff --git a/src/js/extensions/FooterConfiguration.ts b/src/js/configurations/FooterConfiguration.ts similarity index 100% rename from src/js/extensions/FooterConfiguration.ts rename to src/js/configurations/FooterConfiguration.ts diff --git a/src/js/index.ts b/src/js/index.ts index 0713c9a..81ae786 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -1,6 +1,6 @@ import { Canvas } from "./controllers/Canvas.js"; import { View } from "./controllers/View.js"; -import { FooterConfiguration } from "./extensions/FooterConfiguration.js"; +import { FooterConfiguration } from "./configurations/FooterConfiguration.js"; import { InteractionLayer } from "./extensions/InteractionLayerExtension.js"; import { EditMode } from "./modes/EditMode.js"; import { PanMode } from "./modes/PanMode.js"; From 0fc523f5b1da81e288c86c132736502890e6a25f Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Tue, 23 Jun 2020 17:09:20 -0500 Subject: [PATCH 03/11] updated prototest --- PROTOPAINT.code-workspace | 87 ---------- package-lock.json | 37 +++-- package.json | 5 +- src/js/services/CanvasService.ts | 4 +- src/js/services/FlagOptionService.ts | 21 ++- test/services/canvasService.test.ts | 203 ++++++++++++++++++++++++ test/services/flagOptionService.test.ts | 62 ++++++++ tsconfig.json | 1 + 8 files changed, 310 insertions(+), 110 deletions(-) delete mode 100644 PROTOPAINT.code-workspace create mode 100644 test/services/canvasService.test.ts create mode 100644 test/services/flagOptionService.test.ts diff --git a/PROTOPAINT.code-workspace b/PROTOPAINT.code-workspace deleted file mode 100644 index 6e76f88..0000000 --- a/PROTOPAINT.code-workspace +++ /dev/null @@ -1,87 +0,0 @@ -{ - "folders": [ - { - "name": "Source", - "path": "./src" - }, - { - "name": "Other", - "path": "." - } - ], - "settings": { - "files.exclude": { - // "**/node_modules": false, - "**/.git": false, - "**/.svn": true, - "**/.hg": true, - "**/.gitignore": false, - "**/src": true, - "**/tests": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/*.js.m*": true, - "**/*.js": { - "when": "$(basename).ts" - } - }, - "workbench.colorCustomizations": { - "activityBar.background": "#2f7c47", - "activityBar.activeBackground": "#2f7c47", - "activityBar.activeBorder": "#422c74", - "activityBar.foreground": "#e7e7e7", - "activityBar.inactiveForeground": "#e7e7e799", - "activityBarBadge.background": "#422c74", - "activityBarBadge.foreground": "#e7e7e7", - "titleBar.activeBackground": "#215732", - "titleBar.inactiveBackground": "#21573299", - "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveForeground": "#e7e7e799", - "statusBar.background": "#215732", - "statusBarItem.hoverBackground": "#2f7c47", - "statusBar.foreground": "#e7e7e7", - "statusBar.border": "#215732", - "titleBar.border": "#215732" - }, - "peacock.color": "#215732", - "better-comments.tags": [ - { - "tag": "!", - "color": "#FF2D00", - "strikethrough": false, - "backgroundColor": "transparent" - }, - { - "tag": "#", - "color": "#ffffff", - "strikethrough": false, - "backgroundColor": "#007777" - }, - { - "tag": "?", - "color": "#3498DB", - "strikethrough": false, - "backgroundColor": "transparent" - }, - { - "tag": "//", - "color": "#474747", - "strikethrough": true, - "backgroundColor": "transparent" - }, - { - "tag": "todo", - "color": "#FF8C00", - "strikethrough": false, - "backgroundColor": "transparent" - }, - { - "tag": "*", - "color": "#98C379", - "strikethrough": false, - "backgroundColor": "transparent" - } - ], - "javascript.preferences.importModuleSpecifier": "relative" - } -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 22634c6..a2af828 100644 --- a/package-lock.json +++ b/package-lock.json @@ -155,8 +155,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "body-parser": { "version": "1.19.0", @@ -179,7 +178,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -249,11 +247,15 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concurrently": { "version": "5.2.0", @@ -439,8 +441,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "get-caller-file": { "version": "2.0.5", @@ -452,7 +453,6 @@ "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", @@ -505,7 +505,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -514,8 +513,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip": { "version": "1.1.5", @@ -598,7 +596,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -650,7 +647,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -703,8 +699,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-parse": { "version": "1.0.6", @@ -723,6 +718,15 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "prototest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/prototest/-/prototest-0.1.1.tgz", + "integrity": "sha512-Vaw7fvauKS/eB5ixK2XTDrXsnk4seji7lSQ4ifF+wGRfJB/fEnqIHwb8rZYMN0sRvh2aY7IDp69Me8G6fkKsfQ==", + "requires": { + "colors": "^1.4.0", + "glob": "^7.1.6" + } + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -1042,8 +1046,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "y18n": { "version": "4.0.0", diff --git a/package.json b/package.json index 21d0276..c11c9ba 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,15 @@ "express": "^4.17.1", "ip": "^1.1.5", "node": "^14.x", + "prototest": "^0.1.1", "source-map-support": "^0.5.12" }, "scripts": { "build": "ttsc", "start": "node -r source-map-support/register ./dev-server.js", - "dev": "ttsc && concurrently \"ttsc -w\" \"nodemon\"" + "dev": "ttsc && concurrently \"ttsc -w\" \"nodemon\"", + "pretest": "ttsc", + "test": "prototest" }, "nodemonConfig": { "watch": [ diff --git a/src/js/services/CanvasService.ts b/src/js/services/CanvasService.ts index 8e0e1d2..227292c 100644 --- a/src/js/services/CanvasService.ts +++ b/src/js/services/CanvasService.ts @@ -147,7 +147,7 @@ export class CanvasService { this.context = this.element.getContext("2d"); if (!this.context) - throw new Error("The canvas context failed to be initilized."); + throw new Error("The canvas context failed to be initialized."); //set variables to actual values let canvasBounds = this.element.getBoundingClientRect(); @@ -160,7 +160,7 @@ export class CanvasService { this.$x.subscribe(v => this.applyTransformations()); this.$y.subscribe(v => this.applyTransformations()); this.$width.subscribe(v => { - this.element.width = this.width;//clears canavas + this.element.width = this.width;//resets canvas this.applyTransformations() }); this.$height.subscribe(v => { diff --git a/src/js/services/FlagOptionService.ts b/src/js/services/FlagOptionService.ts index 81babb8..107efed 100644 --- a/src/js/services/FlagOptionService.ts +++ b/src/js/services/FlagOptionService.ts @@ -27,18 +27,33 @@ export class FlagOptionService { public registerOptions(flagOptions: IFlagSuggestion): void { + if (!flagOptions) + throw new TypeError("flag options cannot be null or undefined."); + + if (flagOptions.name === null || flagOptions.name === undefined) + throw new TypeError("Flag name must be defined"); + + if (flagOptions.sourceSelector === null || flagOptions.sourceSelector === undefined) + throw new TypeError("Flag SourceSelector must be defined"); + + if (flagOptions.formatterSelector === null || flagOptions.formatterSelector === undefined) + throw new TypeError("Flag formatterSelector must be defined"); + if (this.options.has(flagOptions.name)) throw new Error(`The FlagOption: "${flagOptions.name}" already exist. Try using a different name`); this.options.set(flagOptions.name, flagOptions); } - public getOptions(optionKeys: string): IDataPart[] | null { + public getOptions(optionKey: string): IDataPart[] | null { + + if (optionKey === null || optionKey === undefined) + throw new TypeError("optionKey cannot be null or undefined"); - if (!this.options.has(optionKeys)) + if (!this.options.has(optionKey)) return null; - let flagSuggestion = this.options.get(optionKeys); + let flagSuggestion = this.options.get(optionKey); let data = flagSuggestion.sourceSelector(); return data.map(flagSuggestion.formatterSelector); diff --git a/test/services/canvasService.test.ts b/test/services/canvasService.test.ts new file mode 100644 index 0000000..2306620 --- /dev/null +++ b/test/services/canvasService.test.ts @@ -0,0 +1,203 @@ +import { specification, it, expect } from "prototest"; +import { CanvasService } from "../../src/js/services/CanvasService.js" + +specification({ + title: "Canvas Service", + authors: [ + "Maxwell DeVos" + ], + description: "",//TODO wrote before testing framework was created + specs: [ + ["Canvas Service Initialization", () => { + + let service = new CanvasService(); + + it("Should have x default value", () => { + expect(service.x).toBe(0); + }); + + it("Should have y default value", () => { + expect(service.y).toBe(0); + }); + + it("Should have width default value", () => { + expect(service.width).toBe(500); + }); + + it("Should have height default value", () => { + expect(service.height).toBe(500); + }); + + it("Should have originX default value", () => { + expect(service.originX).toBe(0); + }); + + it("Should have originY default value", () => { + expect(service.originY).toBe(0); + }); + + it("Should have scale default value", () => { + expect(service.scale).toBe(1); + }); + }], + + ["Canvas Service Pan", () => { + let service = new CanvasService(); + service.pan(10, 10); + + it("Should pan horizontally 10px", () => { + expect(service.x).toBe(10); + }); + + it("Should pan vertically 10px", () => { + expect(service.y).toBe(10); + }); + + service.pan(0, 0); + + it("Should pan horizontally 0px", () => { + expect(service.x).toBe(10); + }); + + it("Should pan vertically 0px", () => { + expect(service.y).toBe(10); + }); + + service.pan(-10, -10); + + it("Should pan horizontally -10px", () => { + expect(service.x).toBe(0); + }); + + it("Should pan vertically -10px", () => { + expect(service.y).toBe(0); + }); + }], + ["Canvas Service Translation", () => { + let service = new CanvasService(); + + service.setTranslation(10, 10); + it("Should have x position 10px", () => { + expect(service.x).toBe(10); + }); + + it("Should have y position 10px", () => { + expect(service.y).toBe(10); + }); + + service.setTranslation(0, 0); + it("Should have x position 0px", () => { + expect(service.x).toBe(0); + }); + + it("Should have y position 0px", () => { + expect(service.y).toBe(0); + }); + + service.setTranslation(-10, -10); + it("Should have x position -10px", () => { + expect(service.x).toBe(-10); + }); + + it("Should have y position -10px", () => { + expect(service.y).toBe(-10); + }); + }], + ["Canvas Service setOrigin", () => { + let service = new CanvasService(); + + service.setOrigin(10, 10); + it("Should have originX 10", () => { + expect(service.originX).toBe(10); + }); + + it("Should have originY 10", () => { + expect(service.originY).toBe(10); + }); + + service.setOrigin(0, 0); + it("Should have originX 0", () => { + expect(service.originX).toBe(0); + }); + + it("Should have originY 0", () => { + expect(service.originY).toBe(0); + }); + + service.setOrigin(-10, -10); + it("Should have originX -10", () => { + expect(service.originX).toBe(-10); + }); + + it("Should have originY -10", () => { + expect(service.originY).toBe(-10); + }); + }], + ["Canvas Service Scale", () => { + + let service = new CanvasService(); + + service.setScale(0); + it("Should have a scale of 0 mapped to 0.25", () => { + expect(service.scale).toBe(0.25); + }); + + service.setScale(5); + it("Should have a scale of 5 mapped to 4", () => { + expect(service.scale).toBe(4); + }); + + service.setScale(-1); + it("Should have a scale of -1 mapped to 0.25", () => { + expect(service.scale).toBe(0.25); + }); + + service.setScale(0.5); + it("Should have a scale of 0.5", () => { + expect(service.scale).toBe(0.5); + }); + }], + + ["Canvas Service scaleFromPoint", () => { + let service = new CanvasService(); + + it("Should have an initial position and scale", () => { + expect(service.x).toBe(0); + expect(service.y).toBe(0); + expect(service.scale).toBe(1); + }); + + service.scaleFromPoint(2, 0, 0); + + it("Should have only changed scale", () => { + expect(service.x).toBe(0); + expect(service.y).toBe(0); + expect(service.scale).toBe(2); + }); + + service.scaleFromPoint(1, 0, 0); + service.scaleFromPoint(2, 250, 250); + + it("Should be scaled by 2 and position be x: -250, Y: -250", () => { + expect(service.x).toBe(-250); + expect(service.y).toBe(-250); + expect(service.scale).toBe(2); + }); + + service.scaleFromPoint(10, 0, 0); + + it("Should not scale by 10 or move", () => { + expect(service.x).toBe(-250); + expect(service.y).toBe(-250); + expect(service.scale).toBe(2); + }); + + it("Should not scale by -1 or move", () => { + expect(service.x).toBe(-250); + expect(service.y).toBe(-250); + expect(service.scale).toBe(2); + }); + + }] + ] +}); \ No newline at end of file diff --git a/test/services/flagOptionService.test.ts b/test/services/flagOptionService.test.ts new file mode 100644 index 0000000..737d005 --- /dev/null +++ b/test/services/flagOptionService.test.ts @@ -0,0 +1,62 @@ +import { it, expect, specification } from "prototest"; +import { FlagOptionService, IFlagSuggestion } from "../../src/js/services/FlagOptionService.js"; + +specification({ + title: "Flag Option Service", + authors: ["Maxwell DeVos"], + description: "",//TODO was written before testing framework + specs: [ + ["flagOptionsService registerOptions", () => { + + let service = new FlagOptionService(); + + const flagOption: IFlagSuggestion = { + name: null, + sourceSelector: null, + formatterSelector: null + }; + + it("Should throw when passed null", () => { + expect(() => service.registerOptions(null)).toThrow(TypeError); + }); + + it("Should throw when name option is null or undefined", () => { + expect(() => service.registerOptions(flagOption)).toThrow(TypeError); + }); + + flagOption.name = "Test Flag Option"; + + it("Should throw when sourceSelector option is null or undefined", () => { + expect(() => service.registerOptions(flagOption)).toThrow(TypeError); + }); + + flagOption.sourceSelector = () => []; + + it("Should throw when formatterSelector option is null or undefined", () => { + expect(() => service.registerOptions(flagOption)).toThrow(TypeError); + }); + }], + + ["flagOptionsService getOptions", () => { + + let service = new FlagOptionService(); + + const flagOption: IFlagSuggestion = { + name: Boolean.name, + sourceSelector: () => [true, false], + formatterSelector: (value: boolean) => ({ value: value + "" }) + }; + + it("Should throw a TypeError when passed null or undefined", () => { + expect(() => service.getOptions(null)).toThrow(TypeError); + }); + + // service.registerOptions(flagOption); + // console.log(service.getOptions(flagOption.name)) + it("Should return a IDataPart array", () => { + expect(service.getOptions(flagOption.name)).toBeDefined(); + }); + + }] + ] +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1152297..59c9206 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,6 +37,7 @@ }, "include": [ "src/**/*.ts", + "test/**/*.ts", "dev-server.ts" ], "exclude": [ From 37b34905eb19075eed1f9159f423ad4036fb877b Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Mon, 29 Jun 2020 22:48:57 -0500 Subject: [PATCH 04/11] progress on notifications --- package-lock.json | 789 ++++++++++++++++++- package.json | 8 +- src/css/index.css | 106 +++ src/index.html | 24 +- src/js/configurations/FooterConfiguration.ts | 27 +- src/js/index.ts | 9 +- src/js/services/NotificationService.ts | 104 +++ src/js/services/PanelService.ts | 9 + test/services/notificationService.test.ts | 160 ++++ 9 files changed, 1213 insertions(+), 23 deletions(-) create mode 100644 src/js/services/NotificationService.ts create mode 100644 test/services/notificationService.test.ts diff --git a/package-lock.json b/package-lock.json index a2af828..594b5dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,6 +83,17 @@ "@types/node": "*" } }, + "@types/jsdom": { + "version": "16.2.3", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.3.tgz", + "integrity": "sha512-BREatezSn74rmLIDksuqGNFUTi9HNAWWQXYpFBFLK9U6wlMCO4M0QCa8CMpDsZQuqxSO9XifVLT5Q1P0vgKLqw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/parse5": "*", + "@types/tough-cookie": "*" + } + }, "@types/mime": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", @@ -95,6 +106,12 @@ "integrity": "sha512-0sCTiXKXELOBxvZLN4krQ0FPOAA7ij+6WwvD0k/PHd9/KAkr4dXel5J9fh6F4x1FwAQILqAWkmpeuS6mjf1iKA==", "dev": true }, + "@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==", + "dev": true + }, "@types/qs": { "version": "6.9.3", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz", @@ -117,12 +134,24 @@ "@types/mime": "*" } }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "@types/ts-nameof": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/ts-nameof/-/ts-nameof-4.2.1.tgz", "integrity": "sha512-NgMmD70b8NwX6BYhKh70xWkquAow6iq3kRAPp4sMAk4Mre9PrqZgvpq5+JbDLWIJPc4Q9ctkwSQjVAOlfuvlyQ==", "dev": true }, + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -132,6 +161,40 @@ "negotiator": "0.6.2" } }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -152,11 +215,53 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -183,6 +288,12 @@ "concat-map": "0.0.1" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -199,6 +310,12 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -252,6 +369,15 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -297,6 +423,55 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "date-fns": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", @@ -317,6 +492,24 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -327,6 +520,33 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -363,6 +583,37 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -405,6 +656,36 @@ "vary": "~1.1.2" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -428,6 +709,23 @@ "locate-path": "^3.0.0" } }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -449,6 +747,15 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -462,6 +769,22 @@ "path-is-absolute": "^1.0.0" } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -474,6 +797,15 @@ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -493,6 +825,17 @@ } } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -520,6 +863,12 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -537,12 +886,110 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", + "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.0.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", + "xml-name-validator": "^3.0.0" + } + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -559,6 +1006,12 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -635,6 +1088,18 @@ "validate-npm-package-license": "^3.0.1" } }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -651,6 +1116,20 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -685,6 +1164,12 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -712,16 +1197,28 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": 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 + }, "prototest": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/prototest/-/prototest-0.1.1.tgz", - "integrity": "sha512-Vaw7fvauKS/eB5ixK2XTDrXsnk4seji7lSQ4ifF+wGRfJB/fEnqIHwb8rZYMN0sRvh2aY7IDp69Me8G6fkKsfQ==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/prototest/-/prototest-0.1.4.tgz", + "integrity": "sha512-CgYDJeG7NGYNIxTb+zoQF92Zky0LUCB/VA7ss5mmyqclvXaExVDn4Tja7KNRMPtipDruRyxfa4OWaBJzSX68IQ==", "requires": { "colors": "^1.4.0", "glob": "^7.1.6" @@ -736,6 +1233,18 @@ "ipaddr.js": "1.9.1" } }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -768,6 +1277,84 @@ "pify": "^3.0.0" } }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -808,6 +1395,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -915,11 +1511,34 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -949,11 +1568,37 @@ "has-flag": "^3.0.0" } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -986,6 +1631,30 @@ "resolve": "^1.9.0" } }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -996,9 +1665,9 @@ } }, "typescript": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", - "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", "dev": true }, "unpipe": { @@ -1006,11 +1675,26 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "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", @@ -1026,12 +1710,87 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", + "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -1048,6 +1807,24 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "ws": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/package.json b/package.json index c11c9ba..4f8e18d 100644 --- a/package.json +++ b/package.json @@ -7,17 +7,19 @@ "devDependencies": { "@types/express": "^4.17.6", "@types/ip": "^1.1.0", + "@types/jsdom": "^16.2.3", "@types/ts-nameof": "^4.2.1", "concurrently": "^5.1.0", + "jsdom": "^16.2.2", "ts-nameof": "^5.0.0", "ttypescript": "^1.5.10", - "typescript": "^3.8.3" + "typescript": "^3.9.5" }, "dependencies": { "express": "^4.17.1", "ip": "^1.1.5", "node": "^14.x", - "prototest": "^0.1.1", + "prototest": "^0.1.4", "source-map-support": "^0.5.12" }, "scripts": { @@ -25,7 +27,7 @@ "start": "node -r source-map-support/register ./dev-server.js", "dev": "ttsc && concurrently \"ttsc -w\" \"nodemon\"", "pretest": "ttsc", - "test": "prototest" + "test": "prototest -t=\"./test/**/*.test.js\"" }, "nodemonConfig": { "watch": [ diff --git a/src/css/index.css b/src/css/index.css index 28e3253..e72ade0 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -122,6 +122,31 @@ div[data-panel] { /* margin: 10px; */ } + +div[data-panel]>div.panel-title>p { + flex-grow: 1; + margin: 0; +} + +div[data-panel]>div.panel-title>span { + flex-grow: 0; +} + +div[data-panel]>div.panel-title>span:hover { + background-color: rgba(226, 226, 226, 0.253); +} + +div[data-panel]>div.panel-title { + top: 0; + position: absolute; + width: 100%; + display: flex; + flex-direction: row; + background-color: rgb(87, 87, 87); + padding: 3px; + z-index: 10; +} + .no-select { -webkit-touch-callout: none; -webkit-user-select: none; @@ -161,6 +186,10 @@ div[data-panel="right"].hide { transform: translateX(110%); } +div[data-panel="notifications"].hide { + transform: translateX(110%); +} + /** ------------------------------ File Menu Dropdowns --------------------------- **/ nav ul, nav li { @@ -232,4 +261,81 @@ nav li:hover { nav kbd { margin: auto; padding: 2px 4px; +} + +/** -------------- Notification Cards -------------------- **/ + +div[data-panel="notifications"] { + position: absolute; + min-width: 200px; + /* height: min-content; */ + right: 0; + bottom: 0; + display: flex; + justify-content: flex-end; + flex-direction: column; + max-height: 60%; + min-height: 20%; + /* flex-shrink: 0; */ + z-index: 100; + margin: 0 5px 10px 0; +} + +div[data-panel="notifications"]>div { + position: relative; + overflow: scroll; + padding: 2px 10px 2px 2px; +} + +.notification { + margin: 5px; + background-color: grey; + color: white; + width: 300px; + position: relative; + animation: grow 0.75s; + transform-origin: right; +} + +@keyframes grow { + from { + transform: scaleX(0); + } + to { + transform: scaleX(1); + } +} + +.notification>div { + display: flex; + flex-direction: row; + background-color: rgb(70, 70, 70); +} + +.notification.warning>div { + background-color: rgb(248, 214, 101); +} + +.notification.error>div { + background-color: rgb(231, 83, 83); +} + +.notification>div>p, .notification>div>span, .notification>p { + margin: 0; + padding: 3px; +} + +.notification>div>p { + flex-grow: 1; +} + +.notification>div>span { + flex-grow: 0; + padding-right: 4px; + padding-left: 4px; + cursor: pointer; +} + +.notification>div>span:hover { + background-color: rgba(226, 226, 226, 0.253); } \ No newline at end of file diff --git a/src/index.html b/src/index.html index 4ba37f4..f533719 100644 --- a/src/index.html +++ b/src/index.html @@ -103,7 +103,7 @@
    File Menu
  • - If command requires input then it opens a dynamicaly generated form for entering + If command requires input then it opens a dynamically generated form for entering flags. It instead just opens the autocomplete at the needed position
  • @@ -196,7 +196,8 @@
    Configuration Support
    1. - Allow for registering configuration files to be run after all services are started Just use a extension for this purpose. + Allow for registering configuration files to be run after all services are + started Just use a extension for this purpose.
    @@ -215,7 +216,7 @@
    App load update
  • - A ProtoPaint logo is displayed and some sort of loading animation is displayed. + A ProtoPaint logo is displayed and some sort of loading animation is displayed.
  • @@ -312,7 +313,7 @@
    ActionCommander.js

    The core of this application. This framework allows the creation of CLI like commands within - controller classes. These commands can then be optionaly bound to keyboard combinations + controller classes. These commands can then be optionally bound to keyboard combinations or though the use of extensions appear in menus. By default this framework makes use of extensions, services, and controllers. @@ -326,7 +327,7 @@

    Extensions:

    Services

    - Can be declared as a singlton or as a transient service. They make use of dependency + Can be declared as a singleton or as a transient service. They make use of dependency injection and also can be used in both extensions, controllers, and/or other services. They do not get access to hooks or the core api. @@ -343,8 +344,8 @@

    Future:
    The main api of this framework feels complete but small changes may come in the future. It is still decoupled from the rest of the project so it could gain a npm module of its own - someday. This framework grew very large very quickly so at somepoint a refractor may be - needed to trim some unneeded code off and also it definitly needs testing. + someday. This framework grew very large very quickly so at some point a refractor may be + needed to trim some unneeded code off and also it definitely needs testing.

  • @@ -353,15 +354,20 @@
    Resize.js
    Used to allow these panels to be resized simply by adding a data tag and indicating the side to - be able to be resized. Will make a npm package in the future. Functionaly complete. + be able to be resized. Will make a npm package in the future. Functionally complete.

  • + +
    +
    +
    + -
    +
    diff --git a/src/js/configurations/FooterConfiguration.ts b/src/js/configurations/FooterConfiguration.ts index ab85c9c..5113fc6 100644 --- a/src/js/configurations/FooterConfiguration.ts +++ b/src/js/configurations/FooterConfiguration.ts @@ -5,6 +5,7 @@ import { MouseService } from "../services/MouseService.js"; import { InteractionModeService } from "../services/InteractionModeService.js"; import { CanvasService } from "../services/CanvasService.js"; import { PanelService } from "../services/PanelService.js"; +import { NotificationService } from "../services/NotificationService.js"; @extension() export class FooterConfiguration { @@ -16,6 +17,7 @@ export class FooterConfiguration { private readonly _ims: InteractionModeService; private readonly _canvas: CanvasService; private readonly _panel: PanelService; + private readonly _notify: NotificationService; constructor( @@ -24,7 +26,8 @@ export class FooterConfiguration { mouse: MouseService, ims: InteractionModeService, canvas: CanvasService, - panel: PanelService + panel: PanelService, + notification: NotificationService ) { this._actionCommander = actionCommander; this._footer = footer; @@ -34,14 +37,30 @@ export class FooterConfiguration { this._canvas = canvas; this._panel = panel; + this._notify = notification; + this._panel.injectActionCommander(actionCommander); } public init(): void { - this._footer.registerObservableButton(this._canvas.$x, null, (v) => `X: ${Math.round(v)}`); - this._footer.registerObservableButton(this._canvas.$y, null, (v) => `Y: ${Math.round(v)}`); + + this._footer.registerObservableButton(this._canvas.$x, + () => { + this._panel.togglePanel("Notifications")}, + (v) => "||"); + + this._footer.registerObservableButton(this._canvas.$x, null, (v) => { + // this._notify.notifyWarning(v.toString()); + return `X: ${Math.round(v)}` + }); + this._footer.registerObservableButton(this._canvas.$y, null, (v) => { + this._notify.notifyError(v.toString()); + return `Y: ${Math.round(v)}` + }); this._footer.registerObservableButton(this._canvas.$scale, null, (v) => `Scale: ${Math.round(v * 100)}%`); - this._footer.registerObservableButton(this._canvas.$width, null, (v) => `Width: ${v}px`); + this._footer.registerObservableButton(this._canvas.$width, null, (v) => { + return `Width: ${v}px` + }); this._footer.registerObservableButton(this._canvas.$height, null, (v) => `Height: ${v}px`); this._footer.registerObservableButton(this._mouse.$canvasPosition, () => console.log("click"), (value) => `Mouse X: ${Math.round(value.x)} Mouse Y: ${Math.round(value.y)}`); diff --git a/src/js/index.ts b/src/js/index.ts index 81ae786..7f07c31 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -27,6 +27,7 @@ import { Edit } from "./controllers/Edit.js"; import { FileController } from "./controllers/FileController.js"; import { Help } from "./controllers/Help.js"; import { FlagForm } from "./extensions/FlagFormExtension.js"; +import { NotificationService } from "./services/NotificationService.js"; class Startup implements IStartup { @@ -48,6 +49,7 @@ class Startup implements IStartup { services.configure(PanelService, (ps) => { ps.registerPanel("Left", 'div[data-panel="left"]'); ps.registerPanel("Right", 'div[data-panel="right"]'); + ps.registerPanel("Notifications", 'div[data-panel="notifications"]'); }); services.addSingleton(InteractionModeService); @@ -58,7 +60,12 @@ class Startup implements IStartup { services.addSingleton(FooterService); services.addSingleton(MouseService); - services.addSingleton(FlagOptionService) + services.addSingleton(FlagOptionService); + + services.addSingleton(NotificationService); + services.configure(NotificationService, (ns) => { + ns.notificationContainer = document.querySelector(`div[data-panel="notifications"]>div.content`) + }); } diff --git a/src/js/services/NotificationService.ts b/src/js/services/NotificationService.ts new file mode 100644 index 0000000..2845f71 --- /dev/null +++ b/src/js/services/NotificationService.ts @@ -0,0 +1,104 @@ +import { service } from "../../lib/dependency-injection/js/DependencyInjection.js"; +import { Observable, Subject } from "../../lib/observable/js/observable.js"; + +export interface INotification { + message: string; + logLevel: LogLevel +} + +export enum LogLevel { + Log, + Warning, + Error +} + +@service() +export class NotificationService { + + private _containerElement: HTMLDivElement; + private _notification: Subject; + public readonly $notification: Observable; + + public set notificationContainer(element: HTMLDivElement) { + this._containerElement = element; + this.$notification.subscribe(v => { + this.appendNotification(v); + }); + } + + constructor() { + this._notification = new Subject(); + this.$notification = this._notification.toObservable(); + } + + /** + * Create a basic notification + * @param message The message of the notification + */ + public notify(message: string): INotification { + return this.generateNotification(message, LogLevel.Log); + } + + /** + * Create a warning notification + * @param message The message of the notification + */ + public notifyWarning(message: string): INotification { + return this.generateNotification(message, LogLevel.Warning); + } + + /** + * Create a warning notification + * @param message The message of the notification + */ + public notifyError(message: string): INotification { + return this.generateNotification(message, LogLevel.Error); + } + + private appendNotification(n: INotification): void { + + let title: string; + let cssClass = "" + + if (n.logLevel === LogLevel.Log) { + title = "Notification"; + } else if (n.logLevel === LogLevel.Warning) { + title = "Warning Notification" + cssClass = "warning" + } else if (n.logLevel === LogLevel.Error) { + title = "Error Notification"; + cssClass = "error"; + } + + this._containerElement.insertAdjacentHTML("beforeend", +/*html*/` +
    +
    +

    ${title}

    + X +
    +

    ${n.message}

    +
    +`.trim()); + + let children = this._containerElement.querySelectorAll(".notification"); + (children[children.length - 1] as any)?.scrollIntoViewIfNeeded?.() + } + + private generateNotification(message: string, logLevel: LogLevel): INotification { + + if (typeof message !== "string") { + throw new TypeError("Notification message must be a valid string"); + } + + let result = { + message: message, + logLevel: logLevel + }; + + this._notification.next(result); + + return result; + } + +} \ No newline at end of file diff --git a/src/js/services/PanelService.ts b/src/js/services/PanelService.ts index d356cf2..71104a6 100644 --- a/src/js/services/PanelService.ts +++ b/src/js/services/PanelService.ts @@ -48,6 +48,12 @@ export class PanelService { this._panels.set(name.toLowerCase(), element); + element.insertAdjacentHTML("afterbegin", /*html*/` +
    +

    ${name}

    + X +
    `) + let dataSource = this._panelSource; dataSource.data = [...this._panels.keys()].map(v => ({ value: v })); this._panelSource = dataSource; @@ -58,18 +64,21 @@ export class PanelService { } public hidePanel(panel: string) { + panel = panel.toLowerCase(); if (this._panels.has(panel)) { this._panels.get(panel)?.classList.add("hide"); } } public showPanel(panel: string) { + panel = panel.toLowerCase(); if (this._panels.has(panel)) { this._panels.get(panel)?.classList.remove("hide"); } } public togglePanel(panel: string) { + panel = panel.toLowerCase(); if (this._panels.has(panel)) { this._panels.get(panel)?.classList.toggle("hide"); } diff --git a/test/services/notificationService.test.ts b/test/services/notificationService.test.ts new file mode 100644 index 0000000..ca8f249 --- /dev/null +++ b/test/services/notificationService.test.ts @@ -0,0 +1,160 @@ +import JSDOM from "jsdom"; +import { specification, it, expect, beforeEach, afterEach } from "prototest"; +import { NotificationService, INotification, LogLevel } from "../../src/js/services/NotificationService.js"; + +specification({ + title: "Notification Service", + authors: [ + "Maxwell DeVos" + ], + description: + "The notification service is to serve as communicating alerts and messages to the user in a standardized way. The service will have 3 levels of notification " + + "with those levels being notify, notifyWarning, and notifyError.", + specs: [ + ["Service Init", () => { + + let service = new NotificationService(); + + it("Should have the property $notification", () => { + expect(service).toHaveProperty("$notification"); + }); + + it("Should have the method notify", () => { + expect(service).toHaveMethod("notify"); + }); + + it("Should have the method notifyWarning", () => { + expect(service).toHaveMethod("notifyWarning"); + }); + + it("Should have the method notifyError", () => { + expect(service).toHaveMethod("notifyError"); + }); + }], + ["Notify Method", () => { + let service = new NotificationService(); + it("Should throw a type error if passed null or undefined", () => { + expect(() => service.notify(null)).toThrow(TypeError); + expect(() => service.notify(undefined)).toThrow(TypeError); + }); + + let message = "Test Message"; + let iNotify: INotification = service.notify(message); + it("Should return a INotification object with expected values", () => { + expect(iNotify).toHaveProperty("message"); + expect(iNotify).toHaveProperty("logLevel"); + + expect(iNotify.message).toStrictEqual(message); + expect(iNotify.logLevel).toStrictEqual(LogLevel.Log); + }); + + iNotify = undefined; + service.$notification.subscribe((v) => { + iNotify = v; + }); + service.notify(message); + + it("Should trigger the $notification observable when called", () => { + expect(iNotify).toBeDefined(); + }); + }], + ["Notify Warning Method", () => { + let service = new NotificationService(); + it("Should throw a TypeError if passed null or undefined", () => { + expect(() => service.notifyWarning(null)).toThrow(TypeError); + expect(() => service.notifyWarning(undefined)).toThrow(TypeError); + }); + + let message = "Test Warning Message"; + let iNotify: INotification = service.notifyWarning(message); + + it("Should return a INotification object with expected values", () => { + expect(iNotify).toHaveProperty("message"); + expect(iNotify).toHaveProperty("logLevel"); + + expect(iNotify.message).toStrictEqual(message); + expect(iNotify.logLevel).toStrictEqual(LogLevel.Warning); + }); + + iNotify = undefined; + service.$notification.subscribe((v) => { + iNotify = v; + }); + + service.notifyWarning(message); + it("Should trigger the $notification observable when called", () => { + expect(iNotify).toBeDefined(); + }); + }], + ["Notify Error Method", () => { + let service = new NotificationService(); + it("Should throw a TypeError if passed null or undefined", () => { + expect(() => service.notifyError(null)).toThrow(TypeError); + expect(() => service.notifyError(undefined)).toThrow(TypeError); + }); + + let message = "Test Error Message"; + let iNotify: INotification = service.notifyError(message); + + it("Should return a INotification object with expected values", () => { + expect(iNotify).toHaveProperty("message"); + expect(iNotify).toHaveProperty("logLevel"); + + expect(iNotify.message).toStrictEqual(message); + expect(iNotify.logLevel).toStrictEqual(LogLevel.Error); + }); + + iNotify = undefined; + service.$notification.subscribe((v) => { + iNotify = v; + }); + + service.notifyError(message); + it("Should trigger the $notification observable when called", () => { + expect(iNotify).toBeDefined(); + }); + }], + ["Notification HTML Container", () => { + const { window } = new JSDOM.JSDOM(); + + let container: HTMLDivElement = window.document.createElement("DIV") as HTMLDivElement; + let service = new NotificationService(); + service.notificationContainer = container; + + let message = "Test Message"; + + let template = (title: string, cssClass: string, message: string) => /*html*/` +
    +
    +

    ${title}

    + X +
    +

    ${message}

    +
    `.trim(); + + let outputHTML = template("Notification", "", message); + service.notify(message); + + it("Container should have 1 basic notification", () => { + expect(container.innerHTML).toStrictEqual(outputHTML); + }); + + outputHTML += template("Warning Notification", "warning", message); + service.notifyWarning(message); + + it("Container should have 2 notifications. 1 basic and 1 Warning", () => { + expect(container.innerHTML).toStrictEqual(outputHTML); + }); + + outputHTML += template("Error Notification", "error", message); + service.notifyError(message); + + it("Container should have 3 notifications. 1 basic, 1 warning, and 1 error", () => { + expect(container.innerHTML).toStrictEqual(outputHTML); + }); + + //Cleanup window + window.close(); + }] + ] +}); \ No newline at end of file From 1efe8f4604100f12d5aa6e299907c8ee315e4769 Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Thu, 2 Jul 2020 00:29:58 -0500 Subject: [PATCH 05/11] completed notifications --- src/css/index.css | 82 +++++++++++++++----- src/index.html | 28 ++++--- src/js/configurations/FooterConfiguration.ts | 22 ++++-- src/js/extensions/SplashScreenExtension.ts | 28 +++++++ src/js/index.ts | 5 ++ src/js/services/NotificationService.ts | 71 ++++++++++++++++- 6 files changed, 192 insertions(+), 44 deletions(-) create mode 100644 src/js/extensions/SplashScreenExtension.ts diff --git a/src/css/index.css b/src/css/index.css index e72ade0..8e59b69 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -9,10 +9,6 @@ --panel-highlight-background-color: rgba(45, 45, 45, 0.95); } -/* * { - font-family: "Fira Code" !important; -} */ - /** ---------------------------------- Setup ---------------------------------- **/ @import url(https://cdn.rawgit.com/tonsky/FiraCode/1.205/distr/fira_code.css); @@ -32,11 +28,6 @@ header { margin: 0; background-color: var(--panel-background-color); flex: 0 1 auto; - /* The above is shorthand for: - flex-grow: 0, - flex-shrink: 1, - flex-basis: auto - */ } section#content { @@ -46,7 +37,6 @@ section#content { height: 100%; flex: 1 1 auto; position: relative; - /* border: solid red 1px; */ } footer { @@ -117,12 +107,10 @@ kbd { div[data-panel] { background-color: var(--panel-highlight-background-color); - /* box-shadow: 0 4px 8px 0 black !important; */ color: var(--panel-color); - /* margin: 10px; */ + transition: transform 0.4s; } - div[data-panel]>div.panel-title>p { flex-grow: 1; margin: 0; @@ -164,10 +152,7 @@ div[data-panel="left"], div[data-panel="right"] { width: 25%; height: 100%; padding: 0; - transition: transform 0.4s; position: relative; - /* flex: 1 1 auto; */ - /* margin: 5px; */ } div[data-panel="left"] { @@ -267,8 +252,7 @@ nav kbd { div[data-panel="notifications"] { position: absolute; - min-width: 200px; - /* height: min-content; */ + min-width: 300px; right: 0; bottom: 0; display: flex; @@ -276,7 +260,6 @@ div[data-panel="notifications"] { flex-direction: column; max-height: 60%; min-height: 20%; - /* flex-shrink: 0; */ z-index: 100; margin: 0 5px 10px 0; } @@ -338,4 +321,65 @@ div[data-panel="notifications"]>div { .notification>div>span:hover { background-color: rgba(226, 226, 226, 0.253); +} + +/************************ Splash Screen *************************/ + +div#splash { + position: absolute; + height: 100vh; + width: 100vw; + z-index: 100000; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + background-color: rgb(87, 87, 87); +} + +div#splash>h1 { + font-size: 4em; + font-weight: bold; + background: rgb(201, 201, 201); + background: linear-gradient(99deg, rgba(201, 201, 201, 1) 14%, rgba(250, 250, 250, 1) 18%, rgba(201, 201, 201, 1) 20%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: shine 1s infinite; + background-size: 900%; + margin: 0; + padding: 0; +} + +@keyframes shine { + 0% { + background-position: right top; + } + 50% { + background-position: 50% 50%; + } + 100% { + background-position: left bottom; + } +} + +@keyframes fade { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +.fade { + animation: fade 0.5s forwards; +} + +.pill{ + background-color: red; + border-radius: 16px; + font-size: smaller; + padding: 0 4px; + margin: 0; } \ No newline at end of file diff --git a/src/index.html b/src/index.html index f533719..aa77961 100644 --- a/src/index.html +++ b/src/index.html @@ -14,13 +14,6 @@ + +
    +
      +
    • + Frame 1 +
        +
      • Layer 1
      • +
      • Layer 2
      • +
      • Layer 3
      • +
      +
    • +
    • + Frame 2 +
        +
      • Layer 1
      • +
      • Layer 2
      • +
      • Layer 3
      • +
      +
    • +
    +
    +`}) +export class FrameMenu extends HTMLElement { + + private readonly _shadowRoot: ShadowRoot; + private readonly _projectService: ProjectService; + + constructor() { + super(); + this._shadowRoot = initShadow(this); + + //because we cant use true dependency injection we must grab the service ourself. The custom element js must also be defined after the service is registered + this._projectService = ServiceCollection.getService(ProjectService); + } + + private render() { + + } + +} \ No newline at end of file diff --git a/src/lib/action-commander/js/ActionCommander.ts b/src/lib/action-commander/js/ActionCommander.ts index 36246d6..900b539 100644 --- a/src/lib/action-commander/js/ActionCommander.ts +++ b/src/lib/action-commander/js/ActionCommander.ts @@ -1,6 +1,6 @@ import { IActionController } from "./interfaces/IActionController.js"; import { IActionExtension, IActionExtensionConstructor } from "./interfaces/IActionExtension.js"; -import { IParsedCommmand } from "./interfaces/IParsedCommand.js"; +import { IParsedCommand } from "./interfaces/IParsedCommand.js"; import { IConfiguration } from "./interfaces/IConfiguration.js"; import { Injector } from "../../dependency-injection/js/DependencyInjection.js"; import { getActionsMetadata } from "./helpers/ActionDecorators.js"; @@ -20,8 +20,8 @@ export interface IActionCommander { registerController(controller: new (...args: any[]) => T): void; - parseCommand(command: string): IParsedCommmand; - executeCommand(parsedCommand: IParsedCommmand): boolean; + parseCommand(command: string): IParsedCommand; + executeCommand(parsedCommand: IParsedCommand): boolean; parseAndExecuteCommand(command: string): boolean; focus(): void; @@ -105,7 +105,7 @@ export class ActionCommander implements IActionCommander { } if (this.controllers.has(controllerName)) { - console.warn(`The controller: "${controller.name}" with command name: "${controllerName}" is registered more than once! The repeated occurences will be omitted`); + console.warn(`The controller: "${controller.name}" with command name: "${controllerName}" is registered more than once! The repeated occurrences will be omitted`); return; } @@ -148,12 +148,12 @@ export class ActionCommander implements IActionCommander { //#region Parsing and Execution - public parseCommand(command: string): IParsedCommmand { + public parseCommand(command: string): IParsedCommand { return CommandParser.parse(command, this.controllers); } - public executeCommand(parsedCommand: IParsedCommmand): boolean { + public executeCommand(parsedCommand: IParsedCommand): boolean { if (!parsedCommand.isValid) { console.error(parsedCommand.errors) @@ -256,7 +256,7 @@ export class ActionCommander implements IActionCommander { //#endregion - //#region Initilization + //#region Initialization public init(): void { @@ -284,7 +284,7 @@ export class ActionCommander implements IActionCommander { this._searchContainer = document.getElementById(this._configuration.searchContainerId ?? "search-container") as HTMLDivElement; if (!this._searchContainer) - throw new Error(`The SearchContainerId: ${this._configuration.searchContainerId ?? "search-container"} is not valid. Aborting Initilization.`); + throw new Error(`The SearchContainerId: ${this._configuration.searchContainerId ?? "search-container"} is not valid. Aborting Initialization.`); //Input Element container this._inputElementContainer.setAttribute("class", "input-container") @@ -306,7 +306,7 @@ export class ActionCommander implements IActionCommander { this.activateExtensionHook(ext => ext.onInput?.(e)); - if (e.key.length > 1)//input event doesnt fire for + if (e.key.length > 1)//input event doesn't fire for this.activateExtensionHook(ex => ex.onChange?.()); if (e.key === "Enter") diff --git a/src/lib/action-commander/js/extensions/ActionHistory.ts b/src/lib/action-commander/js/extensions/ActionHistory.ts index 6a19e45..9b072c0 100644 --- a/src/lib/action-commander/js/extensions/ActionHistory.ts +++ b/src/lib/action-commander/js/extensions/ActionHistory.ts @@ -2,7 +2,7 @@ import { IActionExtension } from "../interfaces/IActionExtension.js"; import { IActionCommander } from "../ActionCommander.js"; import { DataSourceCollection, IDataSource, IDataPart, SourceMode, SelectMode } from "../services/DataSourceCollection.js"; -import { IParsedCommmand } from "../interfaces/IParsedCommand.js"; +import { IParsedCommand } from "../interfaces/IParsedCommand.js"; import { extension } from "../../../dependency-injection/js/DependencyInjection.js"; import { Observable, fromProperty } from "../../../observable/js/observable.js"; @@ -50,7 +50,7 @@ export class ActionHistory implements IActionExtension { } - public onSubmit(parsedCommand: IParsedCommmand): void { + public onSubmit(parsedCommand: IParsedCommand): void { let command = this._actionCommander.getText(); diff --git a/src/lib/action-commander/js/extensions/ErrorDisplay.ts b/src/lib/action-commander/js/extensions/ErrorDisplay.ts index 862b8f5..c72baaa 100644 --- a/src/lib/action-commander/js/extensions/ErrorDisplay.ts +++ b/src/lib/action-commander/js/extensions/ErrorDisplay.ts @@ -1,7 +1,7 @@ import { extension } from "../../../dependency-injection/js/DependencyInjection.js"; import { IActionExtension } from "../interfaces/IActionExtension.js"; import { IActionCommander } from "../ActionCommander.js"; -import { IParsedCommmand } from "../interfaces/IParsedCommand.js"; +import { IParsedCommand } from "../interfaces/IParsedCommand.js"; @extension() export class ErrorDisplay implements IActionExtension { @@ -26,7 +26,7 @@ export class ErrorDisplay implements IActionExtension { this._errorContainer.innerHTML = ""; } - public onError(parsedCommand: IParsedCommmand): void { + public onError(parsedCommand: IParsedCommand): void { this._errorContainer.innerHTML = parsedCommand.errors.join(";"); } diff --git a/src/lib/action-commander/js/extensions/ToggleSearch.ts b/src/lib/action-commander/js/extensions/ToggleSearch.ts index b0a1cf9..bb4c11a 100644 --- a/src/lib/action-commander/js/extensions/ToggleSearch.ts +++ b/src/lib/action-commander/js/extensions/ToggleSearch.ts @@ -1,7 +1,7 @@ import { IActionExtension } from "../interfaces/IActionExtension.js"; import { IActionCommander } from "../ActionCommander.js"; -import { IParsedCommmand } from "../interfaces/IParsedCommand.js"; +import { IParsedCommand } from "../interfaces/IParsedCommand.js"; import { extension } from "../../../dependency-injection/js/DependencyInjection.js"; @extension() diff --git a/src/lib/action-commander/js/helpers/CommandParser.ts b/src/lib/action-commander/js/helpers/CommandParser.ts index 1d85ff4..ec55a01 100644 --- a/src/lib/action-commander/js/helpers/CommandParser.ts +++ b/src/lib/action-commander/js/helpers/CommandParser.ts @@ -1,12 +1,12 @@ -import { IParsedCommmand } from "../interfaces/IParsedCommand.js"; +import { IParsedCommand } from "../interfaces/IParsedCommand.js"; import { IActionController } from "../interfaces/IActionController.js"; export class CommandParser { - public static parse(command: string, controllers: Map): IParsedCommmand { + public static parse(command: string, controllers: Map): IParsedCommand { - let parsedCommand: IParsedCommmand = { + let parsedCommand: IParsedCommand = { command: command, searchKey: "", splitCommand: [], @@ -39,7 +39,7 @@ export class CommandParser { return parsedCommand; } - private static processSplitCommand(parsedCommand: IParsedCommmand, controllers: Map): void { + private static processSplitCommand(parsedCommand: IParsedCommand, controllers: Map): void { //parse controller let controller = parsedCommand.splitCommand.shift(); if (!controllers.has(controller)) { @@ -99,7 +99,7 @@ export class CommandParser { } } - private static splitCommand(parsedCommand: IParsedCommmand): void { + private static splitCommand(parsedCommand: IParsedCommand): void { let index = 0; let insideSingleQuote = false; diff --git a/src/lib/action-commander/js/interfaces/IActionExtension.ts b/src/lib/action-commander/js/interfaces/IActionExtension.ts index dca9795..7429a0e 100644 --- a/src/lib/action-commander/js/interfaces/IActionExtension.ts +++ b/src/lib/action-commander/js/interfaces/IActionExtension.ts @@ -1,5 +1,5 @@ import { IActionCommander } from "../ActionCommander.js"; -import { IParsedCommmand } from "./IParsedCommand.js"; +import { IParsedCommand } from "./IParsedCommand.js"; export interface IActionExtension { @@ -7,12 +7,12 @@ export interface IActionExtension { onInput?(event: KeyboardEvent): void; onChange?(): void; - onSubmit?(parsedCommand: IParsedCommmand): void; + onSubmit?(parsedCommand: IParsedCommand): void; - onExecution?(parsedCommand: IParsedCommmand): void; - onExecutionCancel?(parsedCommand: IParsedCommmand): void; - onSuccess?(parsedCommand: IParsedCommmand): void; - onError?(parsedCommand: IParsedCommmand): void; + onExecution?(parsedCommand: IParsedCommand): void; + onExecutionCancel?(parsedCommand: IParsedCommand): void; + onSuccess?(parsedCommand: IParsedCommand): void; + onError?(parsedCommand: IParsedCommand): void; onFocus?(): void; onBlur?(): void; diff --git a/src/lib/action-commander/js/interfaces/IParsedCommand.ts b/src/lib/action-commander/js/interfaces/IParsedCommand.ts index b663a0b..742540c 100644 --- a/src/lib/action-commander/js/interfaces/IParsedCommand.ts +++ b/src/lib/action-commander/js/interfaces/IParsedCommand.ts @@ -2,7 +2,7 @@ import { IActionController } from "./IActionController.js"; import { IAction } from "./IAction.js"; import { IParsedFlag } from "./IParsedFlag.js"; -export interface IParsedCommmand { +export interface IParsedCommand { command: string; searchKey: string; splitCommand: string[] diff --git a/src/lib/dependency-injection/js/DependencyInjection.ts b/src/lib/dependency-injection/js/DependencyInjection.ts index 4eca775..fa82a4d 100644 --- a/src/lib/dependency-injection/js/DependencyInjection.ts +++ b/src/lib/dependency-injection/js/DependencyInjection.ts @@ -7,23 +7,23 @@ export interface Type { } export function service(): GenericClassDecorator> { - //By decorating the class the constuctor will have its parameters decorated with type metadata + //By decorating the class the constructor will have its parameters decorated with type metadata return function (target: Type) { - //Maybe in the future itll be necessary to do something here + //Maybe in the future it'll be necessary to do something here }; }; export function extension(): GenericClassDecorator> { - //By decorating the class the constuctor will have its parameters decorated with type metadata + //By decorating the class the constructor will have its parameters decorated with type metadata return function (target: Type) { - //Maybe in the future itll be necessary to do something here + //Maybe in the future it'll be necessary to do something here }; }; export class Injector { /** - * Recursivley resolves the dependencies of a given service + * Recursively resolves the dependencies of a given service * @param target The service to resolve */ public static resolve(target: Type): T { @@ -103,7 +103,7 @@ export const ServiceCollection = new class ServiceCollection implements IService if (this._services.has(service)) throw `Service: ${service.name} is already registered.`; - //Create singleton before registering as singleton so we dont get a recursive loop + //Create singleton before registering as singleton so we don't get a recursive loop this._singletonInstances.set(service, Injector.resolve(service)); this._services.set(service, { diff --git a/src/lib/observable/js/observable.ts b/src/lib/observable/js/observable.ts index 0dae2c8..e8d2dc8 100644 --- a/src/lib/observable/js/observable.ts +++ b/src/lib/observable/js/observable.ts @@ -130,7 +130,7 @@ export class Observable implements IObservable{ //#endregion - //#region Observerable.of() + //#region Observable.of() public static of(...items: R[]): Observable { diff --git a/test/services/projectService.test.ts b/test/services/projectService.test.ts new file mode 100644 index 0000000..69bf55f --- /dev/null +++ b/test/services/projectService.test.ts @@ -0,0 +1,157 @@ +import { specification, it, expect } from "prototest"; +import { ProjectService } from "../../src/js/services/ProjectService.js"; +import { LayerType } from "../../src/js/interfaces/IPaintLayer.js"; +import { IPaintFrame } from "../../src/js/interfaces/IPaintFrame.js"; + +specification({ + title: "Project Service", + authors: [ + "Maxwell DeVos", + ], + description: "", + specs: [ + ["Initialization", () => { + let service = new ProjectService(); + let latest: IPaintFrame[]; + let sub = service.$frames.subscribe(v => latest = v); + + it("Should have zero frames", () => { + expect(latest).toBeDefined(); + expect(latest.length).toStrictEqual(0); + }); + + sub.unsubscribe(); + }], + ["addFrame", () => { + let service = new ProjectService(); + let latest: IPaintFrame[]; + let sub = service.$frames.subscribe(v => latest = v); + + it("Should have the method addFrame", () => { + expect(service).toHaveMethod("addFrame"); + }); + + it("Should throw a typeError if not passed a valid string", () => { + expect(() => service.addFrame(null)).toThrow(TypeError); + expect(() => service.addFrame(undefined)).toThrow(TypeError); + expect(() => service.addFrame("")).toThrow(TypeError); + }); + + let frame = service.addFrame("Test"); + + it("Should return a IPaintFrame object with correct default layer", () => { + expect(frame.name).toBe("Test"); + expect(frame.layers.length).toBe(1); + }); + + it("Should have a length of 1 returned by the frame observable", () => { + expect(latest.length).toStrictEqual(1); + }); + + service.addFrame("Frame 2"); + + it("Should have a length of 2 returned by the frame observable", () => { + expect(latest.length).toStrictEqual(2); + }); + + it("Should throw a Error if the same frame name is used more then once", () => { + expect(() => service.addFrame("Test")).toThrow(Error); + }); + + sub.unsubscribe(); + }], + ["removeFrame", () => { + let service = new ProjectService(); + let latest: IPaintFrame[]; + let sub = service.$frames.subscribe(v => latest = v); + + it("Should throw a TypeError if the frameName is not a string or more then 1 character", () => { + expect(() => service.removeFrame(null)).toThrow(TypeError); + expect(() => service.removeFrame(undefined)).toThrow(TypeError); + expect(() => service.removeFrame("")).toThrow(TypeError); + }); + + it("Should throw a Error if the frameName is not present in frameMap", () => { + expect(() => service.removeFrame("Frame 2")).toThrow(Error); + }); + + it("Should decrease the current amount of frames to 0", () => { + service.addFrame("Frame 1"); + expect(latest.length).toBe(1); + service.removeFrame("Frame 1"); + expect(latest.length).toBe(0); + }); + + sub.unsubscribe(); + }], + ["addLayerToFrame", () => { + let service = new ProjectService(); + + it("Should throw a TypeError if frameName or layerName is not a valid string", () => { + expect(() => service.addLayerToFrame(undefined, undefined)).toThrow(TypeError); + expect(() => service.addLayerToFrame(null, undefined)).toThrow(TypeError); + expect(() => service.addLayerToFrame(null, null)).toThrow(TypeError); + expect(() => service.addLayerToFrame("", null)).toThrow(TypeError); + expect(() => service.addLayerToFrame("", "")).toThrow(TypeError); + expect(() => service.addLayerToFrame(null, "")).toThrow(TypeError); + expect(() => service.addLayerToFrame(undefined, null)).toThrow(TypeError); + }); + + it("Should throw a error if the frame does not exist", () => { + expect(() => service.addLayerToFrame("Test", "Layer 1")).toThrow(Error); + }); + + service.addFrame("Test"); + + it("Should throw an error if the layer name is already used for the frame", () => { + expect(() => service.addLayerToFrame("Test", "Layer 1")).toThrow(Error); + }); + + let layer = service.addLayerToFrame("Test", "Layer 2"); + + it("Should return a valid IPaintLayer with a Pixel Layer", () => { + expect(layer.name).toBe("Layer 2"); + expect(layer.layerType).toBe(LayerType.Pixel); + expect(layer.pixelData).toBeDefined(); + expect(layer.vectorData).toBeUndefined(); + + //TODO test further default pixel data + }); + + layer = service.addLayerToFrame("Test", "Layer 3", LayerType.Vector); + + it("Should return a valid IPaintLayer with a Vector Layer", () => { + expect(layer.name).toBe("Layer 3"); + expect(layer.layerType).toBe(LayerType.Vector); + expect(layer.vectorData).toBeDefined(); + expect(layer.pixelData).toBeUndefined(); + + //TODO test further default vector data + }); + + + }], + ["removeLayerFromFrame", () => { + let service = new ProjectService(); + + it("Should throw a TypeError when frameName and/or layerName is not a valid string with at least 1 character", () => { + expect(() => service.removeLayerFromFrame(undefined, undefined)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, undefined)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, null)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame("", null)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame("", "")).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, "")).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(undefined, "")).toThrow(TypeError); + }); + + it("Should throw a error if the frameName and/or layerName is not valid", () => { + expect(() => service.removeLayerFromFrame("Test", "Test")).toThrow(Error); + service.addFrame("Frame 1"); + expect(() => service.removeLayerFromFrame("Frame 1", "Test")).toThrow(Error); + + service.removeLayerFromFrame("Frame 1", "Layer 1"); + }); + + }] + ] +}); \ No newline at end of file From 7c2dd706e24c7f61714bb09ed84644184845b81f Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Sun, 19 Jul 2020 12:42:39 -0500 Subject: [PATCH 08/11] made progress on figuring out how webcomponents work and made progress on abstracting creating new webcomponents --- .editorconfig | 8 - src/index.html | 8 +- src/js/helpers/webcomponent.ts | 26 +++ src/js/webcomponents/frameMenu.ts | 53 ------ src/js/webcomponents/menu-item.ts | 176 ++++++++++++++++++ src/js/webcomponents/project-menu.ts | 109 +++++++++++ .../js/helpers/ActionDecorators.ts | 2 +- src/lib/key-commander/js/KeyCommander.ts | 15 +- 8 files changed, 324 insertions(+), 73 deletions(-) delete mode 100644 .editorconfig delete mode 100644 src/js/webcomponents/frameMenu.ts create mode 100644 src/js/webcomponents/menu-item.ts create mode 100644 src/js/webcomponents/project-menu.ts diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 73c5516..0000000 --- a/.editorconfig +++ /dev/null @@ -1,8 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 4 -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file diff --git a/src/index.html b/src/index.html index 5ad9e54..f31165b 100644 --- a/src/index.html +++ b/src/index.html @@ -289,8 +289,7 @@
    Topic 1

    My library notes

    - - +
    1. KeyCommander.js
      @@ -377,7 +376,6 @@
      Resize.js

      ProtoPaint

      -
      @@ -385,8 +383,8 @@

      ProtoPaint

      - - + + \ No newline at end of file diff --git a/src/js/helpers/webcomponent.ts b/src/js/helpers/webcomponent.ts index 1fec6e3..0cfaeb8 100644 --- a/src/js/helpers/webcomponent.ts +++ b/src/js/helpers/webcomponent.ts @@ -1,15 +1,23 @@ export interface IWebComponent { selector: string; shadowOptions?: ShadowRootInit; + attributes?: string[]; template: string; } export function WebComponent(config: IWebComponent) { + return function (constructor: T) { Reflect.defineMetadata("selector", config.selector, constructor); Reflect.defineMetadata("shadowOptions", config.shadowOptions ?? { mode: "open" }, constructor); Reflect.defineMetadata("template", config.template, constructor); + Reflect.defineMetadata("attributes", config.attributes ?? [], constructor); + + //define static getter "observedAttributes" + Object.defineProperty(constructor, "observedAttributes", { + get: () => config.attributes ?? [], + }); //Register Custom Element window.customElements.define(config.selector, constructor); @@ -28,4 +36,22 @@ export function initShadow(target: T): ShadowRoot { ShadowRoot.appendChild(template.content.cloneNode(true)); return ShadowRoot; +} + +export function attribute(name?: string) { + + return function (target: T, propertyKey: string | symbol) { + + name = name ?? propertyKey as string; + + Object.defineProperty(target, propertyKey, { + get() { + return this.getAttribute(name); + }, + set(value: string) { + this.setAttribute(name, value); + } + }); + + }; } \ No newline at end of file diff --git a/src/js/webcomponents/frameMenu.ts b/src/js/webcomponents/frameMenu.ts deleted file mode 100644 index da60eab..0000000 --- a/src/js/webcomponents/frameMenu.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { WebComponent, initShadow } from "../helpers/webcomponent.js"; -import { ProjectService } from "../services/ProjectService.js"; -import { ServiceCollection } from "../../lib/dependency-injection/js/DependencyInjection.js"; - -@WebComponent({ - selector: "project-menu", - shadowOptions: { mode: "closed" }, - template: /*html*/` - - -
      -
        -
      • - Frame 1 -
          -
        • Layer 1
        • -
        • Layer 2
        • -
        • Layer 3
        • -
        -
      • -
      • - Frame 2 -
          -
        • Layer 1
        • -
        • Layer 2
        • -
        • Layer 3
        • -
        -
      • -
      -
      -`}) -export class FrameMenu extends HTMLElement { - - private readonly _shadowRoot: ShadowRoot; - private readonly _projectService: ProjectService; - - constructor() { - super(); - this._shadowRoot = initShadow(this); - - //because we cant use true dependency injection we must grab the service ourself. The custom element js must also be defined after the service is registered - this._projectService = ServiceCollection.getService(ProjectService); - } - - private render() { - - } - -} \ No newline at end of file diff --git a/src/js/webcomponents/menu-item.ts b/src/js/webcomponents/menu-item.ts new file mode 100644 index 0000000..ac3a8a0 --- /dev/null +++ b/src/js/webcomponents/menu-item.ts @@ -0,0 +1,176 @@ +import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js"; + +@WebComponent({ + selector: "menu-item", + attributes: ["title", "selected"], + template: +/*html*/` + + + +
      + +
      +`}) +export class MenuItem extends HTMLElement { + + @attribute("title") + public title: string; + + @attribute("selected") + public selected: string; + + private _editMode: boolean; + + private readonly _shadowRoot: ShadowRoot; + private readonly _titleSpan: HTMLSpanElement; + private readonly _extraSpan: HTMLSpanElement; + private readonly _arrowSpan: HTMLSpanElement; + + + constructor() { + super(); + + this._editMode = false; + + this._shadowRoot = initShadow(this); + + this._arrowSpan = this._shadowRoot.querySelector("span#arrow"); + this._titleSpan = this._shadowRoot.querySelector("span#title"); + this._extraSpan = this._shadowRoot.querySelector("span#extra"); + + this._arrowSpan.addEventListener("click", e => { + e.preventDefault(); + + this.classList.toggle("show"); + }); + + this._titleSpan.addEventListener("dblclick", (e) => { + e.preventDefault(); + + if (!this._editMode) { + + this._editMode = true; + + let input = document.createElement("input") as HTMLInputElement; + + input.addEventListener("keydown", (e: KeyboardEvent) => { + if (e.key === "Escape") { + this._titleSpan.innerHTML = this.title; + this._editMode = false; + } else if (e.key === "Enter") { + + if (input.value) + this.title = input.value; + + this._titleSpan.innerHTML = this.title; + this._editMode = false; + } + }, false); + + input.addEventListener("focusout", _ => { + if (input.value) + this.title = input.value; + + this._titleSpan.innerHTML = this.title; + this._editMode = false; + }, false); + + input.addEventListener("input", _ => { + input.style.width = input.value.length + 1 + "ch"; + }); + + // this._titleSpan.innerHTML = ``; + this._titleSpan.replaceChild(input, this._titleSpan.childNodes[0]); + + input.value = this.title; + input.style.width = input.value.length + 1 + "ch"; + input.focus(); + } + + }, false); + + + + } + + public connectedCallback() { + this.render(); + } + + public attributeChangedCallback() { + this.render(); + } + + private render() { + this._titleSpan.innerHTML = this.title; + + if (!this.innerHTML) { + (this._shadowRoot.querySelector("span#arrow") as HTMLElement).innerHTML = ""; + } + + //Indicate selected + if (this.selected) { + if (this.innerHTML) + this.style.background = "rgba(255,255,255,0.2)"; + else + (this._shadowRoot.querySelector("div#header") as HTMLElement).style.backgroundColor = "rgba(255,255,255,0.2)"; + } + + } +} \ No newline at end of file diff --git a/src/js/webcomponents/project-menu.ts b/src/js/webcomponents/project-menu.ts new file mode 100644 index 0000000..2d07bea --- /dev/null +++ b/src/js/webcomponents/project-menu.ts @@ -0,0 +1,109 @@ +import { WebComponent, initShadow } from "../helpers/webcomponent.js"; +import { ProjectService } from "../services/ProjectService.js"; +import { ServiceCollection } from "../../lib/dependency-injection/js/DependencyInjection.js"; + +@WebComponent({ + selector: "project-menu", + shadowOptions: { mode: "closed", delegatesFocus: true }, + template: /*html*/` + + + +
      + + + + + + + + + + + + +
      +`}) +export class FrameMenu extends HTMLElement { + + private readonly _shadowRoot: ShadowRoot; + private readonly _projectService: ProjectService; + + constructor() { + super(); + this._shadowRoot = initShadow(this); + + //because we cant use true dependency injection we must grab the service ourself. The custom element js must also be defined after the service is registered + this._projectService = ServiceCollection.getService(ProjectService); + } + + public onConnect() { + this.render(); + } + + private render() { + + //TODO + } +} diff --git a/src/lib/action-commander/js/helpers/ActionDecorators.ts b/src/lib/action-commander/js/helpers/ActionDecorators.ts index b1bb610..c0ac8b3 100644 --- a/src/lib/action-commander/js/helpers/ActionDecorators.ts +++ b/src/lib/action-commander/js/helpers/ActionDecorators.ts @@ -55,7 +55,7 @@ export function action(name: string, summary: string, description?: string): Met //#region Flag Decorator /** - * Declares a paramater as a command flag + * Declares a parameter as a command flag * @param flags Flags the action contains */ export function flag(flags: Array, description: string, suggestionsKey?: string): ParameterDecorator { diff --git a/src/lib/key-commander/js/KeyCommander.ts b/src/lib/key-commander/js/KeyCommander.ts index 669dd26..04de1c7 100644 --- a/src/lib/key-commander/js/KeyCommander.ts +++ b/src/lib/key-commander/js/KeyCommander.ts @@ -14,10 +14,13 @@ export class KeyCommander { this._stopCallbackFunc = (e: KeyboardEvent, element: HTMLElement) => { - return element.tagName === "INPUT" - || element.tagName === "SELECT" - || element.tagName === "TEXTAREA" - || (element.contentEditable === "true"); + return element.tagName !== "BODY"; + + //Below trips and dies on custom elements + // return element.tagName === "INPUT" + // || element.tagName === "SELECT" + // || element.tagName === "TEXTAREA" + // || (element.contentEditable === "true"); }; this.init(); @@ -87,7 +90,7 @@ export class KeyCommander { /** * Formats a key binding string - * @param combination the intial key binding string + * @param combination the initial key binding string */ private static formatCombination(combination: string): string { return combination.split("+").sort().join("+"); @@ -122,7 +125,7 @@ export class KeyCommander { let key = e.key; - if (key === "Meta") {//This is a hack because on macos the meta key is special and a pain in the ass + if (key === "Meta") {//This is a hack because on macosx the meta key is special and a pain in the ass this._activeKeys = []; return; } From 4879a4cdc1290bb788be59374d28a578c0a6443f Mon Sep 17 00:00:00 2001 From: maxdevos49 Date: Fri, 24 Jul 2020 16:11:48 -0500 Subject: [PATCH 09/11] project menu is at a usable stage now --- src/css/index.css | 3 - src/index.html | 87 +------- src/js/helpers/webcomponent.ts | 33 ++- src/js/index.ts | 5 +- src/js/interfaces/IPaintFrame.ts | 1 + src/js/interfaces/IPaintLayer.ts | 3 +- src/js/services/ProjectService.ts | 287 +++++++++++++++++++-------- src/js/webcomponents/menu-item.ts | 227 +++++++++++++++++++-- src/js/webcomponents/project-menu.ts | 125 +++++++++--- test/services/projectService.test.ts | 189 +++++++++++++----- 10 files changed, 691 insertions(+), 269 deletions(-) diff --git a/src/css/index.css b/src/css/index.css index 8e59b69..ef00350 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -125,14 +125,11 @@ div[data-panel]>div.panel-title>span:hover { } div[data-panel]>div.panel-title { - top: 0; - position: absolute; width: 100%; display: flex; flex-direction: row; background-color: rgb(87, 87, 87); padding: 3px; - z-index: 10; } .no-select { diff --git a/src/index.html b/src/index.html index f31165b..3e1db8b 100644 --- a/src/index.html +++ b/src/index.html @@ -7,7 +7,9 @@ - + @@ -284,78 +286,7 @@
      Topic 1
      - - - -
      -

      My library notes

      - -
        -
      1. -
        KeyCommander.js
        -

        - Small library that makes binding key combinations(not sequences) super easy. Used for - all - keyboard input in this app and for the time being is mostly complete. In due time I will - be - making a npm package for this -

        -
        Bugs:
        -
          -
        1. Fails to remove "F" keys from key press history buffer
        2. -
        -
      2. -
      3. -
        ActionCommander.js
        -

        - The core of this application. This framework allows the creation of CLI like commands - within - controller classes. These commands can then be optionally bound to keyboard combinations - or - though the use of extensions appear in menus. By default this framework makes use of - extensions, services, and controllers. -

        -
        -
        Extensions:
        -

        - Take advantage of many different hooks within ActionCommander. They get direct access to - the - api to control functionality. -

        -
        Services
        -

        - Can be declared as a singleton or as a transient service. They make use of dependency - injection and also can be used in both extensions, controllers, and/or other services. - They - do not get access to hooks or the core api. -

        -
        Controllers
        -

        - Used to define the commands/actions to be used inside the application. They have access - to - use any service as needed but not extensions or the core api. -

        - -
        Future:
        -

        - The main api of this framework feels complete but small changes may come in the future. - It - is still decoupled from the rest of the project so it could gain a npm module of its own - someday. This framework grew very large very quickly so at some point a refractor may be - needed to trim some unneeded code off and also it definitely needs testing. -

        -
      4. -
      5. -
        Resize.js
        -

        - Used to allow these panels to be resized simply by adding a data tag and indicating the - side - to - be able to be resized. Will make a npm package in the future. Functionally complete. -

        -
      6. -
      -
      +
      @@ -378,13 +309,15 @@
      Resize.js

      ProtoPaint

    - - - - + + + + + + \ No newline at end of file diff --git a/src/js/helpers/webcomponent.ts b/src/js/helpers/webcomponent.ts index 0cfaeb8..3b85f6d 100644 --- a/src/js/helpers/webcomponent.ts +++ b/src/js/helpers/webcomponent.ts @@ -1,3 +1,5 @@ +import "../../lib/reflect-metadata/js/reflect-metadata.js"; + export interface IWebComponent { selector: string; shadowOptions?: ShadowRootInit; @@ -44,14 +46,29 @@ export function attribute(name?: string) { name = name ?? propertyKey as string; - Object.defineProperty(target, propertyKey, { - get() { - return this.getAttribute(name); - }, - set(value: string) { - this.setAttribute(name, value); - } - }); + let type = Reflect.getMetadata("design:type", target, propertyKey); + + if (type.name !== "String") { + + Object.defineProperty(target, propertyKey, { + get() { + return JSON.parse(this.getAttribute(name)); + }, + set(value: string) { + this.setAttribute(name, JSON.stringify(value)); + } + }); + } else { + + Object.defineProperty(target, propertyKey, { + get() { + return this.getAttribute(name); + }, + set(value: string) { + this.setAttribute(name, value); + } + }); + } }; } \ No newline at end of file diff --git a/src/js/index.ts b/src/js/index.ts index efe3cb2..f05caa4 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -50,7 +50,7 @@ class Startup implements IStartup { services.addSingleton(PanelService); services.configure(PanelService, (ps) => { ps.registerPanel("Left", 'div[data-panel="left"]'); - ps.registerPanel("Right", 'div[data-panel="right"]'); + ps.registerPanel("Project Menu", 'div[data-panel="right"]'); ps.registerPanel("Notifications", 'div[data-panel="notifications"]'); }); @@ -70,6 +70,9 @@ class Startup implements IStartup { }); services.addSingleton(ProjectService); + services.configure(ProjectService, (p) => { + p.menuElement = document.querySelector("project-menu"); + }); } diff --git a/src/js/interfaces/IPaintFrame.ts b/src/js/interfaces/IPaintFrame.ts index b9f09e1..2290291 100644 --- a/src/js/interfaces/IPaintFrame.ts +++ b/src/js/interfaces/IPaintFrame.ts @@ -3,4 +3,5 @@ import { IPaintLayer } from "./IPaintLayer.js"; export interface IPaintFrame { name: string; layers: IPaintLayer[]; + open: boolean; } \ No newline at end of file diff --git a/src/js/interfaces/IPaintLayer.ts b/src/js/interfaces/IPaintLayer.ts index d8dbdab..302fc66 100644 --- a/src/js/interfaces/IPaintLayer.ts +++ b/src/js/interfaces/IPaintLayer.ts @@ -8,11 +8,12 @@ export interface IPaintLayer { layerType: LayerType; + visibility: boolean; + pixelData?: IPixelData; vectorData?: IVectorData; - } export interface IPixelData { diff --git a/src/js/services/ProjectService.ts b/src/js/services/ProjectService.ts index e5d853a..10ae697 100644 --- a/src/js/services/ProjectService.ts +++ b/src/js/services/ProjectService.ts @@ -1,112 +1,147 @@ import { service } from "../../lib/dependency-injection/js/DependencyInjection.js"; import { IPaintFrame } from "../interfaces/IPaintFrame.js"; import { IPaintLayer, LayerType } from "../interfaces/IPaintLayer.js"; -import { Observable, Subject } from "../../lib/observable/js/observable.js"; +import { ProjectMenuElement, ITreeData } from "../webcomponents/project-menu.js"; @service() export class ProjectService { - public name: string; - public readonly $frames: Observable; - - // private _defaultPixelData?: IPixelData; - // private _defaultVectorData?: IVectorData; + public set menuElement(element: ProjectMenuElement) { + this._menuElement = element; + this.init(); + } + private _menuElement: ProjectMenuElement; private _defaultLayerType: LayerType; - - private readonly _frameSubject: Subject; - private readonly _frameMap: Map; + private _selectedFrame: number; + private _selectedLayer: number; + private readonly _frames: IPaintFrame[]; constructor() { this._defaultLayerType = LayerType.Pixel; - this._frameMap = new Map(); - this._frameSubject = new Subject(); - this.$frames = this._frameSubject.toObservable(); - this._frameSubject.start(() => [...this._frameMap.values()]); + this._frames = []; + this._selectedFrame = 0; + this._selectedLayer = 0; + + this.addFrame("Frame 1"); } + private init() { - // public newProject(): void { - // throw new Error("Method not implemented"); - // } + //item is selected + this._menuElement.addEventListener("menu-item-select", ((e: CustomEvent) => { + let frameIndex: number = e.detail.frameIndex; + let layerIndex: number = e.detail.layerIndex ?? 0; - // public resetProject(): void { - // throw new Error("Method not implemented"); - // } + this.select(frameIndex, layerIndex); - // public saveProject(): void { - // throw new Error("Method not implemented"); - // } + }) as EventListener); - // public loadProject(): void { - // throw new Error("Method not implemented"); - // } + //Frame list is toggled + this._menuElement.addEventListener("menu-item-toggle", ((e: CustomEvent) => { + this.toggleFrameList(e.detail.frameIndex); + }) as EventListener); + + //Menu item title is edited + this._menuElement.addEventListener("menu-title-edit", ((e: CustomEvent) => { + this.renameTitle(e.detail.title, e.detail.frameIndex, e.detail.layerIndex); + }) as EventListener); + + //Menu item button is clicked + this._menuElement.addEventListener("menu-item-button-click", ((e: CustomEvent) => { + let buttonType: string = e.detail.buttonType; + let frameIndex: number = e.detail.frameIndex; + let layerIndex: number | null = e.detail.layerIndex; + + if (layerIndex === null) { + if (buttonType === "add") { + this.showFrameList(frameIndex); + this.addLayerToFrame(frameIndex, "Layer " + (this.frameLayerCount(frameIndex) + 1)); + } else if (buttonType === "remove") { + this.removeFrame(frameIndex); + } + + this.renderChanges(); + } else { + if (buttonType === "visibility") { + this.toggleLayerVisibility(frameIndex, layerIndex); + } else if (buttonType === "remove") { + this.removeLayerFromFrame(frameIndex, layerIndex); + this.renderChanges(); + } + + } - public addFrame(frameName: string, layerType?: LayerType): IPaintFrame { + }) as EventListener); + + this._menuElement.addEventListener("menu-button-click", ((e: CustomEvent) => { + let buttonType = e.detail.buttonType; + + if (buttonType === "refresh") { + this.renderChanges(); + } else if (buttonType === "add") { + this.addFrame("Frame " + (this.frameCount() + 1)); + this.renderChanges(); + } + }) as EventListener); + + this.renderChanges(); + } + + public frameCount(): number { + return this._frames.length; + } + + public addFrame(frameName: string, layerType?: LayerType): number { if (frameName === null || frameName === undefined || frameName.length === 0) throw new TypeError("Frame name must be a valid string"); - if (this._frameMap.has(frameName)) - throw new Error(`The frame name ${frameName} is already used. Try a different name.`); - let frame: IPaintFrame = { name: frameName, + open: false, layers: [] }; - this._frameMap.set(frameName, frame); + let frameIndex = this._frames.push(frame) - 1; //Add first layer - this.addLayerToFrame(frameName, "Layer 1", layerType); - - //trigger observable - this._frameSubject.next([...this._frameMap.values()]); + this.addLayerToFrame(frameIndex, "Layer 1", layerType); - return frame; + return frameIndex; } - public removeFrame(frameName: string): void { - - if (typeof frameName !== "string" || frameName.length === 0) - throw new TypeError("frameName must be a valid string longer then 1 character"); - - if (!this._frameMap.has(frameName)) - throw new Error(`The frameName: "${frameName}" was not a valid frameName`); + public getFrame(index: number): IPaintFrame { + if (typeof index !== "number" || index < 0 || index >= this._frames.length) + throw new TypeError("Index must be a valid integer >= 0 and < frameCount"); - this._frameMap.delete(frameName); - this._frameSubject.next([...this._frameMap.values()]); + return this._frames[index]; } - // public getFrame(frameName: string): IPaintFrame { - // throw new Error("Method not implemented"); - // } - - // public frameCount(): number { - // throw new Error("Method not implemented"); - // } + public removeFrame(index: number): void { + if (typeof index !== "number" || index < 0 || index >= this._frames.length) + throw new TypeError("Index must be a number within the range of current frames."); + this._frames.splice(index, 1); + } - public addLayerToFrame(frameName: string, layerName: string, layerType?: LayerType): IPaintLayer { + public addLayerToFrame(frameIndex: number, layerName: string, layerType?: LayerType): number { layerType = layerType ?? this._defaultLayerType; - if (typeof frameName !== "string" || frameName.length === 0 || typeof layerName !== "string" || layerName.length === 0) - throw new TypeError("frameName and/or layerName must be a valid string at least 1 character long"); - - if (!this._frameMap.has(frameName)) - throw new Error(`The frameName: "${frameName}" does not exist`); + if (typeof frameIndex !== "number" || frameIndex < 0 || frameIndex >= this._frames.length) + throw new TypeError("frameIndex must be a valid number >= 0 or < frame count."); - let frame = this._frameMap.get(frameName); + if (typeof layerName !== "string" || layerName.length === 0) + throw new TypeError("layerName must be a valid string at least 1 character long."); - if (frame.layers.filter(v => v.name === layerName).length > 0) - throw new Error(`Layer name: "${layerName}" cannot be repeated`); let newLayer: IPaintLayer = { name: layerName, + visibility: true, layerType: layerType, }; @@ -120,45 +155,133 @@ export class ProjectService { newLayer.vectorData = {};//TODO in future } - //TODO indicate frame was added somehow + let layerIndex = this._frames[frameIndex].layers.push(newLayer) - 1; + return layerIndex; + } + + public removeLayerFromFrame(frameIndex: number, layerIndex: number): void { + + if (typeof frameIndex !== "number" || frameIndex < 0 || frameIndex >= this._frames.length) + throw new TypeError("frameIndex must be a valid integer > 0 and < frame count"); + + if (this._frames[frameIndex].layers.length === 0) + throw new Error("No layers exist on frame"); + + if (typeof layerIndex !== "number" || layerIndex < 0 || layerIndex >= this._frames[frameIndex].layers.length) + throw new TypeError("layerIndex must be a valid integer > 0 and < layer count"); + + + this._frames[frameIndex].layers.splice(layerIndex, 1); + } + + public getFrameLayer(frameIndex: number, layerIndex: number): IPaintLayer { + + if (typeof frameIndex !== "number" || frameIndex < 0 || frameIndex >= this._frames.length) + throw new TypeError("frameIndex must be a valid integer >= 0 or < frameCount."); + + if (typeof layerIndex !== "number" || layerIndex < 0 || layerIndex >= this._frames[frameIndex].layers.length) + throw new TypeError("layerIndex must be a valid integer >= 0 or < frameLayerCount."); + + return this._frames[frameIndex].layers[layerIndex]; + } + + public frameLayerCount(frameIndex: number): number { + + if (typeof frameIndex !== "number" || frameIndex < 0 || frameIndex >= this._frames.length) + throw new TypeError("Frame with the index: ${frameIndex} is not valid"); + + return this._frames[frameIndex].layers.length; + } + + public select(frameIndex: number, layerIndex?: number): void {//TODO TEST + + if (typeof frameIndex !== "number" || frameIndex < 0 || frameIndex >= this._frames.length) + throw new TypeError("frameIndex was not valid"); + + this._selectedFrame = frameIndex; + this._selectedLayer = layerIndex ?? 0; + } + + public toggleFrameList(frameIndex: number) {//TODO TEST + let frame = this.getFrame(frameIndex); + frame.open = !frame.open; + } + + public showFrameList(frameIndex: number) {//TODO TEST + let frame = this.getFrame(frameIndex); + frame.open = true; + } + + public hideFrameList(frameIndex: number) {//TODO TEST + let frame = this.getFrame(frameIndex); + frame.open = false; + } + + public renameTitle(title: string, frameIndex: number, layerIndex?: number | null | undefined) {//TODO TEST + + if (!layerIndex) { + this.getFrame(frameIndex).name = title; + } else { + this.getFrameLayer(frameIndex, layerIndex).name = title; + } + + } + public toggleLayerVisibility(frameIndex: number, layerIndex: number): void { + let layer = this.getFrameLayer(frameIndex, layerIndex); - frame.layers.push(newLayer); - return newLayer; + layer.visibility = !layer.visibility; } - public removeLayerFromFrame(frameName: string, layerName: string): void { + public renderChanges(): void { + if (this._menuElement) + this._menuElement.data = this.generateMenuData(); + } - if (typeof frameName !== "string" || frameName.length === 0 || typeof layerName !== "string" || layerName.length === 0) - throw new TypeError("frameName and/or layerName must be a valid string at least 1 character long"); + private generateMenuData() { + let data: ITreeData[] = []; - if (!this._frameMap.has(frameName)) - throw new Error(`The frameName: "${frameName}" does not exist`); + this._frames.forEach((frameData, frameIndex) => { - let frame = this._frameMap.get(frameName); - let index: number; + let layerMenuData: ITreeData[] = []; - if (frame.layers.filter((v, i) => { - if (v.name === layerName) - index = i; - return v.name === layerName; - }).length === 0) - throw new Error(`Layer name: "${layerName}" cannot be found`); + frameData.layers.forEach((layerData, layerIndex) => { + layerMenuData.push({ + name: layerData.name, + visibility: layerData.visibility, + selected: (this._selectedFrame === frameIndex && this._selectedLayer === layerIndex) + }); + }); - frame.layers.splice(index, 1); + data.push({ + name: frameData.name, + open: frameData.open, + selected: (this._selectedFrame === frameIndex), + data: layerMenuData + }); + }); - //TODO indicate frame was removed somehow + return data; } - // public getFrameLayer(frameName: string, layerName: string): IPaintLayer { + + + + + // public newProject(): void { // throw new Error("Method not implemented"); // } - // public frameLayerCount(frameName: string): number { + // public resetProject(): void { // throw new Error("Method not implemented"); // } + // public saveProject(): void { + // throw new Error("Method not implemented"); + // } - //TODO Render hook/Observable? Maybe Observable string/enum with indication of what to re render + // public loadProject(): void { + // throw new Error("Method not implemented"); + // } -} \ No newline at end of file +} diff --git a/src/js/webcomponents/menu-item.ts b/src/js/webcomponents/menu-item.ts index ac3a8a0..d244bbe 100644 --- a/src/js/webcomponents/menu-item.ts +++ b/src/js/webcomponents/menu-item.ts @@ -2,14 +2,22 @@ import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js" @WebComponent({ selector: "menu-item", - attributes: ["title", "selected"], + attributes: ["title", "selected", "layer-index", "frame-index", "visibility"], template: /*html*/` - +
    - +
    `}) -export class MenuItem extends HTMLElement { +export class MenuItemElement extends HTMLElement { @attribute("title") public title: string; @@ -75,12 +144,23 @@ export class MenuItem extends HTMLElement { @attribute("selected") public selected: string; + @attribute("frame-index") + public frameIndex: string; + + @attribute("layer-index") + public layerIndex: string | null; + + @attribute("visibility") + public visibility: string; + + private _editMode: boolean; private readonly _shadowRoot: ShadowRoot; private readonly _titleSpan: HTMLSpanElement; private readonly _extraSpan: HTMLSpanElement; private readonly _arrowSpan: HTMLSpanElement; + private readonly _headerDiv: HTMLDivElement; constructor() { @@ -93,13 +173,83 @@ export class MenuItem extends HTMLElement { this._arrowSpan = this._shadowRoot.querySelector("span#arrow"); this._titleSpan = this._shadowRoot.querySelector("span#title"); this._extraSpan = this._shadowRoot.querySelector("span#extra"); + this._headerDiv = this._shadowRoot.querySelector("div#header"); - this._arrowSpan.addEventListener("click", e => { + //arrow toggle + this._arrowSpan.addEventListener("click", e => {//Change to click the entire row e.preventDefault(); - + e.stopPropagation(); + + this.dispatchEvent(new CustomEvent("menu-item-toggle", { + bubbles: true, + composed: true, + detail: { + frameIndex: parseInt(this.frameIndex) + } + })); + this.classList.toggle("show"); }); + //select + this._headerDiv.addEventListener("click", e => { + e.preventDefault(); + e.stopPropagation(); + + this.dispatchEvent(new CustomEvent("menu-item-select", { + bubbles: true, + composed: true, + detail: { + frameIndex: parseInt(this.frameIndex ?? (this.parentElement as MenuItemElement).frameIndex), + LayerIndex: parseInt(this.layerIndex) ?? null + } + })); + + + if (this.hasAttribute("frame-index")) { + this.parentElement.querySelectorAll(`menu-item[selected="true"]`).forEach(element => (element as MenuItemElement).selected = "false"); + + this.selected = "true"; + (this.querySelector(`menu-item[layer-index="0"]`) as MenuItemElement).selected = "true"; + } else { + this.parentElement.parentElement.querySelectorAll(`menu-item[selected="true"]`).forEach(element => (element as MenuItemElement).selected = "false"); + + this.selected = "true";//self + (this.parentElement as MenuItemElement).selected = "true";//parent + } + + }); + + //Button click + this._extraSpan.addEventListener("click", (e: MouseEvent) => { + + //Check if we touched anything + if (!(e.target as HTMLElement).closest("i")) + return; + + e.preventDefault(); + e.stopPropagation(); + + let buttonType: string = (e.target as HTMLElement).closest("i").id; + + this.dispatchEvent(new CustomEvent("menu-item-button-click", { + bubbles: true, + composed: true, + detail: { + buttonType: buttonType, + frameIndex: parseInt(this.frameIndex ?? (this.parentElement as MenuItemElement).frameIndex), + layerIndex: this.layerIndex !== null ? parseInt(this.layerIndex) : null + } + })); + + if (buttonType === "visibility") { + this.visibility = (!(this.visibility === "true")) + ""; + } + + + }); + + //edit name this._titleSpan.addEventListener("dblclick", (e) => { e.preventDefault(); @@ -120,6 +270,7 @@ export class MenuItem extends HTMLElement { this._titleSpan.innerHTML = this.title; this._editMode = false; + } }, false); @@ -145,32 +296,66 @@ export class MenuItem extends HTMLElement { }, false); + } + + private dispatchTitleEdit(name: string): void { + this.dispatchEvent(new CustomEvent("menu-title-edit", { + cancelable: false, + composed: true, + bubbles: true, + detail: { + title: name, + frameIndex: parseInt(this.frameIndex ?? (this.parentElement as MenuItemElement).frameIndex), + LayerIndex: parseInt(this.layerIndex) ?? null + } + })); } public connectedCallback() { this.render(); } - public attributeChangedCallback() { + public attributeChangedCallback(attributeName: string, oldValue: string, newValue: string) { + + if (attributeName === "title" && oldValue !== null) { + this.dispatchTitleEdit(newValue); + } else if (attributeName === "visibility") { + let i = this._extraSpan.querySelector("i#visibility"); + + i.classList.remove("fa-eye-slash"); + i.classList.remove("fa-eye"); + + if (newValue === "true") + i.classList.add("fa-eye"); + else + i.classList.add("fa-eye-slash"); + + } + this.render(); } private render() { this._titleSpan.innerHTML = this.title; - if (!this.innerHTML) { - (this._shadowRoot.querySelector("span#arrow") as HTMLElement).innerHTML = ""; + if (this.hasAttribute("layer-index")) { + this._arrowSpan.innerHTML = ""; + (this._extraSpan.querySelector("#remove") as HTMLElement).title = "Remove Layer"; } - //Indicate selected - if (this.selected) { - if (this.innerHTML) - this.style.background = "rgba(255,255,255,0.2)"; - else - (this._shadowRoot.querySelector("div#header") as HTMLElement).style.backgroundColor = "rgba(255,255,255,0.2)"; - } + if (this.hasAttribute("visibility")) { + + // console.log(this.visibility); + // if (this.visibility) { + // console.log("Hey hey what is that noise"); + // let i = this._extraSpan.querySelector("i#visibility"); + // console.log(i, this); + // i.classList.toggle("fa-eye"); + // i.classList.toggle("fa-eye-slash"); + } } + } \ No newline at end of file diff --git a/src/js/webcomponents/project-menu.ts b/src/js/webcomponents/project-menu.ts index 2d07bea..e65140d 100644 --- a/src/js/webcomponents/project-menu.ts +++ b/src/js/webcomponents/project-menu.ts @@ -1,11 +1,12 @@ -import { WebComponent, initShadow } from "../helpers/webcomponent.js"; -import { ProjectService } from "../services/ProjectService.js"; -import { ServiceCollection } from "../../lib/dependency-injection/js/DependencyInjection.js"; +import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js"; +import { MenuItemElement } from "./menu-item.js"; @WebComponent({ selector: "project-menu", - shadowOptions: { mode: "closed", delegatesFocus: true }, + shadowOptions: { mode: "open", delegatesFocus: true }, + attributes: ["data", "title"], template: /*html*/` + +
    - - - - - - - - - - - - + Default yeah
    `}) -export class FrameMenu extends HTMLElement { +export class ProjectMenuElement extends HTMLElement { + + @attribute("data") + public data: ITreeData[]; + + private readonly _buttons: HTMLSpanElement; + private readonly _title: HTMLSpanElement; private readonly _shadowRoot: ShadowRoot; - private readonly _projectService: ProjectService; constructor() { super(); this._shadowRoot = initShadow(this); - //because we cant use true dependency injection we must grab the service ourself. The custom element js must also be defined after the service is registered - this._projectService = ServiceCollection.getService(ProjectService); + this._buttons = this._shadowRoot.querySelector("span.buttons"); + + this._buttons.addEventListener("click", (e) => { + + if (!(e.target as HTMLElement).closest("i")) + return; + + e.preventDefault(); + e.stopPropagation(); + + let buttonType = (e.target as HTMLElement).id; + + this.dispatchEvent(new CustomEvent("menu-button-click", { + composed: true, + bubbles: true, + detail: { + buttonType: buttonType + } + })); + }); + + // this. } public onConnect() { this.render(); } + public attributeChangedCallback(name: string, oldValue: string, newValue: string) { + this.render(); + } + private render() { - //TODO + let itemsContainer = this._shadowRoot.querySelector("div#items") as HTMLDivElement; + itemsContainer.innerHTML = ""; + + this.data.forEach((frame, frameIndex) => { + + let frameElement = document.createElement("menu-item") as MenuItemElement; + frameElement.title = frame.name; + frameElement.frameIndex = frameIndex + ""; + frameElement.selected = frame.selected + ""; + + if (frame.open) + frameElement.classList.add("show"); + + frame.data?.forEach((layer, layerIndex) => { + let layerElement = document.createElement("menu-item") as MenuItemElement; + + layerElement.title = layer.name; + layerElement.layerIndex = layerIndex + ""; + layerElement.selected = layer.selected + ""; + layerElement.visibility = layer.visibility + ""; + + frameElement.appendChild(layerElement); + }); + + itemsContainer.appendChild(frameElement); + }); + } } + +export interface ITreeData { + name: string; + visibility?: boolean, + open?: boolean; + data?: ITreeData[]; + selected?: boolean; +} \ No newline at end of file diff --git a/test/services/projectService.test.ts b/test/services/projectService.test.ts index 69bf55f..eb2d075 100644 --- a/test/services/projectService.test.ts +++ b/test/services/projectService.test.ts @@ -1,7 +1,6 @@ import { specification, it, expect } from "prototest"; import { ProjectService } from "../../src/js/services/ProjectService.js"; import { LayerType } from "../../src/js/interfaces/IPaintLayer.js"; -import { IPaintFrame } from "../../src/js/interfaces/IPaintFrame.js"; specification({ title: "Project Service", @@ -12,20 +11,17 @@ specification({ specs: [ ["Initialization", () => { let service = new ProjectService(); - let latest: IPaintFrame[]; - let sub = service.$frames.subscribe(v => latest = v); it("Should have zero frames", () => { - expect(latest).toBeDefined(); - expect(latest.length).toStrictEqual(0); + let count = service.frameCount(); + expect(count).toBeDefined(); + expect(typeof count).toBe("number"); + expect(count).toStrictEqual(0); }); - sub.unsubscribe(); }], ["addFrame", () => { let service = new ProjectService(); - let latest: IPaintFrame[]; - let sub = service.$frames.subscribe(v => latest = v); it("Should have the method addFrame", () => { expect(service).toHaveMethod("addFrame"); @@ -37,52 +33,53 @@ specification({ expect(() => service.addFrame("")).toThrow(TypeError); }); - let frame = service.addFrame("Test"); + let frameIndex = service.addFrame("Test"); - it("Should return a IPaintFrame object with correct default layer", () => { - expect(frame.name).toBe("Test"); - expect(frame.layers.length).toBe(1); + it("Should return the index of the newly created frame which is 0", () => { + expect(frameIndex).toBe(0); }); - it("Should have a length of 1 returned by the frame observable", () => { - expect(latest.length).toStrictEqual(1); + + it("Should have 1 frame in service", () => { + let count = service.frameCount(); + expect(count).toStrictEqual(1); }); service.addFrame("Frame 2"); - it("Should have a length of 2 returned by the frame observable", () => { - expect(latest.length).toStrictEqual(2); + it("Should have 2 frames in service", () => { + let count = service.frameCount(); + expect(count).toStrictEqual(2); }); - it("Should throw a Error if the same frame name is used more then once", () => { - expect(() => service.addFrame("Test")).toThrow(Error); - }); - - sub.unsubscribe(); }], ["removeFrame", () => { let service = new ProjectService(); - let latest: IPaintFrame[]; - let sub = service.$frames.subscribe(v => latest = v); - it("Should throw a TypeError if the frameName is not a string or more then 1 character", () => { + it("Should throw a TypeError if the frameIndex is not a valid index", () => { expect(() => service.removeFrame(null)).toThrow(TypeError); expect(() => service.removeFrame(undefined)).toThrow(TypeError); - expect(() => service.removeFrame("")).toThrow(TypeError); + expect(() => service.removeFrame(-1)).toThrow(TypeError); + expect(() => service.removeFrame(1)).toThrow(TypeError); }); - it("Should throw a Error if the frameName is not present in frameMap", () => { - expect(() => service.removeFrame("Frame 2")).toThrow(Error); + it("Should throw a Error if the frameIndex does not exist in the frame array", () => { + expect(() => service.removeFrame(1)).toThrow(Error); }); it("Should decrease the current amount of frames to 0", () => { + let count: number; + service.addFrame("Frame 1"); - expect(latest.length).toBe(1); - service.removeFrame("Frame 1"); - expect(latest.length).toBe(0); + count = service.frameCount(); + expect(count).toBe(1); + + service.removeFrame(0); + count = service.frameCount(); + expect(count).toBe(0); + }); - sub.unsubscribe(); }], ["addLayerToFrame", () => { let service = new ProjectService(); @@ -91,23 +88,72 @@ specification({ expect(() => service.addLayerToFrame(undefined, undefined)).toThrow(TypeError); expect(() => service.addLayerToFrame(null, undefined)).toThrow(TypeError); expect(() => service.addLayerToFrame(null, null)).toThrow(TypeError); - expect(() => service.addLayerToFrame("", null)).toThrow(TypeError); - expect(() => service.addLayerToFrame("", "")).toThrow(TypeError); + expect(() => service.addLayerToFrame(0, null)).toThrow(TypeError); + expect(() => service.addLayerToFrame(-1, null)).toThrow(TypeError); + expect(() => service.addLayerToFrame(0, "")).toThrow(TypeError); + expect(() => service.addLayerToFrame(-1, "")).toThrow(TypeError); expect(() => service.addLayerToFrame(null, "")).toThrow(TypeError); expect(() => service.addLayerToFrame(undefined, null)).toThrow(TypeError); }); it("Should throw a error if the frame does not exist", () => { - expect(() => service.addLayerToFrame("Test", "Layer 1")).toThrow(Error); + expect(() => service.addLayerToFrame(0, "Layer 1")).toThrow(Error); }); service.addFrame("Test"); - it("Should throw an error if the layer name is already used for the frame", () => { - expect(() => service.addLayerToFrame("Test", "Layer 1")).toThrow(Error); + let layerIndex = service.addLayerToFrame(0, "Layer 2"); + + it("Should return the new layers index", () => { + expect(layerIndex).toBe(1); + layerIndex = service.addLayerToFrame(0, "Layer 3", LayerType.Vector); + expect(layerIndex).toBe(2); + }); + + }], + ["removeLayerFromFrame", () => { + let service = new ProjectService(); + + it("Should throw a TypeError when frameName and/or layerName is not a valid string with at least 1 character", () => { + expect(() => service.removeLayerFromFrame(undefined, undefined)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, undefined)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, null)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(0, null)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(-1, null)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(0, 0)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(-1, 0)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(-1, -1)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(0, -1)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, 0)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(null, -1)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(undefined, 0)).toThrow(TypeError); + expect(() => service.removeLayerFromFrame(undefined, -1)).toThrow(TypeError); + }); + + it("Should throw a error if the frameName and/or layerName is not valid", () => { + expect(() => service.removeLayerFromFrame(0, 0)).toThrow(Error); + service.addFrame("Frame 1"); + expect(() => service.removeLayerFromFrame(0, 1)).toThrow(Error); + + service.removeLayerFromFrame(0, 0); + }); + + }], + ["getFrameLayer", () => { + let service = new ProjectService(); + + it("Should throw a TypeError with invalid parameters", () => { + expect(() => service.getFrameLayer(null, null)).toThrow(TypeError); + expect(() => service.getFrameLayer(undefined, null)).toThrow(TypeError); + expect(() => service.getFrameLayer(undefined, undefined)).toThrow(TypeError); + expect(() => service.getFrameLayer(0, undefined)).toThrow(TypeError); + expect(() => service.getFrameLayer(0, 0)).toThrow(TypeError); }); - let layer = service.addLayerToFrame("Test", "Layer 2"); + let frameIndex = service.addFrame("Test"); + + let layerIndex = service.addLayerToFrame(frameIndex, "Layer 2"); + let layer = service.getFrameLayer(frameIndex, layerIndex); it("Should return a valid IPaintLayer with a Pixel Layer", () => { expect(layer.name).toBe("Layer 2"); @@ -118,7 +164,8 @@ specification({ //TODO test further default pixel data }); - layer = service.addLayerToFrame("Test", "Layer 3", LayerType.Vector); + layerIndex = service.addLayerToFrame(frameIndex, "Layer 3", LayerType.Vector); + layer = service.getFrameLayer(frameIndex, layerIndex); it("Should return a valid IPaintLayer with a Vector Layer", () => { expect(layer.name).toBe("Layer 3"); @@ -129,29 +176,67 @@ specification({ //TODO test further default vector data }); + }], + ["getFrame", () => { + let service = new ProjectService(); + + service.addFrame("Test"); + + let frame = service.getFrame(0); + + it("Should return a IPaintFrame object with correct default layer", () => { + expect(frame.name).toBe("Test"); + expect(frame.layers.length).toBe(1); + }); + + }], + ["frameCount", () => { + let service = new ProjectService(); + + it("Should have zero frames initially", () => { + expect(service.frameCount()).toBe(0); + }); + + let frameIndex = service.addFrame("Test Frame"); + + it("Should have 1 frame after adding a frame", () => { + expect(service.frameCount()).toBe(1); + }); + + service.removeFrame(frameIndex); + + it("Should have a frame count of zero again after removing the frame", () => { + expect(service.frameCount()).toBe(0); + }); }], - ["removeLayerFromFrame", () => { + ["frameLayerCount", () => { let service = new ProjectService(); - it("Should throw a TypeError when frameName and/or layerName is not a valid string with at least 1 character", () => { - expect(() => service.removeLayerFromFrame(undefined, undefined)).toThrow(TypeError); - expect(() => service.removeLayerFromFrame(null, undefined)).toThrow(TypeError); - expect(() => service.removeLayerFromFrame(null, null)).toThrow(TypeError); - expect(() => service.removeLayerFromFrame("", null)).toThrow(TypeError); - expect(() => service.removeLayerFromFrame("", "")).toThrow(TypeError); - expect(() => service.removeLayerFromFrame(null, "")).toThrow(TypeError); - expect(() => service.removeLayerFromFrame(undefined, "")).toThrow(TypeError); + it("Should throw a TypeError if the frameIndex is not valid", () => { + expect(() => service.frameLayerCount(null)).toThrow(TypeError); + expect(() => service.frameLayerCount(undefined)).toThrow(TypeError); + expect(() => service.frameLayerCount(0)).toThrow(TypeError); + expect(() => service.frameLayerCount(-1)).toThrow(TypeError); }); - it("Should throw a error if the frameName and/or layerName is not valid", () => { - expect(() => service.removeLayerFromFrame("Test", "Test")).toThrow(Error); - service.addFrame("Frame 1"); - expect(() => service.removeLayerFromFrame("Frame 1", "Test")).toThrow(Error); + let frameIndex = service.addFrame("Frame 1"); + + it("Should return 1 after adding a new frame", () => { + expect(service.frameLayerCount(frameIndex)).toBe(1); + }); + + service.removeLayerFromFrame(frameIndex, 0); - service.removeLayerFromFrame("Frame 1", "Layer 1"); + it("Should return 0 after removing the layer", () => { + expect(service.frameLayerCount(frameIndex)).toBe(0); }); + service.addLayerToFrame(frameIndex, "Layer Test"); + + it("Should return 1 after adding a new layer to the frame", () => { + expect(service.frameLayerCount(frameIndex)).toBe(1); + }); }] ] }); \ No newline at end of file From 2be61e8c088672f0fde1bf717c4e617639e769df Mon Sep 17 00:00:00 2001 From: Maxwell DeVos Date: Sun, 12 Sep 2021 23:54:03 -0500 Subject: [PATCH 10/11] Pushing changes from 1 year ago --- src/css/index.css | 4 + src/index.html | 260 ++---------------- src/js/index.ts | 10 + src/js/modes/EditMode.ts | 27 +- src/js/services/HistoryService.ts | 41 +++ src/js/services/PanelService.ts | 4 +- src/js/services/PixelDrawingService.ts | 20 ++ src/js/services/ProjectService.ts | 5 +- src/js/services/VectorDrawingService.ts | 0 src/js/webcomponents/customelement.ts | 53 ++++ src/js/webcomponents/menu-container.ts | 257 +++++++++++++++++ src/js/webcomponents/menu-item.ts | 47 ++-- src/js/webcomponents/project-menu.ts | 98 ++++++- src/js/webcomponents/tab-menu.ts | 29 ++ .../js/ActionCommandBuilder.ts | 4 +- src/lib/resize/js/resize.ts | 3 +- src/manifest.json | 17 ++ 17 files changed, 585 insertions(+), 294 deletions(-) create mode 100644 src/js/services/HistoryService.ts create mode 100644 src/js/services/PixelDrawingService.ts create mode 100644 src/js/services/VectorDrawingService.ts create mode 100644 src/js/webcomponents/customelement.ts create mode 100644 src/js/webcomponents/menu-container.ts create mode 100644 src/js/webcomponents/tab-menu.ts create mode 100644 src/manifest.json diff --git a/src/css/index.css b/src/css/index.css index ef00350..f5e0e47 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -379,4 +379,8 @@ div#splash>h1 { font-size: smaller; padding: 0 4px; margin: 0; +} + +.fa-layer-group{ + color: rgb(255, 235, 55) !important; } \ No newline at end of file diff --git a/src/index.html b/src/index.html index 3e1db8b..f355844 100644 --- a/src/index.html +++ b/src/index.html @@ -1,7 +1,15 @@ - + + ProtoPaint + + + + + + +
    -
    -

    ProtoPaint

    -

    Started: March 26, 2020

    - -

    Advanced paint application built with javascript. Extensibility and maintainability are the main - goals with some ambitious features planned.

    - -

    TODO List

    -
      -
    • -
      HTML/CSS Updates
      -
        -
      1. - - Update page to use flex box where the footer and header have fixed heights and the - interaction area grows to fit the remaining space -
      2. -
      3. - - Clean up unused/unneeded css from old website -
      4. -
      5. - - Pick a font to use for the application.(FiraCode for monospace and default bootstrap - for elsewhere) -
      6. -
      7. - - adjust panel color to look a little inset(distinguish from footer and header) -
      8. -
      -
    • -
    • -
      File Menu
      -
        -
      1. - - Builds upon variation binding. -
      2. -
      3. - - Displays key combo if applicable -
      4. -
      5. - - Can use an observable list for options If options are needed it is displayed - as autocomplete -
      6. -
      7. - - If command requires input then it opens a dynamically generated form for entering - flags. It instead just opens the autocomplete at the needed position -
      8. -
      -
    • - -
    • -
      Action Search
      -
        -
      1. - - Fix flags so they display grouped together -
      2. -
      3. - - When using the autocomplete on the flag add the "=" instead of a space -
      4. -
      5. - - Commands can use autocomplete for selecting flag option values -
      6. -
      7. - - Rewrite command parser because its overly complex and hard to deal with. (Now with - over - half as much parsing code) -
      8. -
      -
    • - -
    • -
      Footer Menu
      -
        -
      1. - - Group all footer declarations into 1 file. (So its easy to find and update them) -
      2. -
      3. - - Hook into the action search to display the options for each menu action when needed -
      4. -
      -
    • - -
    • -
      Action Commands
      -
        -
      1. - - Fix fullscreen command. Make typescript be happy with the function calls. -
      2. -
      3. - - Create file controller -
      4. -
      5. - - Create help controller -
      6. -
      7. - - Create Edit controller -
      8. -
      -
    • - -
    • -
      Notification Panel
      -
        -
      1. - - Create Service -
      2. -
      3. - - Log Message, error, and warning -
      4. -
      5. - - Removable notifications -
      6. -
      7. - - Slide in from right and fade out when new notification. They stack upwards. -
      8. -
      -
    • - -
    • -
      Configuration Support
      -
        -
      1. - - Allow for registering configuration files to be run after all services are - started Just use a extension for this purpose. -
      2. -
      -
    • - -
    • -
      App load update
      -
        -
      1. - - Add splash screen that is shown by default and covers the whole screen -
      2. -
      3. - - Splash screen is removed after all extensions, controllers, and - configurations are loaded -
      4. -
      5. - - A ProtoPaint logo is displayed and some sort of loading animation is displayed. -
      6. -
      -
    • - -
    • -
      Help Commands
      -
        -
      1. - - Tutorial -
      2. -
      3. - - Display/Remap Keyboard Commands -
      4. -
      5. - - Explain actionsearch controls -
      6. -
      -
    • - -
    • -
      Edit controller
      -
        -
      1. - - Create new shape -
      2. -
      3. - - Move virtual cursor -
      4. -
      5. - - Change layer -
      6. -
      -
    • - -
    • -
      File controller
      -
        -
      1. - - save -
      2. -
      3. - - new project -
      4. -
      -
    • -
    - -
    -
    - +
    + + + + TODO + Default Layer Type(Pixel/Vector) + + + TODO + + + TODO +
    @@ -312,6 +97,7 @@

    ProtoPaint

    + diff --git a/src/js/index.ts b/src/js/index.ts index f05caa4..dc19b5c 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -30,6 +30,7 @@ import { FlagForm } from "./extensions/FlagFormExtension.js"; import { NotificationService } from "./services/NotificationService.js"; import { SplashScreen } from "./extensions/SplashScreenExtension.js"; import { ProjectService } from "./services/ProjectService.js"; +import { PixelDrawingService } from "./services/PixelDrawingService.js"; class Startup implements IStartup { @@ -73,6 +74,15 @@ class Startup implements IStartup { services.configure(ProjectService, (p) => { p.menuElement = document.querySelector("project-menu"); }); + + services.addSingleton(PixelDrawingService); + + // Event Testing + // window.addEventListener("test", _ => { + // console.log("HEYYYYYYYYY YAAAAAAAAAA"); + // }); + + // window.dispatchEvent(new Event("test")); } diff --git a/src/js/modes/EditMode.ts b/src/js/modes/EditMode.ts index a8e8f32..092340d 100644 --- a/src/js/modes/EditMode.ts +++ b/src/js/modes/EditMode.ts @@ -2,28 +2,35 @@ import { InteractionMode } from "../services/InteractionModeService.js"; import { IInteractionMode } from "../interfaces/IInteractionMode.js"; import { Vector } from "../helpers/vector.js"; import { CanvasService } from "../services/CanvasService.js"; +import { PixelDrawingService } from "../services/PixelDrawingService.js"; @InteractionMode() export class EditMode implements IInteractionMode { private _mouseDown: boolean; private _previousPosition: Vector; - private readonly _canvas: CanvasService; - constructor(canvas: CanvasService) { + private readonly _pixel: PixelDrawingService; + + + constructor(canvas: CanvasService, pixel: PixelDrawingService) { this._canvas = canvas; + this._pixel = pixel; + + this._previousPosition = new Vector(); + } public init(): void { - throw new Error("Method not implemented."); + this._canvas.interactionLayer.style.cursor = "crosshair"; } public onMouseDown(e: MouseEvent): void { - this.mouseDown(); + this._pixel.activate(e.offsetX, e.offsetY); + } public onMouseUp(e: MouseEvent): void { - this.mouseUp(); } public onMouseMove(e: MouseEvent): void { @@ -36,7 +43,6 @@ export class EditMode implements IInteractionMode { public onMouseLeave(e: MouseEvent): void { - this.mouseUp(); } public onMouseDblClick(e: MouseEvent): void { @@ -47,7 +53,6 @@ export class EditMode implements IInteractionMode { } public onContextMenu(e: MouseEvent): void { - this.mouseUp(); } public onWheel(e: WheelEvent): void { @@ -58,13 +63,5 @@ export class EditMode implements IInteractionMode { } - private mouseDown(): void { - this._mouseDown = true; - this._canvas.interactionLayer.style.cursor = "grabbing"; - } - private mouseUp(): void { - this._mouseDown = false; - this._canvas.interactionLayer.style.cursor = "grab"; - } } \ No newline at end of file diff --git a/src/js/services/HistoryService.ts b/src/js/services/HistoryService.ts new file mode 100644 index 0000000..8fe3f1b --- /dev/null +++ b/src/js/services/HistoryService.ts @@ -0,0 +1,41 @@ +import { service } from "../../lib/dependency-injection/js/DependencyInjection.js"; + + +export interface Undoable { + + pushState(data: D): void; + + getState(): D; + +} + +class Test { + test: number; + other: number; +} + +@service() +export class HistoryService { + + constructor() { + + } + + + public addHistoryGroup(): void { + + } + + public addHistory(): void { + + } + + public undo(times: number = 1): void { + + } + + public redo(times: number = 1): void { + + } + +} \ No newline at end of file diff --git a/src/js/services/PanelService.ts b/src/js/services/PanelService.ts index 71104a6..e3cb857 100644 --- a/src/js/services/PanelService.ts +++ b/src/js/services/PanelService.ts @@ -2,7 +2,7 @@ import { service } from "../../lib/dependency-injection/js/DependencyInjection.j import { IActionCommander } from "../../lib/action-commander/js/ActionCommander.js"; import { FlagOptionService } from "./FlagOptionService.js"; import { DataSourceCollection, SourceMode, SelectMode, IDataSource } from "../../lib/action-commander/js/services/DataSourceCollection.js"; -import { Subject, Observable, fromProperty } from "../../lib/observable/js/observable.js"; +import { Observable, fromProperty } from "../../lib/observable/js/observable.js"; @service() export class PanelService { @@ -51,7 +51,7 @@ export class PanelService { element.insertAdjacentHTML("afterbegin", /*html*/`

    ${name}

    - X +
    `) let dataSource = this._panelSource; diff --git a/src/js/services/PixelDrawingService.ts b/src/js/services/PixelDrawingService.ts new file mode 100644 index 0000000..f5a6107 --- /dev/null +++ b/src/js/services/PixelDrawingService.ts @@ -0,0 +1,20 @@ +import { service } from "../../lib/dependency-injection/js/DependencyInjection.js"; +import { ProjectService } from "./ProjectService.js"; + + +@service() +export class PixelDrawingService { + + private readonly _project: ProjectService; + + constructor(projectService: ProjectService) { + this._project = projectService; + } + + public activate(x: number, y: number) { + + console.log(x, y); + + } + +} \ No newline at end of file diff --git a/src/js/services/ProjectService.ts b/src/js/services/ProjectService.ts index 10ae697..bfeebae 100644 --- a/src/js/services/ProjectService.ts +++ b/src/js/services/ProjectService.ts @@ -21,10 +21,13 @@ export class ProjectService { constructor() { this._defaultLayerType = LayerType.Pixel; this._frames = []; + + //defaults this._selectedFrame = 0; this._selectedLayer = 0; this.addFrame("Frame 1"); + this.toggleFrameList(0); } private init() { @@ -219,7 +222,7 @@ export class ProjectService { public renameTitle(title: string, frameIndex: number, layerIndex?: number | null | undefined) {//TODO TEST - if (!layerIndex) { + if (typeof layerIndex !== "number") { this.getFrame(frameIndex).name = title; } else { this.getFrameLayer(frameIndex, layerIndex).name = title; diff --git a/src/js/services/VectorDrawingService.ts b/src/js/services/VectorDrawingService.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/js/webcomponents/customelement.ts b/src/js/webcomponents/customelement.ts new file mode 100644 index 0000000..aab074b --- /dev/null +++ b/src/js/webcomponents/customelement.ts @@ -0,0 +1,53 @@ +// import { fromEvent } from "../../lib/observable/js/observable.js"; + +// export class CustomElement extends HTMLElement { + +// protected state: S; + +// constructor() { +// super(); + +// // fromEvent(window, "ProtoPaint.State.Canvas", (e) => e.details).subscribe((_state) => { +// // this.setState(_state); +// // }); + +// window.addEventListener("ProtoPaint.State.Canvas", (e) => { + +// }); + +// } + +// public show(): void { +// this.classList.remove("hidden"); +// } + +// public hide(): void { +// this.classList.add("hidden"); +// } + +// public setState(newState: S): void { +// Object.entries(newState) +// .forEach(([k, value]) => { + +// let key: keyof S = k as unknown as any; + +// this.state[key] = this.isObject(this.state[key]) && this.isObject(value) ? { ...this.state[key], ...value } : value; + +// const bindKey = this.isObject(value) ? this.getBindKey(key, value) : key; +// // const bindKeys = this.isArray(bindKey) ? bindKey : [bindKey]; + +// // bindKeys.forEach(key => this.updateBindings(key, value)); +// }); + +// this.state = newState; +// } + +// private isObject(obj: any) { +// return Object.prototype.toString.call(obj) === '[object Object]'; +// } + +// private getBindKey(key: keyof S, obj: V): string[] { +// return Object.keys(obj).map((k: keyof V) => this.isObject(obj[k]) ? `${key}.${this.getBindKey(k, obj[k])}` : `${key}.${k}`); +// } + +// } \ No newline at end of file diff --git a/src/js/webcomponents/menu-container.ts b/src/js/webcomponents/menu-container.ts new file mode 100644 index 0000000..d8d7b28 --- /dev/null +++ b/src/js/webcomponents/menu-container.ts @@ -0,0 +1,257 @@ +import { WebComponent, attribute, initShadow } from "../helpers/webcomponent.js"; + +@WebComponent({ + selector: "menu-container", + attributes: ["resize", "title", "toggle", "height"], + template: /*html*/` + + + +
    + +
    + +` +}) +export class MenuContainerElement extends HTMLElement { + + @attribute("resize") + public side: string; + + @attribute("title") + public title: string; + + @attribute("height") + public height: string; + + private _dragging: boolean; + private readonly _dragElement: HTMLDivElement; + private readonly _containerElement: HTMLDivElement; + + private readonly _toggleElement: HTMLDivElement; + private readonly _titleElement: HTMLDivElement; + + private readonly _shadowRoot: ShadowRoot; + + constructor() { + super(); + + this._shadowRoot = initShadow(this); + + this._dragElement = document.createElement("div"); + + this._containerElement = this._shadowRoot.querySelector("div#container"); + this._titleElement = this._shadowRoot.querySelector("span#title"); + this._toggleElement = this._shadowRoot.querySelector("span#toggle"); + + this._dragging = false; + } + + public connectedCallback(): void { + this.addListeners(); + this.render(); + } + + public attributeChangedCallback(name: string, oldValue: string, newValue: string): void { + this.render(); + } + + public render(): void { + + if (this.height) { + this._containerElement.style.height = this.height; + } + + //If Title + if (this.title) { + this._titleElement.innerHTML = this.title; + } + + //If resizable + if (this.side) { + + this._dragElement.setAttribute("data-dragger", this.side); + this._dragElement.innerHTML = "
    "; + + if (this.side === "bottom") { + this._shadowRoot.appendChild(this._dragElement); + } else if (this.side === "top") { + this._shadowRoot.prepend(this._dragElement); + } else if (this.side === "left") { + //TODO + } else if (this.side === "right") { + //TODO + } + } + } + + private addListeners() { + + this._toggleElement.addEventListener("click", e => { + this.classList.toggle("closed"); + }, false); + + this._toggleElement.parentElement.addEventListener("dblclick", e => { + this.classList.toggle("closed"); + }, false) + + let startWidth: number, startHeight: number, startX: number, startY: number; + + this._dragElement.addEventListener("mousedown", (e) => { + e.preventDefault(); + let el = document.activeElement as HTMLElement; + el.blur(); + + startX = e.clientX; + startY = e.clientY; + startWidth = this._containerElement.offsetWidth; + startHeight = this._containerElement.offsetHeight; + + this._dragging = true; + }, false); + + document.addEventListener("mousemove", (e) => { + e.preventDefault(); + + if (this._dragging) { + + switch (this.side) { + case "top": + this._containerElement.style.height = (startHeight - (e.clientY - startY)) + 'px'; + break; + case "bottom": + this._containerElement.style.height = (startHeight + (e.clientY - startY)) + 'px'; + break; + case "right": + this._containerElement.style.width = (startWidth + (e.clientX - startX)) + 'px'; + break; + case "left": + this._containerElement.style.width = (startWidth - (e.clientX - startX)) + 'px'; + break; + } + } + + }, false); + + document.addEventListener("mouseup", (e) => { + e.preventDefault(); + if (this._dragging) + this._dragging = false; + }, false); + + } +} \ No newline at end of file diff --git a/src/js/webcomponents/menu-item.ts b/src/js/webcomponents/menu-item.ts index d244bbe..cd9a4bf 100644 --- a/src/js/webcomponents/menu-item.ts +++ b/src/js/webcomponents/menu-item.ts @@ -15,8 +15,6 @@ import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js" border-top: rgba(255,255,255,0.1) 1px solid; border-bottom: rgba(255,255,255,0.1) 1px solid; border-collapse: collapse; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; transition: 0.1s; } @@ -30,6 +28,7 @@ import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js" :host([selected="true"]){ background: rgba(255,255,255,0.2); + border-radius: 4px; } div#header{ @@ -49,7 +48,7 @@ import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js" span#arrow{ position: absolute; left: -15px; - padding: 0 4px 0 0; + top: 7px; margin: 0; transition: 0.2s; z-index: 100000; @@ -118,10 +117,29 @@ import { WebComponent, initShadow, attribute } from "../helpers/webcomponent.js" transition: 0.2s; } + .fa-layer-group{ + color: rgb(255, 255, 10) !important; + } + + .fa-eye{ + color: rgb(10,10,200) !important; + } + .fa-eye-slash{ + color: rgb(255, 5, 5) !important; + } + + .fa-trash-alt{ + color: rgb(255,5,5) !important; + } + + .fa-plus{ + color: rgb(5,255,5) !important; + } +