diff --git a/.gitmodules b/.gitmodules index dc85288f252..83c24e9a7d8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,15 @@ path = external/qooxdoo url = https://github.com/CometVisu/qooxdoo.git branch = cometvisu +[submodule "external/qx-osparc-theme"] + path = external/qx-osparc-theme + url = https://github.com/peuter/qx-osparc-theme.git +[submodule "external/qx-iconfont-material"] + path = external/qx-iconfont-material + url = https://github.com/peuter/qx-iconfont-material.git +[submodule "external/qx-contrib-dialog"] + path = external/qx-contrib-dialog + url = https://github.com/cboulanger/qx-contrib-Dialog.git +[submodule "external/qx-upload-manager"] + path = external/qx-upload-manager + url = https://github.com/johnspackman/UploadMgr.git diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 00000000000..5d77295cbfb --- /dev/null +++ b/.jshintignore @@ -0,0 +1 @@ +source/rest \ No newline at end of file diff --git a/.jshintrc b/.jshintrc index a4a7ee0896b..16b032193c6 100644 --- a/.jshintrc +++ b/.jshintrc @@ -16,6 +16,7 @@ "smarttabs": true, "multistr": true, "jasmine": true, + "worker": true, "globals": { "browser": false, "describe": false, @@ -47,6 +48,12 @@ "EVENT_RECORDER": true, "DOMWindow": false, "Favico": false, - "Sentry": true + "Sentry": true, + "osparc": true, + "monaco": true, + "CRC32": true, + "xmllint": true, + "dialog": true, + "com": true } } \ No newline at end of file diff --git a/config.json b/config.json index c457a9a071b..810f6f30ddc 100644 --- a/config.json +++ b/config.json @@ -36,7 +36,8 @@ "validate-config", "validate-manifest", "watch", - "profile" + "profile", + "make-font-map" ], "default-job" : "source-hybrid", @@ -100,7 +101,8 @@ "svg4everybody", "EVENT_RECORDER", "Favico", - "Sentry" + "Sentry", + "Promise" ] }, @@ -172,7 +174,23 @@ { "library" : [ - { "manifest" : "client/Manifest.json" } + { "manifest" : "client/Manifest.json" }, + { + "manifest" : "external/qx-iconfont-material/Manifest.json", + "uri" : "../external/qx-iconfont-material" + }, + { + "manifest" : "external/qx-osparc-theme/Manifest.json", + "uri" : "../external/qx-osparc-theme" + }, + { + "manifest" : "external/qx-contrib-dialog/Manifest.json", + "uri" : "../external/qx-contrib-dialog" + }, + { + "manifest" : "external/qx-upload-manager/Manifest.json", + "uri" : "../external/qx-upload-manager" + } ] }, @@ -198,6 +216,7 @@ { // "verifier-bombs-on-error" : false, // "separate-loader" : true, + "i18n-as-parts": true, "parts" : { "boot" : @@ -213,6 +232,10 @@ "include": [ "${APPLICATION}.ui.structure.pure.*" ] }, + "manager": { + "include": [ "${APPLICATION}.ui.manager.Main" ] + }, + "plugin-diagram" : { "include" : [ "${APPLICATION}.plugins.diagram.*" ] @@ -283,7 +306,7 @@ }, "plugin-openhab" : { - "include" : [ "${APPLICATION}.plugins.openhab.*", "${QXTHEME}" ] + "include" : [ "${APPLICATION}.plugins.openhab.*" ] } } } @@ -520,6 +543,30 @@ { "qx.aspects" : true } + }, + + "make-font-map" : + { + "desc" : "Build a font mapping from glyphname to unicode id", + + "let" : + { + "RESPATH" : "./external/qx-iconfont-material/source/resource", + "QXRESPATH" : "${QOOXDOO_PATH}/framework/source/resource" + }, + + "font-map" : + { + "fonts" : + { + "${RESPATH}/iconfont/material/MaterialIcons-Regular.ttf" : + { + "prefix": [ "${RESPATH}" ], + "alias" : "MaterialIcons", + "size" : 32 + } + } + } } } } diff --git a/external/qooxdoo b/external/qooxdoo index 69366cee89b..3dc93207238 160000 --- a/external/qooxdoo +++ b/external/qooxdoo @@ -1 +1 @@ -Subproject commit 69366cee89bca5972bf0b7350bfe85ec7f4f5ba0 +Subproject commit 3dc93207238ca2f5a3f05de6efdd912389915fe9 diff --git a/external/qx-contrib-dialog b/external/qx-contrib-dialog new file mode 160000 index 00000000000..d9f9c4f74b1 --- /dev/null +++ b/external/qx-contrib-dialog @@ -0,0 +1 @@ +Subproject commit d9f9c4f74b1e745bab0c3b5864bf52ae2500867a diff --git a/external/qx-iconfont-material b/external/qx-iconfont-material new file mode 160000 index 00000000000..de2cd99c35e --- /dev/null +++ b/external/qx-iconfont-material @@ -0,0 +1 @@ +Subproject commit de2cd99c35e7a45ed66ba66506011b99f5afa656 diff --git a/external/qx-osparc-theme b/external/qx-osparc-theme new file mode 160000 index 00000000000..8154f05a2dc --- /dev/null +++ b/external/qx-osparc-theme @@ -0,0 +1 @@ +Subproject commit 8154f05a2dc5fd1f2d844121036f51acc15f43da diff --git a/external/qx-upload-manager b/external/qx-upload-manager new file mode 160000 index 00000000000..66dfe2def73 --- /dev/null +++ b/external/qx-upload-manager @@ -0,0 +1 @@ +Subproject commit 66dfe2def73e673a7fcb7bb42043fee65cd267e8 diff --git a/package-lock.json b/package-lock.json index ee113538739..8709fcaefc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,63 +1,63 @@ { "name": "CometVisu", - "version": "0.11.0-dev", + "version": "0.12.0-dev", "lockfileVersion": 1, "requires": true, "dependencies": { "@sentry/browser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.3.4.tgz", - "integrity": "sha512-odRXxnhcSYzyR4YvTolNEyrz3fdDVw308l+9RBRJA9yOFVlezaz1mXH6Gv00F7cIj9yE/JtezDyhP339WsWy3w==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.4.2.tgz", + "integrity": "sha512-km1lf9jYlNTLDUAEoopisUA3+pa9+bYi7aXy8jR5OuDsLDo+mUACTXaRu62iNiEPgBtDO9dg8jz2ZhjwriNUug==", "requires": { - "@sentry/core": "4.3.4", - "@sentry/types": "4.3.4", - "@sentry/utils": "4.3.4", + "@sentry/core": "5.4.2", + "@sentry/types": "5.4.2", + "@sentry/utils": "5.4.2", "tslib": "^1.9.3" } }, "@sentry/core": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.3.4.tgz", - "integrity": "sha512-KwolQmAnXiFMeXBuxPUM8fW+2bOICdHfpjdf83qD7WSeuKqGvXhxXyApWNSLE+l2DPO6/8UKnIGmR8bEn0G7QA==", - "requires": { - "@sentry/hub": "4.3.4", - "@sentry/minimal": "4.3.4", - "@sentry/types": "4.3.4", - "@sentry/utils": "4.3.4", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.4.2.tgz", + "integrity": "sha512-B7AwuWKOziozLNXbgCXNHBminh4R+q/h19CSX7Cz0awiRKsKcuIK4iBsTd+b+tiKfkPYayxi337eZchdbg/rPQ==", + "requires": { + "@sentry/hub": "5.4.2", + "@sentry/minimal": "5.4.2", + "@sentry/types": "5.4.2", + "@sentry/utils": "5.4.2", "tslib": "^1.9.3" } }, "@sentry/hub": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.3.4.tgz", - "integrity": "sha512-vaBGCnhinLB8N4aQLMiPPhnlTkIUwU/dxWzw/xsuKY3MYWrmfMUyWgMZF60Mz3B4F0lW1lsg5jnJz9xPnjZowg==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.4.2.tgz", + "integrity": "sha512-2iS1TxiLsSj0Vc1QUw57uM8FDmVs7reYEwjCEX8+ihmemO2OoPpGeqsG9e3MRNcZp3RDkv87Pon8gOKrXhvOPA==", "requires": { - "@sentry/types": "4.3.4", - "@sentry/utils": "4.3.4", + "@sentry/types": "5.4.2", + "@sentry/utils": "5.4.2", "tslib": "^1.9.3" } }, "@sentry/minimal": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.3.4.tgz", - "integrity": "sha512-EBmQgdAQgxkhWFsBO4TmsP3cg5yTzg48HmPe3Dyt7PtF5Umw3DFW6qboAqnN1+KF+pHNuxkqevvgBTFp7b4Saw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.4.2.tgz", + "integrity": "sha512-9fVm/IZvC8Mxxp2vW5M9vCWlyP6V7Ba0qhEQ8PkUOC8MEKQUm0dFlEyPek2PdYueyi8+XHTk4txCHphzS/lJSg==", "requires": { - "@sentry/hub": "4.3.4", - "@sentry/types": "4.3.4", + "@sentry/hub": "5.4.2", + "@sentry/types": "5.4.2", "tslib": "^1.9.3" } }, "@sentry/types": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.3.4.tgz", - "integrity": "sha512-qsqrcyNilpbzYjqef+km0Grh5BckSFD4MUdJDNkUE5XU/ImniYddj18bMDlQxluJlTPDjUFQ37FXtEmxLeOwkQ==" + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.4.2.tgz", + "integrity": "sha512-yh1fd7x5lLOIZ8W3A1I792B3jowJVCWp4HcTRikjTsjbF8lcURY62m+hiLYUFPTIX99AlFRIPiApDkWiwMGYMA==" }, "@sentry/utils": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.3.4.tgz", - "integrity": "sha512-CMGMdIv5RHUCKRF4aWPZ/gFRTfBQpLVVJEGCeFGZLXHBdpgQac0lf3jlu8sND0KZ0S3C5x3tGS/eEqmOZRQ/pw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.4.2.tgz", + "integrity": "sha512-AW7/TGt2HiPQB8lJ8NgMgaFAIDQpKDF+wV8nENRbC1CP1zzcvb1QBF4zBL2auDT4fhkhVa817064s7vlDiJVLQ==", "requires": { - "@sentry/types": "4.3.4", + "@sentry/types": "5.4.2", "tslib": "^1.9.3" } }, @@ -74,9 +74,9 @@ "dev": true }, "@types/selenium-webdriver": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.13.tgz", - "integrity": "sha512-rI0LGoMiZGUM+tjDakQpwZOvcmQoubiJ7hxqrYU12VRxBuGGvOThxrBOU/QmJKlKg1WG6FMzuvcEyLffvVSsmw==", + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.15.tgz", + "integrity": "sha512-5nh8/K2u9p4bk95GGCJB7KBvewaB0TUziZ9DTr+mR2I6RoO4OJVqx7rxK83hs2J1tomwtCGkhiW+Dy8EUnfB+Q==", "dev": true }, "@types/semver": { @@ -123,9 +123,9 @@ } }, "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -169,6 +169,11 @@ "normalize-path": "^2.1.1" } }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "application-config": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/application-config/-/application-config-0.1.2.tgz", @@ -209,18 +214,18 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -231,12 +236,6 @@ "path-is-absolute": "^1.0.0" } }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -263,9 +262,9 @@ }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -282,12 +281,6 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -342,12 +335,6 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -418,9 +405,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-limiter": { @@ -590,9 +577,9 @@ } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bl": { @@ -640,35 +627,82 @@ }, "bluebird": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-1.0.3.tgz", "integrity": "sha1-xLRBGEgC47ZKYe7tRXgnG0yL9qw=", "dev": true }, "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "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.0.0", + "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "http-errors": { + "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": { - "safer-buffer": ">= 2.1.2 < 3" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "type-is": { + "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" } } } @@ -722,23 +756,12 @@ "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "browserstack": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.1.tgz", - "integrity": "sha512-O8VMT64P9NOLhuIoD4YngyxBURefaSdR4QdhG8l6HZ9VxtU7jc3m6jLufFwKA5gaf7fetfB2TnRJnMxyob+heg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.2.tgz", + "integrity": "sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg==", "dev": true, "requires": { "https-proxy-agent": "^2.2.1" @@ -782,16 +805,53 @@ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", "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==" + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true }, "cache-base": { @@ -875,24 +935,31 @@ } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", "dev": true, "requires": { "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", - "inherits": "^2.0.1", + "inherits": "^2.0.3", "is-binary-path": "^1.0.0", "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", + "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "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 + } } }, "chownr": { @@ -902,12 +969,6 @@ "dev": true, "optional": true }, - "circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -918,17 +979,6 @@ "define-property": "^0.2.5", "isobject": "^3.0.0", "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } } }, "cli-cursor": { @@ -947,12 +997,57 @@ "dev": true }, "coa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.1.tgz", - "integrity": "sha512-5wfTTO8E2/ja4jFSxePXlG5nRu5bBtL/r1HCIpJW/lzT6yDtKl0u0Z4o/Vpz32IpKmBn7HerheEZQgA9N2DarQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "dev": true, "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", "q": "^1.1.2" + }, + "dependencies": { + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "code-point-at": { @@ -998,15 +1093,6 @@ "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==", "dev": true }, - "combine-lists": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", - "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", - "dev": true, - "requires": { - "lodash": "^4.5.0" - } - }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -1032,9 +1118,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "component-inherit": { @@ -1061,6 +1147,17 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", @@ -1120,16 +1217,15 @@ "dev": true }, "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", "dev": true }, "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 + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "corser": { "version": "2.0.1", @@ -1356,6 +1452,15 @@ "buffer": "^5.1.0" } }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, "crc32-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", @@ -1487,9 +1592,9 @@ } }, "date-format": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", + "integrity": "sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==", "dev": true }, "dateformat": { @@ -1556,58 +1661,20 @@ }, "dependencies": { "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true } } }, "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-descriptor": "^0.1.0" } }, "del": { @@ -1662,6 +1729,38 @@ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "dev": true }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "divhide": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/divhide/-/divhide-2.0.1.tgz", @@ -1763,7 +1862,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -1775,7 +1874,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } @@ -1793,27 +1892,17 @@ "stream-shift": "^1.0.0" } }, - "each-async": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", - "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", - "dev": true, - "requires": { - "onetime": "^1.0.0", - "set-immediate-shim": "^1.0.0" - } - }, "easyimage": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/easyimage/-/easyimage-3.1.0.tgz", - "integrity": "sha512-yycLx61oU5UOmIR3pVrv1fkoMKHurR2vPo74+iHs2aLkTdvpco0oiCX/ljeuM6VcUocXx7jijWsAupWHRI1e7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/easyimage/-/easyimage-3.1.1.tgz", + "integrity": "sha512-W9QFelSdXjDK7ja0+jkDKwtJSrSggN/GDzgDY4+QguF9YElVkcbMZp64H8OinBI0ajow/h2p/MukdFOzpH1Mng==", "dev": true, "requires": { "bluebird": "^3.5.1", "mkdirp": "^0.5.0", "nanoid": "^1.0.2", "tslib": "^1.8.1", - "typescript": "^2.6.2" + "typescript": "^3.3.0" }, "dependencies": { "bluebird": { @@ -1835,9 +1924,9 @@ } }, "ecstatic": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.0.tgz", - "integrity": "sha512-EblWYTd+wPIAMQ0U4oYJZ7QBypT9ZUIwpqli0bKDjeIIQnXDBK2dXtZ9yzRCOlkW1HkO8gn7/FxLK1yPIW17pw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", "dev": true, "requires": { "he": "^1.1.1", @@ -1854,7 +1943,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -1913,8 +2002,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=" }, "encodeurl": { "version": "1.0.2", @@ -1975,6 +2063,12 @@ "yeast": "0.1.2" }, "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -2021,22 +2115,31 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -2045,9 +2148,9 @@ } }, "es6-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", - "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", "dev": true }, "es6-promisify": { @@ -2109,9 +2212,9 @@ } }, "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "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 }, "esutils": { @@ -2171,33 +2274,10 @@ "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, - "expand-braces": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", - "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", - "dev": true, - "requires": { - "array-slice": "^0.2.3", - "array-unique": "^0.2.1", - "braces": "^0.1.2" - }, - "dependencies": { - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", - "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", - "dev": true, - "requires": { - "expand-range": "^0.1.0" - } - } - } + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" }, "expand-brackets": { "version": "2.1.4", @@ -2212,50 +2292,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-range": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", - "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", - "dev": true, - "requires": { - "is-number": "^0.1.1", - "repeat-string": "^0.2.2" - }, - "dependencies": { - "is-number": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", - "dev": true - }, - "repeat-string": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", - "dev": true - } } }, "expand-template": { @@ -2272,24 +2308,12 @@ "dev": true }, "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "is-extendable": "^0.1.0" } }, "external-editor": { @@ -2348,15 +2372,6 @@ "is-descriptor": "^1.0.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -2448,17 +2463,6 @@ "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "finalhandler": { @@ -2518,6 +2522,12 @@ } } }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -2598,20 +2608,19 @@ "dev": true }, "fs-extra": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz", - "integrity": "sha1-M3NSve1KC3FPPrhN6M6nZenTdgA=", - "dev": true, + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "dependencies": { "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" } } }, @@ -2622,14 +2631,14 @@ "dev": true }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -2650,7 +2659,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -2674,7 +2683,7 @@ } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -2701,16 +2710,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -2759,7 +2768,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -2779,12 +2788,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -2845,16 +2854,16 @@ "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -2871,35 +2880,42 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -2916,13 +2932,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -2997,12 +3013,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -3032,16 +3048,16 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true }, @@ -3058,7 +3074,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -3109,17 +3125,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -3130,12 +3146,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -3144,16 +3160,16 @@ "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true } } }, "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -3265,7 +3281,7 @@ "dependencies": { "bl": { "version": "0.9.5", - "resolved": "http://registry.npmjs.org/bl/-/bl-0.9.5.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", "integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=", "dev": true, "requires": { @@ -3280,7 +3296,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -3292,7 +3308,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } @@ -3306,7 +3322,7 @@ }, "github-changes": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/github-changes/-/github-changes-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/github-changes/-/github-changes-1.0.2.tgz", "integrity": "sha1-ChJ2gBKi4mF7NBqqBJWiK9mu064=", "dev": true, "requires": { @@ -3323,13 +3339,13 @@ "dependencies": { "lodash": { "version": "2.4.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz", "integrity": "sha1-W3cjA03aTSYuWkb7LFjXzCL3FCA=", "dev": true }, "semver": { "version": "2.2.1", - "resolved": "http://registry.npmjs.org/semver/-/semver-2.2.1.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz", "integrity": "sha1-eUEYKz/8xYC/8cF5QqzfeVHA0hM=", "dev": true } @@ -3361,13 +3377,13 @@ }, "async": { "version": "0.2.10", - "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", "dev": true }, "combined-stream": { "version": "0.0.7", - "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", "dev": true, "requires": { @@ -3388,7 +3404,7 @@ }, "form-data": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/form-data/-/form-data-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.0.8.tgz", "integrity": "sha1-CJDNEAXFzOzAudJKiAUskkQtDbU=", "dev": true, "requires": { @@ -3416,7 +3432,7 @@ }, "mime": { "version": "1.2.11", - "resolved": "http://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=", "dev": true }, @@ -3428,13 +3444,13 @@ }, "qs": { "version": "0.6.6", - "resolved": "http://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=", "dev": true }, "request": { "version": "2.22.0", - "resolved": "http://registry.npmjs.org/request/-/request-2.22.0.tgz", + "resolved": "https://registry.npmjs.org/request/-/request-2.22.0.tgz", "integrity": "sha1-uIOnacxKkJVx61AEs0TEPPflFZI=", "dev": true, "requires": { @@ -3559,9 +3575,9 @@ "dev": true }, "grunt": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.3.tgz", - "integrity": "sha512-/JzmZNPfKorlCrrmxWqQO4JVodO+DVd5XX4DkocL/1WlLlKVLE9+SdEIempOAxDhWPysLle6afvn/hg7Ck2k9g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz", + "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==", "dev": true, "requires": { "coffeescript": "~1.10.0", @@ -3575,7 +3591,7 @@ "grunt-legacy-log": "~2.0.0", "grunt-legacy-util": "~1.1.1", "iconv-lite": "~0.4.13", - "js-yaml": "~3.5.2", + "js-yaml": "~3.13.0", "minimatch": "~3.0.2", "mkdirp": "~0.5.1", "nopt": "~3.0.6", @@ -3619,12 +3635,28 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" + }, + "dependencies": { + "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" + } + } } } } @@ -3718,25 +3750,17 @@ } }, "grunt-contrib-compress": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.4.3.tgz", - "integrity": "sha1-Ac7/ucY39S5wgfRjdQmD0KOw+nM=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.5.0.tgz", + "integrity": "sha512-RcCyetnvTJ7jvnDCSm05wOndAd00HWZTHeVGDVVmCM+K/PEivL0yx8vKyi8uzy0492l2dJgtzR0Ucid7roKg6A==", "dev": true, "requires": { "archiver": "^1.3.0", "chalk": "^1.1.1", - "iltorb": "^1.0.13", + "iltorb": "^1.3.10", "lodash": "^4.7.0", "pretty-bytes": "^4.0.2", "stream-buffers": "^2.1.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } } }, "grunt-contrib-connect": { @@ -3768,14 +3792,14 @@ } }, "grunt-contrib-uglify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.0.tgz", - "integrity": "sha512-vy3Vop2KDqdiwcGOGAjyKvjHFrRD/YK4KPQWR3Yt6OdYlgFw1z7HCuk66+IJ9s7oJmp9uRQXuuSHyawKRAgiMw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.1.tgz", + "integrity": "sha512-dwf8/+4uW1+7pH72WButOEnzErPGmtUvc8p08B0eQS/6ON0WdeQu0+WFeafaPTbbY1GqtS25lsHWaDeiTQNWPg==", "dev": true, "requires": { "chalk": "^2.4.1", "maxmin": "^2.1.0", - "uglify-js": "~3.4.8", + "uglify-js": "^3.5.0", "uri-path": "^1.0.0" }, "dependencies": { @@ -3789,9 +3813,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -3799,12 +3823,24 @@ "supports-color": "^5.3.0" } }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "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 + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3813,6 +3849,16 @@ "requires": { "has-flag": "^3.0.0" } + }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + } } } }, @@ -4027,9 +4073,9 @@ } }, "grunt-karma": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/grunt-karma/-/grunt-karma-3.0.1.tgz", - "integrity": "sha512-iNt1Qe5GoePMIfBQmeffvfrvnvwTfJ9/h9p9gqGMIuEdVsUo4PKhTxIwyW5NMbHrgD8p2UEdeTJH4l0QGz4YtA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/grunt-karma/-/grunt-karma-3.0.2.tgz", + "integrity": "sha512-imNhQO1bR1O7X6/3F5vO0o7mKy4xdkpSd40QVfxGO70cBAFcOqjv2Zu5QzsfEsSrppuu3N0vIQPbfBRjeGdpWg==", "dev": true, "requires": { "lodash": "^4.17.10" @@ -4150,9 +4196,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -4287,12 +4333,28 @@ "escape-string-regexp": "^1.0.5" } }, + "fs-extra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz", + "integrity": "sha1-M3NSve1KC3FPPrhN6M6nZenTdgA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0" + } + }, "fs-readdir-recursive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=", "dev": true }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, "inquirer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.1.tgz", @@ -4320,6 +4382,15 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -4378,26 +4449,78 @@ } }, "grunt-shell": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-2.1.0.tgz", - "integrity": "sha1-Q595FZ7RHmSmUaacyKPQK+v17MI=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-3.0.1.tgz", + "integrity": "sha512-C8eR4frw/NmIFIwSvzSLS4wOQBUzC+z6QhrKPzwt/tlaIqlzH35i/O2MggVOBj2Sh1tbaAqpASWxGiGsi4JMIQ==", "dev": true, "requires": { - "chalk": "^1.0.0", - "npm-run-path": "^2.0.0" + "chalk": "^2.4.1", + "npm-run-path": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "grunt-svgmin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/grunt-svgmin/-/grunt-svgmin-5.0.0.tgz", - "integrity": "sha1-8O4pOtFi++hcjD5o2xUt/3J3qCQ=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/grunt-svgmin/-/grunt-svgmin-6.0.0.tgz", + "integrity": "sha512-gSVIzJ9TNUDpsTpZELaAdBkQ5DRMios6SlFKc+S7XwUPFvqx8scCsiYTEiGLeYDEvE9+a2GGsSdJUd5ufIFlGQ==", "dev": true, "requires": { - "chalk": "^2.3.0", - "each-async": "^1.1.1", - "log-symbols": "^2.1.0", - "pretty-bytes": "^4.0.2", - "svgo": "^1.0.3" + "chalk": "^2.4.2", + "log-symbols": "^2.2.0", + "pretty-bytes": "^5.1.0", + "svgo": "^1.2.0" }, "dependencies": { "ansi-styles": { @@ -4410,9 +4533,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -4435,6 +4558,12 @@ "chalk": "^2.0.1" } }, + "pretty-bytes": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.2.0.tgz", + "integrity": "sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4505,55 +4634,22 @@ } }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" }, "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } - }, - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "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 - }, - "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" - } } } }, @@ -4666,7 +4762,7 @@ }, "hawk": { "version": "0.13.1", - "resolved": "http://registry.npmjs.org/hawk/-/hawk-0.13.1.tgz", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-0.13.1.tgz", "integrity": "sha1-NheViCH1gxHk1/beKR/KZitBLvQ=", "dev": true, "requires": { @@ -4684,7 +4780,7 @@ }, "hoek": { "version": "0.8.5", - "resolved": "http://registry.npmjs.org/hoek/-/hoek-0.8.5.tgz", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.8.5.tgz", "integrity": "sha1-Hp/XcO9+vgJ0rfy1sIBqAlpeTp8=", "dev": true }, @@ -4906,9 +5002,9 @@ } }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "iltorb": { @@ -4969,14 +5065,12 @@ "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=" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { "version": "0.11.4", @@ -5021,7 +5115,7 @@ }, "is": { "version": "0.2.7", - "resolved": "http://registry.npmjs.org/is/-/is-0.2.7.tgz", + "resolved": "https://registry.npmjs.org/is/-/is-0.2.7.tgz", "integrity": "sha1-OzSixI81mXLzUEKEkZOucmS2NWI=", "dev": true }, @@ -5135,9 +5229,9 @@ } }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "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" @@ -5282,8 +5376,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isbinaryfile": { "version": "3.0.3", @@ -5340,15 +5433,6 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "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" - } - }, "async": { "version": "1.5.2", "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -5396,9 +5480,9 @@ } }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "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", @@ -5506,9 +5590,9 @@ } }, "jasmine-core": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.3.0.tgz", - "integrity": "sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", "dev": true }, "jasminewd2": { @@ -5566,13 +5650,13 @@ } }, "js-yaml": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", - "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", + "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.2", - "esprima": "^2.6.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -5614,10 +5698,9 @@ "dev": true }, "jsonfile": { - "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { "graceful-fs": "^4.1.6" }, @@ -5626,7 +5709,6 @@ "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, "optional": true } } @@ -5650,80 +5732,39 @@ } }, "jszip": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", - "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.0.tgz", + "integrity": "sha512-4WjbsaEtBK/DHeDZOPiPw5nzSGLDEDDreFRDEgnoMwmknPjTqa+23XuYFk6NiGbeiAeZCctiQ/X/z0lQBmDVOQ==", "dev": true, "requires": { - "core-js": "~2.3.0", - "es6-promise": "~3.0.2", - "lie": "~3.1.0", + "lie": "~3.3.0", "pako": "~1.0.2", - "readable-stream": "~2.0.6" - }, - "dependencies": { - "core-js": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", - "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", - "dev": true - }, - "es6-promise": { - "version": "3.0.2", - "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" } }, "karma": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/karma/-/karma-3.1.1.tgz", - "integrity": "sha512-NetT3wPCQMNB36uiL9LLyhrOt8SQwrEKt0xD3+KpTCfm0VxVyUJdPL5oTq2Ic5ouemgL/Iz4wqXEbF3zea9kQQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", + "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", "dev": true, "requires": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", + "braces": "^2.3.2", "chokidar": "^2.0.3", "colors": "^1.1.0", - "combine-lists": "^1.0.0", "connect": "^3.6.0", "core-js": "^2.2.0", "di": "^0.0.1", "dom-serialize": "^2.2.0", - "expand-braces": "^0.1.1", + "flatted": "^2.0.0", "glob": "^7.1.1", "graceful-fs": "^4.1.2", "http-proxy": "^1.13.0", "isbinaryfile": "^3.0.0", - "lodash": "^4.17.4", - "log4js": "^3.0.0", + "lodash": "^4.17.11", + "log4js": "^4.0.0", "mime": "^2.3.1", "minimatch": "^3.0.2", "optimist": "^0.6.1", @@ -5734,19 +5775,19 @@ "socket.io": "2.1.1", "source-map": "^0.6.1", "tmp": "0.0.33", - "useragent": "2.2.1" + "useragent": "2.3.0" }, "dependencies": { "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", "dev": true }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -5764,9 +5805,9 @@ "dev": true }, "mime": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", - "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, "minimatch": { @@ -5779,12 +5820,12 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "source-map": { @@ -5792,15 +5833,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } } } }, @@ -5844,15 +5876,6 @@ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "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" - } - }, "async": { "version": "1.5.2", "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -5948,9 +5971,9 @@ } }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "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", @@ -6119,9 +6142,9 @@ } }, "lie": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", - "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, "requires": { "immediate": "~3.0.5" @@ -6161,14 +6184,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.isfinite": { "version": "3.3.2", @@ -6198,31 +6214,31 @@ } }, "log4js": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-3.0.6.tgz", - "integrity": "sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.3.2.tgz", + "integrity": "sha512-72GjgSP+ifL156MD/bXEhE7UlFLKS2KkCXujodb1nl1z6PpKhCfS+41dyNQ7zKi4iM49TQl+aWLEISXGLcGCCQ==", "dev": true, "requires": { - "circular-json": "^0.5.5", - "date-format": "^1.2.0", - "debug": "^3.1.0", + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", "rfdc": "^1.1.2", - "streamroller": "0.7.0" + "streamroller": "^1.0.5" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "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==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -6296,8 +6312,7 @@ "media-typer": { "version": "0.3.0", "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { "version": "1.1.0", @@ -6355,6 +6370,64 @@ "to-regex": "^3.0.2" }, "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -6372,14 +6445,12 @@ "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "dev": true + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" }, "mime-types": { "version": "2.1.21", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dev": true, "requires": { "mime-db": "~1.37.0" } @@ -6410,8 +6481,7 @@ "minimist": { "version": "0.0.8", "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mixin-deep": { "version": "1.3.1", @@ -6438,21 +6508,20 @@ "version": "0.5.1", "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } }, "moment": { "version": "2.5.1", - "resolved": "http://registry.npmjs.org/moment/-/moment-2.5.1.tgz", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.5.1.tgz", "integrity": "sha1-cUajkAUzBkynmdXnkvTkgO4Ogrw=", "dev": true }, "monaco-editor": { - "version": "0.15.6", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.15.6.tgz", - "integrity": "sha512-JoU9V9k6KqT9R9Tiw1RTU8ohZ+Xnf9DMg6Ktqqw5hILumwmq7xqa/KLXw513uTUsWbhtnHoSJYYR++u3pkyxJg==" + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.17.0.tgz", + "integrity": "sha512-8BQQHCFxy3DF0GYFOy5BmcCWlwm/XaTMPbPbN4gwItFGctZErSfX82uQSBpojJSlPNyudB5Q5qnukoorD3/UuA==" }, "morgan": { "version": "1.9.1", @@ -6473,6 +6542,21 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "multer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.1.tgz", + "integrity": "sha512-zzOLNRxzszwd+61JFuAo0fxdQfvku12aNJgnla0AQ+hHxFmfc/B7jBVuPr5Rmvu46Jze/iJrFpSOsD7afO8SDw==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, "mustache": { "version": "2.3.0", "resolved": "http://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", @@ -6517,6 +6601,64 @@ "to-regex": "^3.0.1" }, "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -6531,10 +6673,16 @@ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", "dev": true }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "node-abi": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.0.tgz", - "integrity": "sha512-9g2twBGSP6wIR5PW7tXvAWnEWKJDH/VskdXp168xsw9VVxpEGov8K4jsP4/VeoC7b2ZAyzckvMCuQuQlw44lXg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz", + "integrity": "sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA==", "dev": true, "optional": true, "requires": { @@ -6542,9 +6690,9 @@ }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true, "optional": true } @@ -6572,9 +6720,9 @@ }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "optional": true, "requires": { @@ -6603,16 +6751,6 @@ "brace-expansion": "^1.1.7" } }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "optional": true, - "requires": { - "abbrev": "1" - } - }, "semver": { "version": "5.3.0", "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -6656,7 +6794,7 @@ "dependencies": { "colors": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", "dev": true } @@ -6750,8 +6888,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-component": { "version": "0.0.3", @@ -6768,17 +6905,6 @@ "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } } }, "object-keys": { @@ -6821,22 +6947,21 @@ } }, "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" } }, "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" } @@ -6965,9 +7090,9 @@ "dev": true }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parse-json": { @@ -7214,11 +7339,15 @@ "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", "dev": true }, + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "proto-list": { "version": "1.2.4", @@ -7227,12 +7356,11 @@ "dev": true }, "protractor": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.1.tgz", - "integrity": "sha512-ORey5ewQMYiXQxcQohsqEiKYOg/r5yJoJbt0tuROmmgajdg/CA3gTOZNIFJncUVMAJIk5YFqBBLUjKVmQO6tfA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.2.tgz", + "integrity": "sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA==", "dev": true, "requires": { - "@types/node": "^6.0.46", "@types/q": "^0.0.32", "@types/selenium-webdriver": "^3.0.0", "blocking-proxy": "^1.0.0", @@ -7286,12 +7414,12 @@ "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "semver": { @@ -7300,19 +7428,10 @@ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, "webdriver-manager": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.0.tgz", - "integrity": "sha512-oEc5fmkpz6Yh6udhwir5m0eN5mgRPq9P/NU5YWuT3Up5slt6Zz+znhLU7q4+8rwCZz/Qq3Fgpr/4oao7NPCm2A==", + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.1.tgz", + "integrity": "sha512-L9TEQmZs6JbMMRQI1w60mfps265/NCr0toYJl7p/R2OAk6oXAfwI6jqYP7EWae+d7Ad2S2Aj4+rzxoSjqk3ZuA==", "dev": true, "requires": { "adm-zip": "^0.4.9", @@ -7339,8 +7458,7 @@ "psl": { "version": "1.1.29", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", - "dev": true + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, "pump": { "version": "2.0.1", @@ -7390,25 +7508,41 @@ "dev": true }, "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "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.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "http-errors": { + "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": { - "safer-buffer": ">= 2.1.2 < 3" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true } } }, @@ -7489,7 +7623,6 @@ "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7556,6 +7689,27 @@ "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "remove-trailing-separator": { @@ -7604,6 +7758,24 @@ "uuid": "^3.3.2" } }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7651,9 +7823,9 @@ "dev": true }, "rfdc": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.2.tgz", - "integrity": "sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", "dev": true }, "rimraf": { @@ -7686,8 +7858,7 @@ "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==" }, "safe-regex": { "version": "1.1.0", @@ -7755,12 +7926,21 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" + } + }, + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" } } } @@ -7849,17 +8029,6 @@ "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "setimmediate": { @@ -7891,7 +8060,7 @@ }, "shelljs": { "version": "0.5.3", - "resolved": "http://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", "integrity": "sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=", "dev": true }, @@ -8013,26 +8182,6 @@ "source-map": "^0.5.6", "source-map-resolve": "^0.5.0", "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } } }, "snapdragon-node": { @@ -8171,6 +8320,12 @@ "to-array": "0.1.4" }, "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -8193,6 +8348,12 @@ "isarray": "2.0.1" }, "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -8229,6 +8390,15 @@ "urix": "^0.1.0" } }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -8283,6 +8453,27 @@ "dev": true, "requires": { "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } } }, "sprintf-js": { @@ -8322,17 +8513,6 @@ "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } } }, "statuses": { @@ -8341,6 +8521,11 @@ "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", "dev": true }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "stream-browserify": { "version": "2.0.1", "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -8364,17 +8549,27 @@ "dev": true }, "streamroller": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.5.tgz", + "integrity": "sha512-iGVaMcyF5PcUY0cPbW3xFQUXnr9O4RZXNBBjhuLZgrjLO4XCLLGfx4T2sGqygSeylUjwgWRsnNbT9aV0Zb8AYw==", "dev": true, "requires": { - "date-format": "^1.2.0", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.11" }, "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -8384,14 +8579,36 @@ "ms": "^2.1.1" } }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, "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==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -8416,7 +8633,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -8480,32 +8696,46 @@ "dev": true }, "svgo": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.1.1.tgz", - "integrity": "sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.2.tgz", + "integrity": "sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA==", "dev": true, "requires": { - "coa": "~2.0.1", - "colors": "~1.1.2", + "chalk": "^2.4.1", + "coa": "^2.0.2", "css-select": "^2.0.0", - "css-select-base-adapter": "~0.1.0", + "css-select-base-adapter": "^0.1.1", "css-tree": "1.0.0-alpha.28", "css-url-regex": "^1.1.0", - "csso": "^3.5.0", - "js-yaml": "^3.12.0", + "csso": "^3.5.1", + "js-yaml": "^3.13.1", "mkdirp": "~0.5.1", - "object.values": "^1.0.4", + "object.values": "^1.1.0", "sax": "~1.2.4", - "stable": "~0.1.6", + "stable": "^0.1.8", "unquote": "~1.1.1", "util.promisify": "~1.0.0" }, "dependencies": { - "colors": { - "version": "1.1.2", - "resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, "css-select": { "version": "2.0.2", @@ -8539,33 +8769,32 @@ "domelementtype": "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==", + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "has-flag": "^3.0.0" } } } }, "tar": { - "version": "2.2.1", - "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "dev": true, "optional": true, "requires": { "block-stream": "*", - "fstream": "^1.0.2", + "fstream": "^1.0.12", "inherits": "2" } }, @@ -8624,7 +8853,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -8640,7 +8869,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -8652,7 +8881,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } @@ -8668,12 +8897,12 @@ } }, "tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "~1.0.1" + "os-tmpdir": "~1.0.2" } }, "to-array": { @@ -8707,6 +8936,72 @@ "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" + }, + "dependencies": { + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } } }, "to-regex-range": { @@ -8719,11 +9014,16 @@ "repeat-string": "^1.6.1" } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -8732,8 +9032,7 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, @@ -8776,39 +9075,46 @@ "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.18" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "version": "3.3.3333", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz", + "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", "dev": true }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, + "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true }, "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 + "dev": true, + "optional": true } } }, @@ -8820,7 +9126,7 @@ }, "underscore": { "version": "1.4.4", - "resolved": "http://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", "dev": true }, @@ -8863,15 +9169,6 @@ "set-value": "^0.4.3" }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, "set-value": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", @@ -8886,6 +9183,11 @@ } } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -8939,9 +9241,9 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "uri-js": { @@ -8996,19 +9298,29 @@ "dev": true }, "useragent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", - "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", "dev": true, "requires": { - "lru-cache": "2.2.x", + "lru-cache": "4.1.x", "tmp": "0.0.x" }, "dependencies": { "lru-cache": { - "version": "2.2.4", - "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", - "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true } } @@ -9033,8 +9345,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.0", @@ -9184,16 +9495,14 @@ "requires": { "sax": ">=0.6.0", "xmlbuilder": "~9.0.1" - }, - "dependencies": { - "xmlbuilder": { - "version": "9.0.7", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - } } }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", @@ -9203,8 +9512,7 @@ "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { "version": "3.2.1", @@ -9251,14 +9559,6 @@ "compress-commons": "^1.2.0", "lodash": "^4.8.0", "readable-stream": "^2.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } } } } diff --git a/package.json b/package.json index e62f7e1247c..a979e64a8ce 100644 --- a/package.json +++ b/package.json @@ -20,42 +20,47 @@ ], "devDependencies": { "csso": "^3.5.1", - "easyimage": "^3.1.0", - "grunt": "^1.0.3", + "easyimage": "^3.1.1", + "grunt": "^1.0.4", "grunt-banner": "^0.6.0", "grunt-bump": "^0.8.0", "grunt-chmod": "latest", "grunt-contrib-clean": "^2.0.0", - "grunt-contrib-compress": "^1.0.0", + "grunt-contrib-compress": "^1.5.0", "grunt-contrib-connect": "^2.0.0", - "grunt-contrib-uglify": "^4.0.0", + "grunt-contrib-uglify": "^4.0.1", "grunt-file-creator": "^0.1.3", "grunt-github-changes": "latest", "grunt-github-releaser": "^0.1.18", "grunt-http-server": "^2.1.0", - "grunt-karma": "^3.0.1", + "grunt-karma": "^3.0.2", "grunt-karma-coveralls": "^2.5.4", "grunt-prompt": "^1.3.3", "grunt-protractor-runner": "^5.0.0", "grunt-scaffold": "^0.7.0", - "grunt-shell": "^2.1.0", - "grunt-svgmin": "^5.0.0", + "grunt-shell": "^3.0.1", + "grunt-svgmin": "^6.0.0", "grunt-svgstore": "latest", - "jasmine-core": "^3.3.0", + "jasmine-core": "^3.4.0", "jshint-stylish": "^2.1.0", - "karma": "^3.1.1", + "karma": "^4.1.0", "karma-chrome-launcher": "^2.0.0", "karma-coverage": "^1.1.1", "karma-firefox-launcher": "^1.0.0", "karma-jasmine": "^2.0.1", "karma-qooxdoo": "^0.6.0", "karma-spec-reporter": "0.0.32", - "protractor": "^5.3.0", - "request": "^2.69.0", + "protractor": "^5.4.2", + "request": "^2.88.0", "svgmin": "^0.1.0" }, "dependencies": { - "@sentry/browser": "^4.0.4", - "monaco-editor": "^0.15.6" + "@sentry/browser": "^5.4.2", + "crc-32": "^1.2.0", + "fs-extra": "^8.0.1", + "ini": "^1.3.5", + "monaco-editor": "^0.17.0", + "multer": "^1.4.1", + "request-promise-native": "^1.0.7" } } diff --git a/source/class/cv/Application.js b/source/class/cv/Application.js index 55f26db85a8..10c3f733192 100644 --- a/source/class/cv/Application.js +++ b/source/class/cv/Application.js @@ -34,6 +34,20 @@ qx.Class.define("cv.Application", { extend : qx.application.Native, + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this.initCommandManager(new qx.ui.command.GroupManager()); + var lang = qx.locale.Manager.getInstance().getLanguage(); + if (qx.io.PartLoader.getInstance().hasPart(lang)) { + qx.io.PartLoader.require([lang]); + } + }, + /* ****************************************************** STATICS @@ -42,6 +56,7 @@ qx.Class.define("cv.Application", statics: { HTML_STRUCT: '

', consoleCommands: [], + __commandManager: null, /** * Client factory method -> create a client @@ -93,6 +108,11 @@ qx.Class.define("cv.Application", check: 'Boolean', init: false, event: 'changeStructureLoaded' + }, + + commandManager: { + check: 'qx.ui.command.GroupManager', + deferredInit: true } }, @@ -157,6 +177,14 @@ qx.Class.define("cv.Application", console.log(info); + // add command to load and open the manager + var manCommand = new qx.ui.command.Command('Ctrl+M'); + cv.TemplateEngine.getInstance().getCommands().add("open-manager", manCommand); + manCommand.addListener('execute', this.showManager, this); + if (cv.Config.request.queryKey.manager) { + this.showManager(); + } + if (qx.core.Environment.get("qx.aspects")) { qx.dev.Profile.stop(); qx.dev.Profile.start(); @@ -190,6 +218,12 @@ qx.Class.define("cv.Application", this.__init(); }, + showManager: function () { + qx.io.PartLoader.require(['manager'], function (states) { + cv.ui.manager.Main.getInstance(); + }, this); + }, + __globalErrorHandler: function(ex) { // connect client data for Bug-Report var bugData = cv.report.Record.getClientData(); diff --git a/source/class/cv/Config.js b/source/class/cv/Config.js index d9637c7a6f2..a0329234a73 100644 --- a/source/class/cv/Config.js +++ b/source/class/cv/Config.js @@ -266,6 +266,9 @@ qx.Class.define('cv.Config', { cv.Config.startpage = req.queryKey.startpage; } + // store for later usage + cv.Config.request = req; + if (qx.core.Environment.get('cv.testMode') !== false) { cv.Config.testMode = true; if (qx.core.Environment.get('cv.testMode') !== "true") { diff --git a/source/class/cv/TemplateEngine.js b/source/class/cv/TemplateEngine.js index d941c889992..852d4439689 100644 --- a/source/class/cv/TemplateEngine.js +++ b/source/class/cv/TemplateEngine.js @@ -36,7 +36,15 @@ qx.Class.define('cv.TemplateEngine', { }, this); this.defaults = {widget: {}, plugin: {}}; - this.setCommands(new qx.ui.command.Group()); + var group = new qx.ui.command.Group(); + this.setCommands(group); + var app = qx.core.Init.getApplication(); + if (app) { + // application is not available in tests + var manager = app.getCommandManager(); + manager.add(group); + manager.setActive(group); + } }, properties: { diff --git a/source/class/cv/io/rest/Client.js b/source/class/cv/io/rest/Client.js new file mode 100644 index 00000000000..a59e86b3d97 --- /dev/null +++ b/source/class/cv/io/rest/Client.js @@ -0,0 +1,196 @@ +/** + * + */ +qx.Class.define('cv.io.rest.Client', { + type: 'static', + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + BASE_URL: 'http://localhost:3000', + __configFile: null, + __dirClient: null, + __dpClient: null, + __callbacks: {}, + + getConfigClient: function() { + if (!this.__configFile) { + this.__configFile = new qx.io.rest.Resource({ + get: { + method: 'GET', url: '/config/hidden/{section}/{key}' + }, + put: { + method: 'PUT', url: '/config/hidden/{section}/{key}' + }, + post: { + method: 'POST', url: '/config/hidden/{section}/{key}' + }, + "delete": { + method: 'DELETE', url: '/config/hidden/{section}/{key}' + }, + save: { + method: 'PUT', url: '/config/hidden' + } + }); + this.__configFile.setBaseUrl(this.BASE_URL); + this.__configFile.configureRequest(function (req, action) { + if (action === 'save') { + req.setRequestHeader('Content-Type', 'application/json'); + } + if (action === 'get') { + req.setAccept('text/xml'); + } else { + req.setAccept('application/json'); + } + }); + } + return this.__configFile; + }, + + getFsClient: function () { + if (!this.__dirClient) { + var config = { + read: { + method: 'GET', url: '/fs?path={path}' + }, + update: { + method: 'PUT', url: '/fs?path={path}' + }, + create: { + method: 'POST', url: '/fs?path={path}&type={type}' + }, + "delete": { + method: 'DELETE', url: '/fs?path={path}&force={force}' + }, + move: { + method: 'PUT', url: '/fs/move?src={src}&target={target}' + }, + checkEnvironment: { + method: 'GET', url: '/fs/check' + } + }; + this.__dirClient = new qx.io.rest.Resource(config); + this.__dirClient.setBaseUrl(this.BASE_URL); + this.__dirClient.configureRequest(function (req, action, params) { + if (params.hash) { + req.setUrl(req.getUrl() + '&hash=' + params.hash); + } + if (params.recursive === true && action === 'read') { + req.setUrl(req.getUrl() + '&recursive=true'); + } + if (action === 'update' || action === 'create') { + var parts = params.path.split('.'); + if (parts.length > 1) { + var type = parts.pop(); + var mimetype = cv.ui.manager.tree.FileSystem.getMimetypeFromSuffix(type); + req.setRequestHeader('Content-Type', mimetype || 'text/plain'); + } else { + req.setRequestHeader('Content-Type', 'text/plain'); + } + req.setAccept('application/json'); + } + }); + + + this._enableSync(this.__dirClient, config); + + // general listeners + this.__dirClient.addListener('updateSuccess', this._onSaveSuccess, this); + this.__dirClient.addListener('createSuccess', this._onSaveSuccess, this); + this.__dirClient.addListener('updateError', this._onSaveError, this); + this.__dirClient.addListener('createError', this._onSaveError, this); + } + return this.__dirClient; + }, + + getDataProviderClient: function () { + if (!this.__dpClient) { + var config = { + designs: { + method: 'GET', url: '/data/designs' + }, + rrds: { + method: 'GET', url: '/data/rrds' + }, + influxdbs: { + method: 'GET', url: '/data/influxdbs?auth={auth}' + }, + influxdbfields: { + method: 'GET', url: '/data/influxdbfields?auth={auth}&measurement={measurement}' + }, + influxdbtags: { + method: 'GET', url: '/data/influxdbtags?auth={auth}&measurement={measurement}' + } + }; + this.__dpClient = new qx.io.rest.Resource(config); + this.__dpClient.setBaseUrl(this.BASE_URL); + + this._enableSync(this.__dpClient, config); + } + return this.__dpClient; + }, + + _enableSync: function (client, config) { + // install the callback calls + Object.keys(config).forEach(function (callName) { + client[callName + 'Sync'] = function () { + var args = qx.lang.Array.fromArguments(arguments); + var callback; + var context = args.pop(); + if (qx.lang.Type.isFunction(context)) { + callback = context; + context = this; + } else { + callback = args.pop(); + } + this.__callbacks[client[callName].apply(client, args)] = callback.bind(context); + }.bind(this); + }, this); + + // add the general listeners + client.addListener('success', function (ev) { + var req = ev.getRequest(); + var id = parseInt(req.toHashCode(), 10); + if (this.__callbacks.hasOwnProperty(id)) { + this.__callbacks[id](null, ev.getData()); + delete this.__callbacks[id]; + } + }, this); + + client.addListener('error', function (ev) { + var req = ev.getRequest(); + var id = parseInt(req.toHashCode(), 10); + if (this.__callbacks.hasOwnProperty(id)) { + qx.log.Logger.error(this, ev.getData()); + this.__callbacks[id](ev.getData().message, null); + delete this.__callbacks[id]; + } + if (req.getPhase() === 'load') { + // error during load phase => backend not reachable + dialog.Dialog.error(qx.locale.Manager.tr('Backend does not respond!')); + } + }, this); + }, + + _onSaveSuccess: function (ev) { + var req = ev.getRequest(); + var id = parseInt(req.toHashCode(), 10); + // only handle this events, when there is no callback for it + if (!this.__callbacks.hasOwnProperty(id)) { + cv.ui.manager.snackbar.Controller.info(qx.locale.Manager.tr('File has been saved')); + } + }, + + _onSaveError: function (ev) { + var req = ev.getRequest(); + var id = parseInt(req.toHashCode(), 10); + // only handle this events, when there is no callback for it + if (!this.__callbacks.hasOwnProperty(id)) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('Error saving file')); + } + } + } +}); diff --git a/source/class/cv/plugins/openhab/Openhab.js b/source/class/cv/plugins/openhab/Openhab.js index 8c06dd46c0f..05f9c9866f6 100644 --- a/source/class/cv/plugins/openhab/Openhab.js +++ b/source/class/cv/plugins/openhab/Openhab.js @@ -42,16 +42,18 @@ qx.Class.define("cv.plugins.openhab.Openhab", { */ construct: function () { this.base(arguments); + if (!cv.Config.request.queryKey.hasOwnProperty('preview')) { - this.__notificationRouter = cv.core.notifications.Router.getInstance(); + this.__notificationRouter = cv.core.notifications.Router.getInstance(); - // listen to notifications - var client = cv.TemplateEngine.getInstance().visu; - var sse = client.getCurrentTransport && client.getCurrentTransport(); - if (sse) { - sse.subscribe("notifications", this._onNotification, this); + // listen to notifications + var client = cv.TemplateEngine.getInstance().visu; + var sse = client.getCurrentTransport && client.getCurrentTransport(); + if (sse) { + sse.subscribe("notifications", this._onNotification, this); + } + cv.TemplateEngine.getInstance().executeWhenDomFinished(this._createSettings, this); } - cv.TemplateEngine.getInstance().executeWhenDomFinished(this._createSettings, this); }, /* diff --git a/source/class/cv/svg/Element.js b/source/class/cv/svg/Element.js new file mode 100644 index 00000000000..7f5b87dcfc1 --- /dev/null +++ b/source/class/cv/svg/Element.js @@ -0,0 +1,31 @@ +qx.Class.define("cv.svg.Element", { + extend: qx.html.Element, + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function (tagName) { + this.base(arguments); + this.__svgElement = document.createElementNS("http://www.w3.org/2000/svg", tagName); + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _createDomElement : function() { + return this.__svgElement; + }, + getDomElement : function() { + return this.__svgElement; + } + }, + + destruct : function() { + this.__svgElement.$$widget = null; + this.__svgElement = null; + } +}); diff --git a/source/class/cv/theme/dark/Appearance.js b/source/class/cv/theme/dark/Appearance.js index 8009d722097..b276cff0d57 100644 --- a/source/class/cv/theme/dark/Appearance.js +++ b/source/class/cv/theme/dark/Appearance.js @@ -20,9 +20,378 @@ qx.Theme.define("cv.theme.dark.Appearance", { - extend : qx.theme.simple.Appearance, + extend : osparc.theme.osparcdark.Appearance, appearances : { + 'cv-start': 'widget', + 'cv-start/configs-header': { + style: function () { + return { + margin: [20, 10, 0, 10], + decorator: 'cv-start-section-title' + }; + } + }, + 'cv-start/configs-title': { + style: function () { + return { + iconPosition: 'right', + font: 'title', + marginLeft: 10, + allowGrowX: true + }; + } + }, + 'cv-start/configs-toolbar': { + style: function () { + return { + }; + } + }, + 'cv-start/misc-title': { + style: function () { + return { + iconPosition: 'right', + font: 'title', + margin: [20, 10, 0, 10], + paddingTop: 5, + cursor: 'pointer', + allowGrowX: true, + decorator: 'cv-start-section-title' + }; + } + }, + 'cv-start/demo-configs-title': 'cv-start/misc-title', + 'cv-start/media-title': 'cv-start/configs-title', + 'cv-start/media-toolbar': 'cv-start/configs-toolbar', + 'cv-start/media-header': 'cv-start/configs-header', + + 'cv-file-item': { + include: 'listitem', + alias: 'listitem', + + style: function () { + return { + iconPosition: 'top', + font: 'small', + width: 130 + }; + } + }, + 'cv-file-item/atom/icon': { + include: 'atom/icon', + style: function () { + return { + width: 70, + height: 70, + scale: true + }; + } + }, + 'cv-file-item/action-menu': 'menu', + 'cv-file-item/download-button': { + include: 'button', + alias: 'button', + + style: function () { + return { + height: 30, + show: 'icon' + }; + } + }, + 'cv-file-item/action-button': 'cv-file-item/download-button', + 'cv-file-item/open-button': 'cv-file-item/download-button', + 'cv-icon': 'cv-file-item', + 'cv-icon/icon': { + include: 'atom/icon', + style: function () { + return { + width: 70, + height: 70 + }; + } + }, + 'cv-file-item-add-file': { + include: 'cv-file-item', + alias: 'cv-file-item', + + style: function (states) { + return { + decorator: 'cv-file-item-add-file', + opacity: states.hovered ? 1.0 : 0.5, + cursor: 'pointer' + }; + } + }, + 'open-file-item': { + alias: "atom", + + style: function (states) { + var padding = [2, 5, 2, 5]; + if (states.lead) { + padding = [1, 4, 1, 4]; + } + if (states.dragover) { + padding[2] -= 1; + } + + var backgroundColor; + if (states.selected) { + backgroundColor = "background-selected"; + if (states.disabled) { + backgroundColor += "-disabled"; + } + } + return { + backgroundColor: backgroundColor, + textColor: states.selected ? "text-selected" : undefined, + decorator: states.lead ? "lead-item" : states.dragover ? "dragover" : undefined, + opacity: states.drag ? 0.5 : undefined, + height: 26, + padding: padding, + margin: 0 + }; + } + }, + 'open-file-item/label': { + include: 'listitem/label', + + style: function () { + return { + alignY: 'middle' + }; + } + }, + 'open-file-item/icon': { + alias: 'listitem/icon', + style: function () { + return { + alignY: 'middle', + padding: [0, 8] + }; + } + }, + 'open-file-item/close': { + + style: function () { + return { + padding: 8, + cursor: 'pointer', + alignY: 'middle' + }; + } + }, + + 'open-with-button': { + include: 'menu-button', + alias: 'menu-button', + + style: function (states) { + return { + font: states.default ? 'bold' : 'default' + }; + } + }, + + 'list': { + style: function () { + return { + decorator: null + }; + } + }, + + 'cv-editor-config': { + style: function () { + return { + padding: 10 + }; + } + }, + + 'cv-editor-config-section': { + style: function () { + return { + padding: 10, + decorator: 'cv-editor-config-section', + marginBottom: 10 + }; + } + }, + + 'cv-editor-config-option': { + style: function () { + return { + marginBottom: 10 + }; + } + }, + + 'cv-config-textfield': { + include: 'textfield', + alias: 'textfield', + + style: function () { + return { + minWidth: 300 + }; + } + }, + + 'cv-editor-config-section/section-title': { + style: function () { + return { + font: 'title', + marginRight: 20 + }; + } + }, + + 'cv-editor-config-section/options-title': 'cv-editor-config-section/section-title', + 'cv-editor-config-section/name': 'cv-config-textfield', + 'cv-editor-config-section/list': { + include: 'list', + alias: 'list', + + style: function() { + return { + height: null + }; + } + }, + 'cv-editor-config-option/value-title': { + style: function () { + return { + allowGrowX: true, + font: 'subtitle' + }; + } + }, + 'cv-editor-config-option/key-title': 'cv-editor-config-option/value-title', + + // snackbar components + 'cv-snackbar': { + style: function () { + return { + zIndex: 1000 + }; + } + }, + + 'cv-snackbar/list': { + style: function () { + return { + height: null, + width: 400, + minWidth: 300 + }; + } + }, + + 'cv-snackbar-msg': { + style: function () { + return { + marginTop: 10, + padding: 10, + textColor: 'text', + decorator: 'cv-snackbar-msg' + }; + } + }, + + 'cv-snackbar-msg/content': { + style: function () { + return { + allowGrowX: true + }; + } + }, + + 'cv-snackbar-msg/close': { + style: function () { + return { + cursor: 'pointer' + }; + } + }, + 'cv-toolbar': { + include: 'toolbar', + alias: 'toolbar', + + style: function () { + return { + // decorator: 'cv-toolbar' + }; + } + }, + 'cv-toolbar-button': { + include: 'toolbar-button', + alias: 'toolbar-button', + + style: function () { + return { + // margin: 1 + }; + } + }, + + 'image-viewer': {}, + 'image-viewer/scroll': 'scrollarea', + 'image-viewer/image': { + include: 'atom', + alias: 'atom', + + style: function () { + return { + iconPosition: 'top', + gap: 10, + center: true + }; + }, + 'image-viewer/image/label': { + style: function () { + return { + margin: 10 + }; + } + } + }, + + 'fs-tree-item': { + include: 'virtual-tree-folder', + alias: 'virtual-tree-folder', + + style: function (states) { + return { + font: states.temporary ? 'italic' : 'default' + }; + } + }, + + 'fs-tree-item/icon': { + include: 'virtual-tree-folder/icon', + alias: 'virtual-tree-folder/icon', + + style: function(states) { + return { + textColor: states.error ? 'invalid-color' : null + }; + } + }, + 'cv-file-contextmenu': 'menu', + 'cv-file-contextmenu/open-with-button': 'menu-button', + 'cv-file-contextmenu/compare-with-button': 'menu-button', + 'open-files-tabs': { + style: function () { + return { + height: 34, + padding: 0, + marginBottom: 5, + decorator: 'open-file-tabs' + }; + } + } } }); \ No newline at end of file diff --git a/source/class/cv/theme/dark/Color.js b/source/class/cv/theme/dark/Color.js index 7bea322e3ab..02904ad75a9 100644 --- a/source/class/cv/theme/dark/Color.js +++ b/source/class/cv/theme/dark/Color.js @@ -20,9 +20,10 @@ qx.Theme.define("cv.theme.dark.Color", { - extend : qx.theme.simple.Color, + extend : osparc.theme.osparcdark.Color, colors : { - + 'valid-color': '#22822d', + 'invalid-color': 'material-textfield-invalid' } }); \ No newline at end of file diff --git a/source/class/cv/theme/dark/Decoration.js b/source/class/cv/theme/dark/Decoration.js index 110a9d66be5..a185e734a3c 100644 --- a/source/class/cv/theme/dark/Decoration.js +++ b/source/class/cv/theme/dark/Decoration.js @@ -20,11 +20,67 @@ qx.Theme.define("cv.theme.dark.Decoration", { - extend : qx.theme.simple.Decoration, + extend : osparc.theme.osparcdark.Decoration, decorations : { "window-caption-active": { + }, + 'cv-editor-config-section': { + style: { + width: 1, + color: 'material-textfield' + } + }, + + 'cv-snackbar-msg': { + style: { + backgroundColor: 'button' + } + }, + + 'cv-snackbar-msg-error': { + style: { + backgroundColor: 'material-textfield-invalid' + } + }, + + 'cv-toolbar': { + style: { + width: [1, 0, 1, 0], + color: 'background-main' + } + }, + + 'file-action-button': { + style: { + width: 1, + color: 'text' + } + }, + + 'cv-start-section-title': { + style: { + width: [1, 0, 0, 0], + color: 'text-placeholder' + } + }, + 'open-file-tabs': { + style: { + shadowSpreadRadius: 0, + shadowBlurRadius: 4, + shadowHorizontalLength: 1, + shadowVerticalLength: 1, + shadowColor: 'rgba(255, 255, 255, 0.1)' + } + }, + + 'cv-file-item-add-file': { + style: { + width: 1, + color: 'text', + style: 'dashed' + } } } }); \ No newline at end of file diff --git a/source/class/cv/theme/dark/Font.js b/source/class/cv/theme/dark/Font.js index 7732d630da7..ce95b7f1cee 100644 --- a/source/class/cv/theme/dark/Font.js +++ b/source/class/cv/theme/dark/Font.js @@ -20,37 +20,98 @@ /** * Font definitions - * + * @asset(iconfont/material/MaterialIcons-Regular.eot) + * @asset(iconfont/material/MaterialIcons-Regular.ttf) + * @asset(iconfont/material/MaterialIcons-Regular.woff) + * @asset(iconfont/material/MaterialIcons-Regular.woff2) + * @asset(iconfont/material/MaterialIcons-Regular.json) */ -qx.Theme.define("cv.theme.dark.Font", -{ - extend : qx.theme.simple.Font, +qx.Theme.define("cv.theme.dark.Font",{ + extend : osparc.theme.osparcdark.Font, fonts : { - "default" : - { - size : 13, - family : ['URW Gothic L','Century Gothic','Apple Gothic',"arial","sans-serif"] + "italic": { + size: 13, + family: ["sans-serif"], + color: "text", + italic: true, + sources: [ + { + family: "Roboto", + source: [ + "osparc/font/roboto-v18-latin_latin-ext-regular.eot", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff2", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff", + "osparc/font/roboto-v18-latin_latin-ext-regular.ttf" + ] + } + ] }, - - "bold" : - { - size : 13, - family : ['URW Gothic L','Century Gothic','Apple Gothic',"arial","sans-serif"], - bold: true - }, - - "subtext" : - { - size : 12, - family : ['URW Gothic L','Century Gothic','Apple Gothic',"arial","sans-serif"] + "title": { + size: 18, + family: ["sans-serif"], + color: "text", + sources: [ + { + family: "Roboto", + source: [ + "osparc/font/roboto-v18-latin_latin-ext-regular.eot", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff2", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff", + "osparc/font/roboto-v18-latin_latin-ext-regular.ttf" + ] + } + ] + }, + "small": { + size: 12, + family: ["sans-serif"], + color: "text", + sources: [ + { + family: "Roboto", + source: [ + "osparc/font/roboto-v18-latin_latin-ext-regular.eot", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff2", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff", + "osparc/font/roboto-v18-latin_latin-ext-regular.ttf" + ] + } + ] + }, + "subtitle": { + size: 16, + family: ["sans-serif"], + color: "text", + sources: [ + { + family: "Roboto", + source: [ + "osparc/font/roboto-v18-latin_latin-ext-regular.eot", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff2", + "osparc/font/roboto-v18-latin_latin-ext-regular.woff", + "osparc/font/roboto-v18-latin_latin-ext-regular.ttf" + ] + } + ] }, - - "title" : - { - size : 18, - bold : true, - family : ['URW Gothic L','Century Gothic','Apple Gothic',"arial","sans-serif"] + "MaterialIcons": { + size: 32, + lineHeight: 1, + comparisonString : "\uf1e3\uf1f7\uf11b\uf19d", + family: ["MaterialIcons"], + sources: [ + { + family: "MaterialIcons", + mapping: "iconfont/material/MaterialIcons-Regular.json", + source: [ + "iconfont/material/MaterialIcons-Regular.eot", + "iconfont/material/MaterialIcons-Regular.woff2", + "iconfont/material/MaterialIcons-Regular.woff", + "iconfont/material/MaterialIcons-Regular.ttf" + ] + } + ] } } }); \ No newline at end of file diff --git a/source/class/cv/theme/dark/Icon.js b/source/class/cv/theme/dark/Icon.js index e2e6779a269..b892ef69529 100644 --- a/source/class/cv/theme/dark/Icon.js +++ b/source/class/cv/theme/dark/Icon.js @@ -19,5 +19,13 @@ qx.Theme.define("cv.theme.dark.Icon", { + extend: qx.theme.icon.Tango, + aliases: { + "dialog.icon.cancel" : "@MaterialIcons/cancel/18", + "dialog.icon.ok" : "@MaterialIcons/check/18", + "dialog.icon.info" : "@MaterialIcons/info/18", + "dialog.icon.error" : "@MaterialIcons/error/18", + "dialog.icon.warning" : "@MaterialIcons/warning/18" + } }); \ No newline at end of file diff --git a/source/class/cv/theme/dark/Images.js b/source/class/cv/theme/dark/Images.js new file mode 100644 index 00000000000..4e36b4b2305 --- /dev/null +++ b/source/class/cv/theme/dark/Images.js @@ -0,0 +1,57 @@ +/** + * Some icon definitions. + */ +qx.Class.define('cv.theme.dark.Images', { + type: 'static', + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + ICONS: { + 'new': '@MaterialIcons/add', + 'new-file': '@MaterialIcons/note_add', + 'new-folder': '@MaterialIcons/create_new_folder', + 'save': '@MaterialIcons/save', + 'delete': '@MaterialIcons/delete', + 'close': '@MaterialIcons/close', + 'quit': '@MaterialIcons/exit_to_app', + 'undo': '@MaterialIcons/undo', + 'redo': '@MaterialIcons/redo', + 'hidden-config': '@MaterialIcons/settings', + 'reload': '@MaterialIcons/sync', + 'add': '@MaterialIcons/add', + 'mounted-folder': '@MaterialIcons/folder_special', + 'folder': '@MaterialIcons/folder', + 'folder-open': '@MaterialIcons/folder_open', + 'file': '@MaterialIcons/insert_drive_file', + 'download': '@MaterialIcons/cloud_download', + 'upload': '@MaterialIcons/cloud_upload', + 'rename': '@MaterialIcons/text_rotation_none', + 'compare': '@MaterialIcons/compare_arrows', + 'preview': '@MaterialIcons/remove_red_eye', + 'trash': '@MaterialIcons/delete', + 'open': '@MaterialIcons/open_in_browser', + 'open-with': '@MaterialIcons/open_with', + 'validate': '@MaterialIcons/spellcheck', + 'valid': '@MaterialIcons/check_circle', + 'error': '@MaterialIcons/error', + 'image': '@MaterialIcons/image', + 'text': '@MaterialIcons/format_align_left', + 'xml': '@MaterialIcons/ballot', + 'icons': '@MaterialIcons/image_search', + 'home': '@MaterialIcons/home', + 'edit': '@MaterialIcons/edit', + 'menu': '@MaterialIcons/menu', + 'drop-down': '@MaterialIcons/arrow_drop_down', + 'drop-up': '@MaterialIcons/arrow_drop_up', + 'clone-file': '@MaterialIcons/file_copy' + }, + + getIcon: function (name, size) { + return this.ICONS.hasOwnProperty(name) ? this.ICONS[name] + '/' + size : '@MaterialIcons/' + name + '/' + size; + } + } +}); diff --git a/source/class/cv/ui/NotificationCenter.js b/source/class/cv/ui/NotificationCenter.js index 468f0bed1de..8b2794f1b73 100644 --- a/source/class/cv/ui/NotificationCenter.js +++ b/source/class/cv/ui/NotificationCenter.js @@ -70,7 +70,7 @@ qx.Class.define("cv.ui.NotificationCenter", { cv.core.notifications.Router.getInstance().registerMessageHandler(this, { 'cv.*': {} }); - this._openCommand = new qx.ui.command.Command("Ctrl+M"); + this._openCommand = new qx.ui.command.Command("Ctrl+N"); this._openCommand.addListener("execute", this.toggleVisibility, this); cv.TemplateEngine.getInstance().getCommands().add("open-notificationcenter", this._openCommand); diff --git a/source/class/cv/ui/manager/IActionHandler.js b/source/class/cv/ui/manager/IActionHandler.js new file mode 100644 index 00000000000..aac774f2d1c --- /dev/null +++ b/source/class/cv/ui/manager/IActionHandler.js @@ -0,0 +1,24 @@ +/** + * All Widgets that need to handle actions from the managers action event, need to implement this interface. + */ +qx.Interface.define('cv.ui.manager.IActionHandler', { + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + /** + * Checks if the action handle can process the action. + * @param actionName {String} action name + */ + canHandleAction: function(actionName) {}, + + /** + * Executes the action handling. + * @param actionName {String} action name + * @param data {var} action payload + */ + handleAction: function (actionName, data) {} + } +}); diff --git a/source/class/cv/ui/manager/Main.js b/source/class/cv/ui/manager/Main.js new file mode 100644 index 00000000000..4ce63b6239c --- /dev/null +++ b/source/class/cv/ui/manager/Main.js @@ -0,0 +1,757 @@ +/** + * Main class of the CometVisu file manager. + * @author Tobias Bräutigam + * @since 0.12.0 + * + * @asset(manager/*) + */ +qx.Class.define('cv.ui.manager.Main', { + extend: qx.core.Object, + type: "singleton", + include: [ + cv.ui.manager.control.MFileEventHandler + ], + implement: [cv.ui.manager.IActionHandler, cv.ui.manager.control.IFileEventHandler], + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._checkEnvironment(); + this.initOpenFiles(new qx.data.Array()); + this.__actionDispatcher = cv.ui.manager.control.ActionDispatcher.getInstance(); + this.__actionDispatcher.setMain(this); + + this.__initCommands(); + this._draw(); + + qx.event.message.Bus.subscribe('cv.manager.*', this._onManagerEvent, this); + + // Initialize tooltip manager + qx.ui.tooltip.Manager.getInstance(); + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + ROOT: null + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + openFiles: { + check: 'qx.data.Array', + deferredInit: true + }, + + /** + * Current selected folder (if a file is selected its parent folder) is writeable. + */ + writeableFolder: { + check: 'Boolean', + init: false, + event: 'changeWriteableFolder' + }, + + currentFolder: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_applyCurrentFolder', + event: 'changeCurrentFolder' + }, + + currentSelection: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_applyCurrentSelection', + event: 'changeCurrentSelection' + }, + + deleteableSelection: { + check: 'Boolean', + init: false, + event: 'changeDeleteableSelection' + }, + + renameableSelection: { + check: 'Boolean', + init: false, + event: 'changeRenameableSelection' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + __previewFileIndex: null, + __root: null, + _pane: null, + _tree: null, + _stack: null, + _oldCommandGroup: null, + _mainContent: null, + _openFilesController: null, + _hiddenConfigFakeFile: null, + __actionDispatcher: null, + + _checkEnvironment: function () { + cv.io.rest.Client.getFsClient().checkEnvironmentSync(function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else if (res) { + res.forEach(function (env) { + switch (env.entity) { + case '.': + // config folder must be writeable + if ((env.state & 1) === 0) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('config folder does not exists')); + } else if ((env.state & 2) === 0) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('config folder is not readable')); + } else if ((env.state & 4) === 0) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('config folder is not writeable')); + } + break; + + case 'backup': + if ((env.state & 4) === 0) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('backup folder is not writeable')); + } + break; + + case 'media': + if ((env.state & 4) === 0) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('media folder is not writeable')); + } + break; + } + }, this); + } + }, this); + }, + + canHandleAction: function (actionName) { + return ['close', 'quit', 'hidden-config', 'new-file', 'new-config-file', 'new-folder', 'delete', 'upload', 'clone'].includes(actionName); + }, + + handleAction: function (actionName, data) { + switch (actionName) { + case 'hidden-config': + this._onOpenHiddenConfig(); + break; + + case 'close': + this.closeCurrentFile(); + break; + + case 'quit': + this.dispose(); + break; + + case 'new-file': + this._onCreate('file'); + break; + + case 'new-config-file': + cv.io.rest.Client.getFsClient().readSync({path: '.templates/visu_config.xml'}, function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('Cannot load config template')); + } else { + this._onCreate('config', res); + } + }, this); + break; + + case 'clone': + cv.io.rest.Client.getFsClient().readSync({path: data.file.getFullPath()}, function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.tr('Cannot load file content')); + } else { + if (data.file.isConfigFile()) { + // config files need to be cloned in the root folder + this._onCreate('config', res, cv.ui.manager.model.FileItem.ROOT); + } else { + this._onCreate('file', res); + } + } + }, this); + break; + + case 'new-folder': + this._onCreate('dir'); + break; + + case 'delete': + this._onDelete(data); + break; + + case 'upload': + // nothing to to, this is handled in another way + break; + + default: + this.warn(actionName + ' handling is not implemented yet!'); + break; + } + }, + + _handleFileEvent: function (ev) { + var data = ev.getData(); + if (data.action === 'deleted') { + // check if file is currently opened and close it + var openFiles = this.getOpenFiles().copy(); + openFiles.some(function (openFile) { + if (openFile.getFile().isRelated(data.path)) { + this.closeFile(openFile); + } + }, this); + } + }, + + _onManagerEvent: function (ev) { + var data = ev.getData(); + switch (ev.getName()) { + case 'cv.manager.compareFiles': + this.openFile(data, false); + break; + + case 'cv.manager.openWith': + this.openFile(data.file || this.getCurrentSelection(), false, data.handler); + break; + + case 'cv.manager.open': + this.openFile(data || this.getCurrentSelection(), false); + break; + } + }, + + /** + * open selected file in preview mode + * @private + */ + _onChangeTreeSelection: function (ev) { + var data = ev.getData(); + if ((cv.ui.manager.model.Preferences.getInstance().isQuickPreview() && data.mode === 'tap') || data.mode === 'dbltap') { + this.__openSelectedFile(data.node, data.mode); + } + var node = data.node; + if (node) { + if (data.node.getType() === 'file') { + this.setCurrentFolder(data.node.getParent()); + } else { + this.setCurrentFolder(node); + } + this.setCurrentSelection(node); + } else { + this.resetCurrentFolder(); + this.resetCurrentSelection(); + } + }, + + __openSelectedFile: function (node, mode) { + if (node) { + if (node.getType() === 'file') { + this.openFile(node, mode === 'tap'); + } else if (mode === 'dbltap') { + // edit folder name on dbltap + node.setEditing(true); + } + } + }, + + _applyCurrentFolder: function (value, old) { + if (old) { + old.removeRelatedBindings(this); + } + if (value) { + value.bind('writeable', this, 'writeableFolder'); + } else { + this.resetWriteableFolder(); + } + }, + + _applyCurrentSelection: function (value, old) { + if (old) { + old.removeRelatedBindings(this); + } + if (value) { + value.bind('writeable', this, 'deleteableSelection'); + value.bind('inTrash', this, 'renameableSelection', { + converter: function (value) { + return !value; + } + }); + } else { + this.resetDeleteableSelection(); + } + }, + + _onChangeFileSelection: function () { + var sel = this._openFilesController.getSelection(); + if (sel.length > 0) { + var openFile = sel.getItem(0); + var file = openFile.getFile(); + var editorConfig; + var handlerId = openFile.getHandlerId(); + if (handlerId) { + editorConfig = cv.ui.manager.control.FileHandlerRegistry.getInstance().getFileHandlerById(handlerId); + } else { + editorConfig = cv.ui.manager.control.FileHandlerRegistry.getInstance().getFileHandler(file); + } + if (!editorConfig.instance) { + editorConfig.instance = new editorConfig.Clazz(); + editorConfig.instance.setFile(file); + this._stack.add(editorConfig.instance); + } else { + editorConfig.instance.setFile(file); + } + this._stack.setSelection([editorConfig.instance]); + this.__actionDispatcher.setFocusedWidget(editorConfig.instance); + } + }, + + openFile: function (file, preview, handlerId) { + var openFiles = this.getOpenFiles(); + var openFile; + if (!handlerId) { + var handlerConf = cv.ui.manager.control.FileHandlerRegistry.getInstance().getFileHandler(file); + + if (!handlerConf) { + // no handler + cv.ui.manager.snackbar.Controller.info(qx.locale.Manager.tr('Cannot open file: "%1"', file.getName())); + return; + } else { + handlerId = handlerConf.Clazz.classname; + } + } + var isOpen = openFiles.some(function (of) { + if (of.getFile() === file && handlerId === of.getHandlerId()) { + openFile = of; + return true; + } + }); + if (!openFile) { + openFile = new cv.ui.manager.model.OpenFile(file, handlerId); + } + if (preview === true) { + if (!openFile.isPermanent()) { + if (this.__previewFileIndex !== null && !openFiles.getItem(this.__previewFileIndex).isPermanent()) { + openFiles.setItem(this.__previewFileIndex, openFile); + } else { + this.__previewFileIndex = openFiles.length; + openFiles.push(openFile); + } + // do not 'downgrade' the permanent state + openFile.setPermanent(false); + } + } else { + if (!isOpen && (this.__previewFileIndex === null || openFiles.indexOf(openFile) !== this.__previewFileIndex)) { + openFiles.push(openFile); + } + openFile.setPermanent(true); + this.__previewFileIndex = null; + } + this._openFilesController.getTarget().setModelSelection([openFile]); + }, + + closeFile: function (openFile, force) { + var file = openFile.getFile(); + if (!openFile.isCloseable()) { + return; + } + + // check if this file is modified + if (file.isModified() && !force) { + // check if temporary + var message = qx.locale.Manager.tr('This file has unsaved changes that will be lost when you close it. Do you really want to close the file?'); + if (file.isTemporary()) { + message = qx.locale.Manager.tr('This file has not been saved on the backend yet. It will be lost when you close it. Do you really want to close the file?'); + } + dialog.Dialog.confirm(message, function (confirmed) { + if (confirmed) { + this.closeFile(openFile, true); + } + }, this, qx.locale.Manager.tr('Unsaved changes')); + return; + } + openFile.resetPermanent(); + var currentSelection = this._openFilesController.getSelection(); + var selectionIndex = -1; + var openFiles = this.getOpenFiles(); + if (currentSelection.length > 0 && currentSelection.getItem(0) === openFile) { + // we need to select another file after this one got closed + selectionIndex = openFiles.indexOf(openFile); + } + openFiles.remove(openFile); + if (this.getOpenFiles().length === 0) { + this._stack.resetSelection(); + this.__actionDispatcher.resetFocusedWidget(); + this.__previewFileIndex = null; + } + if (selectionIndex > 0) { + this._openFilesController.getSelection().replace(openFiles.getItem(selectionIndex - 1)); + } else if (selectionIndex === 0 && openFiles.length > 0) { + this._openFilesController.getSelection().replace(openFiles.getItem(0)); + } + + if (file instanceof cv.ui.manager.model.CompareFiles) { + var fileHandlerConf = cv.ui.manager.control.FileHandlerRegistry.getInstance().getFileHandler(file); + fileHandlerConf.instance.clear(); + if (openFiles.filter(function (openFile) { + return openFile.getFile() instanceof cv.ui.manager.model.CompareFiles; + }).length === 0) { + fileHandlerConf.instance.destroy(); + fileHandlerConf.instance = null; + } + } else if (window.monaco && openFile.getHandlerId() === 'cv.ui.manager.editor.Source') { + // close textmodel in monaco editor if exists + var oldModel = window.monaco.editor.getModel(file.getUri()); + if (oldModel) { + oldModel.dispose(); + } + } + }, + + closeCurrentFile: function () { + var selected = this._openFilesController.getSelection().length > 0 ? this._openFilesController.getSelection().getItem(0) : null; + if (selected) { + this.closeFile(selected); + } + }, + + _onCloseFile: function (ev) { + this.closeFile(ev.getData()); + }, + + __getRoot: function () { + if (!this.__root) { + this.__root = qx.dom.Element.create('div', { + id: 'manager', + style: 'position: absolute; top: 0; left: 0; right: 0; bottom: 0;' + }); + qx.dom.Element.insertEnd(this.__root, document.body); + qx.theme.manager.Meta.getInstance().setTheme(cv.theme.Dark); + } + return this.__root; + }, + + __initCommands: function () { + var group = new qx.ui.command.Group(); + group.add('save', new qx.ui.command.Command('Ctrl+S')); + group.add('save-as', new qx.ui.command.Command('Ctrl+Shift+S')); + // this command will close the browser window, thats not what we want + // group.add('close', new qx.ui.command.Command('Ctrl+W')); + group.add('new-file', new qx.ui.command.Command('Ctrl+N')); + group.add('new-folder', new qx.ui.command.Command('Ctrl+Shift+N')); + group.add('quit', new qx.ui.command.Command('Ctrl+Q')); + // group.add('delete', new qx.ui.command.Command('Del')); + + var renameCommand = new qx.ui.command.Command('F2'); + group.add('rename', renameCommand); + this.bind('renameableSelection', renameCommand, 'enabled'); + + // edit commands (adding cut/copy/paste command will deactivate the native browser functions) + // and as we cannot simulate pasting from clipboard, we do not use them here + // group.add('cut', new qx.ui.command.Command('Ctrl+X')); + // group.add('copy', new qx.ui.command.Command('Ctrl+C')); + // group.add('paste', new qx.ui.command.Command('Ctrl+V')); + + var manager = qx.core.Init.getApplication().getCommandManager(); + this._oldCommandGroup = manager.getActive(); + manager.add(group); + manager.setActive(group); + }, + + _onOpenHiddenConfig: function () { + var fakeFile = new cv.ui.manager.model.FileItem.getHiddenConfigFile(); + if (this.getOpenFiles().includes(fakeFile)) { + this.closeFile(fakeFile); + } else { + this.openFile(fakeFile, false); + } + }, + + _onDelete: function (file) { + var item = file || this.getCurrentSelection(); + if (item) { + cv.ui.manager.control.FileController.getInstance().delete(item); + } + }, + + _onChangeStackSelection: function (ev) { + var selection = ev.getData(); + var openFiles = []; + // sync tab selection with currently visible page + selection.forEach(function(page) { + var openFile = this.getOpenFiles().toArray().find(function (openFile) { + return openFile.getFile() === page.getFile() && openFile.getHandlerId() === page.classname; + }); + if (openFile) { + openFiles.push(openFile); + } + }, this); + + this._openFilesController.getSelection().replace(openFiles); + }, + + _onCreate: function (type, content, folder) { + var currentFolder = folder || this.getCurrentFolder(); + if (!currentFolder) { + return; + } + var message, existsMessage; + if (type === 'config') { + message = qx.locale.Manager.tr('Please enter the name of the new configuration (without "visu_config_" at the beginning and ".xml" at the end)'); + existsMessage = qx.locale.Manager.tr('A configuration with this name already exists.'); + } else if (type === 'file') { + message = qx.locale.Manager.tr('Please enter the file name.'); + existsMessage = qx.locale.Manager.tr('A file with this name already exists.'); + } else { + message = qx.locale.Manager.tr('Please enter the folder name.'); + existsMessage = qx.locale.Manager.tr('A folder with this name already exists.'); + } + var handlePrompt = function (name) { + if (!name) { + // canceled + return; + } + var filename = name; + // add visu_config_..-xml + if (type === 'config') { + var match = /visu[_-]config[_-]([\w\d_-]+)(\.xml)?/.exec(name); + if (match) { + name = match[1]; + } + filename = 'visu_config_' + name + '.xml'; + } + // check if name does not exist + var exists = currentFolder.getChildren().some(function (child) { + if (child.getName() === filename) { + return true; + } + }, this); + + if (exists) { + cv.ui.manager.snackbar.Controller.error(existsMessage); + dialog.Dialog.prompt(message, handlePrompt, this, name); + } else { + var item = new cv.ui.manager.model.FileItem(filename, currentFolder.getPath(), currentFolder); + item.set({ + type: type === 'config' ? 'file' : type, + readable: true, + writeable: true, + loaded: true, + modified: true, + temporary: true, + parentFolder: currentFolder.getFullPath(), + content: content || '' + }); + currentFolder.addChild(item); + currentFolder.sortElements(); + this._tree.refresh(); + this._tree.setSelection(item); + this.openFile(item, false); + } + }; + + dialog.Dialog.prompt(message, handlePrompt, this); + }, + + /** + * Finds next droppable parent of the given element. Maybe the element itself as well. + * + * Looks for the attribute qxDroppable with the value on. + * + * @param elem {Element} The element to query + * @return {Element} The next parent element which is droppable. May also be null + */ + __findDroppable : function (elem) { + while (elem && elem.nodeType === 1) { + if (elem.getAttribute("qxDroppable") === "on") { + return elem; + } + + elem = elem.parentNode; + } + + return null; + }, + + // overridden + _draw: function () { + + var root = new qx.ui.root.Inline(this.__getRoot(), true, true); + root.addListenerOnce('appear', function () { + // disable file drop + var element = root.getContentElement().getDomElement(); + element.addEventListener('drop', function (ev) { + var target = this.__findDroppable(ev.target); + if (!target) { + ev.preventDefault(); + } + }.bind(this)); + element.addEventListener('dragover', function (ev) { + var target = this.__findDroppable(ev.target); + if (!target) { + ev.preventDefault(); + } + }.bind(this)); + }, this); + qx.core.Init.getApplication().setRoot(root); + root.setLayout(new qx.ui.layout.Canvas()); + + var snackbar = cv.ui.manager.snackbar.Controller.getInstance(); + root.add(snackbar, { + bottom: 10, + left: 200 + }); + + function resize() { + var bounds = root.getBounds(); + snackbar.setLayoutProperties({ + bottom: 10, + left: Math.round(bounds.width / 2) - 150 + }); + snackbar.setMaxHeight(bounds.height - 40); + } + root.addListener('resize', resize, this); + root.addListener('appear', resize, this); + + var main = new qx.ui.container.Composite(new qx.ui.layout.Dock()); + root.add(main, {edge: 0}); + // menu on top + var menuBar = cv.ui.manager.MenuBar.getInstance(); + main.add(menuBar, {edge: 'north'}); + + var uploadButton = menuBar.getButton('upload'); + var uploadManager = new cv.ui.manager.upload.UploadMgr(uploadButton); + this.bind('currentFolder', uploadManager, 'folder'); + + this._pane = new qx.ui.splitpane.Pane(); + main.add(this._pane, {edge: 'center'}); + + var rootFolder = cv.ui.manager.model.FileItem.ROOT = new cv.ui.manager.model.FileItem('.'); + var fakeIconFile = cv.ui.manager.model.FileItem.getIconFile(); + // TODO: needs to be verified by the backend + rootFolder.set({ + overrideIcon: true, + writeable: true, + readable: true, + open: true, + fakeChildren: [fakeIconFile], + icon: cv.theme.dark.Images.getIcon('home', 18) + }); + this.setCurrentFolder(rootFolder); + this._tree = new cv.ui.manager.tree.FileSystem(rootFolder); + this._tree.addListener("changeSelection", this._onChangeTreeSelection, this); + + // left container + var leftContainer = new qx.ui.container.Composite(new qx.ui.layout.VBox()); + + // left toolbar + var leftBar = new cv.ui.manager.ToolBar(uploadManager); + this.bind('currentFolder', leftBar, 'folder'); + this.bind('currentSelection', leftBar, 'file'); + leftBar.addListener('reload', this._tree.reload, this._tree); + + // globally bind writeable folder to command for new files + var buttonConfig = menuBar.getButtonConfiguration(); + this.bind('writeableFolder', buttonConfig['new-file'].args[2], 'enabled'); + this.bind('writeableFolder', buttonConfig['new-folder'].args[2], 'enabled'); + + leftContainer.add(leftBar); + leftContainer.add(this._tree, {flex: 1}); + this._pane.add(leftContainer, 0); + cv.ui.manager.model.Preferences.getInstance().bind('expertMode', leftContainer, 'visibility', { + converter: function (value) { + return value ? 'visible' : 'excluded'; + } + }); + + this._mainContent = new qx.ui.container.Composite(new qx.ui.layout.VBox()); + + // tab list + var list = new qx.ui.form.List(true); + list.setAppearance('open-files-tabs'); + this._openFilesController = new qx.data.controller.List(this.getOpenFiles(), list, "file.name"); + this._openFilesController.setDelegate({ + createItem: function () { + var item = new cv.ui.manager.form.FileTabItem(); + item.addListener('close', this._onCloseFile, this); + return item; + }.bind(this), + + bindItem: function (controller, item, index) { + controller.bindDefaultProperties(item, index); + controller.bindProperty('file.permanent', 'permanent', null, item, index); + controller.bindProperty('file.modified', 'modified', null, item, index); + controller.bindProperty('icon', 'icon', null, item, index); + controller.bindProperty('closeable', 'closeable', null, item, index); + } + }); + list.addListener('changeSelection', this._onChangeFileSelection, this); + this._mainContent.add(list); + + this._stack = new qx.ui.container.Stack(); + this._stack.addListener('changeSelection', this._onChangeStackSelection, this); + this._mainContent.add(this._stack, {flex: 1}); + this._pane.add(this._mainContent, 1); + + var startOpenFile = new cv.ui.manager.model.OpenFile(rootFolder, 'cv.ui.manager.Start'); + startOpenFile.setCloseable(false); + console.log(startOpenFile); + this.getOpenFiles().push(startOpenFile); + list.setModelSelection([startOpenFile]); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._disposeObjects( + '_pane', '_tree', '_stack', '_mainContent', '_openFilesController' + ); + // restore former command group + var application = qx.core.Init.getApplication(); + var manager = application.getCommandManager(); + manager.setActive(this._oldCommandGroup); + this._oldCommandGroup = null; + + // defer the reset to let the dispose queue to be emptied before removing the root + new qx.util.DeferredCall(function () { + application.resetRoot(); + }).schedule(); + + document.body.removeChild(this.__root); + this.__root = null; + this.__actionDispatcher = null; + + qx.event.message.Bus.unsubscribe('cv.manager.*', this._onManagerEvent, this); + + // destroy the singleton instance + delete cv.ui.manager.Main.$$instance; + }, + + defer: function(statics) { + // initialize on load + statics.getInstance(); + + // load backupFolder + cv.ui.manager.model.BackupFolder.getInstance(); + } +}); diff --git a/source/class/cv/ui/manager/MenuBar.js b/source/class/cv/ui/manager/MenuBar.js new file mode 100644 index 00000000000..e393d3185eb --- /dev/null +++ b/source/class/cv/ui/manager/MenuBar.js @@ -0,0 +1,315 @@ +/** + * Main toolbar on top. + */ +qx.Class.define('cv.ui.manager.MenuBar', { + extend: qx.ui.menubar.MenuBar, + type: 'singleton', + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._commandGroup = qx.core.Init.getApplication().getCommandManager().getActive(); + this.__buttons = {}; + + this._draw(); + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _commandGroup: null, + __buttons: null, + __defaultButtonConfiguration: null, + __buttonConfiguration: null, + + _draw: function () { + this._createChildControl('file'); + this._createChildControl('edit'); + this._createChildControl('preferences'); + this.add(new qx.ui.core.Spacer(), {flex: 1}); + + this._createChildControl('title'); + this.add(new qx.ui.core.Spacer(), {flex: 1}); + + var editorGroup = new qx.ui.form.RadioGroup(); + + this.__defaultButtonConfiguration = { + 'new-file': { + menu: 'new-menu', + args: [this.tr('New file'), cv.theme.dark.Images.getIcon('new-file', 18), this._commandGroup.get('new-file')], + enabled: true + }, + 'new-folder': { + menu: 'new-menu', + args: [this.tr('New folder'), cv.theme.dark.Images.getIcon('new-folder', 18), this._commandGroup.get('new-folder')], + enabled: true, + separator: 'after' + }, + 'new-config-file': { + menu: 'new-menu', + args: [this.tr('New config file')], + enabled: true + }, + 'upload': { + menu: 'file-menu', + clazz: com.zenesis.qx.upload.UploadMenuButton, + args: [this.tr('Upload file'), cv.theme.dark.Images.getIcon('upload', 18)], + enabled: true, + separator: 'before' + }, + 'save': { + menu: 'file-menu', + args: [this.tr('Save'), cv.theme.dark.Images.getIcon('save', 18), this._commandGroup.get('save')], + enabled: false, + separator: 'before' + }, + 'save-as': { + menu: 'file-menu', + args: [this.tr('Save as...'), null, this._commandGroup.get('save-as')], + enabled: false + }, + 'delete': { + menu: 'file-menu', + args: [this.tr('Delete'), cv.theme.dark.Images.getIcon('delete', 18), this._commandGroup.get('delete')], + enabled: false, + separator: 'before' + }, + 'close': { + menu: 'file-menu', + args: [this.tr('Close file'), cv.theme.dark.Images.getIcon('close', 18), this._commandGroup.get('close')], + enabled: false, + separator: 'before' + }, + 'quit': { + menu: 'file-menu', + args: [this.tr('Quit'), cv.theme.dark.Images.getIcon('quit', 18), this._commandGroup.get('quit')], + enabled: true, + separator: 'before' + }, + // edit menu basics + 'undo': { + menu: 'edit-menu', + args: [this.tr('Undo'), cv.theme.dark.Images.getIcon('undo', 18), this.tr('Ctrl+Z')], + enabled: true + }, + 'redo': { + menu: 'edit-menu', + args: [this.tr('Redo'), cv.theme.dark.Images.getIcon('redo', 18), this.tr('Ctrl+Y')], + enabled: true + }, + 'cut': { + menu: 'edit-menu', + args: [this.tr('Cut'), null, this.tr('Ctrl+X')], + enabled: false, + separator: 'before' + }, + 'copy': { + menu: 'edit-menu', + args: [this.tr('Copy'), null, this.tr('Ctrl+C')], + enabled: false + }, + 'paste': { + menu: 'edit-menu', + args: [this.tr('Paste'), null, this.tr('Ctrl+V')], + enabled: false + }, + 'hidden-config': { + menu: 'edit-menu', + args: [this.tr('Hidden configuration'), cv.theme.dark.Images.getIcon('hidden-config', 18)], + enabled: true + }, + // preferences + 'source-editor': { + menu: 'preferences-menu', + clazz: qx.ui.menu.RadioButton, + args: [this.tr('Use text editor')], + general: true, + enabled: true, + properties: { + model: 'source', + group: editorGroup + } + }, + 'xml-editor': { + menu: 'preferences-menu', + clazz: qx.ui.menu.RadioButton, + args: [this.tr('Use xml editor')], + general: true, + enabled: true, + properties: { + model: 'xml', + group: editorGroup + } + }, + 'quick-preview': { + menu: 'preferences-menu', + clazz: qx.ui.menu.CheckBox, + args: [this.tr('Enable quick preview')], + general: true, + enabled: true, + separator: 'before' + }, + 'expert-mode': { + menu: 'preferences-menu', + clazz: qx.ui.menu.CheckBox, + args: [this.tr('Expert mode')], + general: true, + enabled: true + } + }; + this.maintainButtons(); + + var prefs = cv.ui.manager.model.Preferences.getInstance(); + + prefs.bind('defaultConfigEditor', editorGroup, 'modelSelection', { + converter: function (value) { + return [value]; + } + }); + editorGroup.getModelSelection().addListener('change', function () { + prefs.setDefaultConfigEditor(editorGroup.getModelSelection().getItem(0)); + }, this); + + this.__bindToPreference('quick-preview', 'quickPreview'); + this.__bindToPreference('expert-mode', 'expertMode'); + }, + + __bindToPreference: function (buttonName, preferenceName) { + var button = this.getButton(buttonName); + var prefs = cv.ui.manager.model.Preferences.getInstance() + prefs.bind(preferenceName, button, 'value'); + button.bind('value', prefs, preferenceName); + }, + + maintainButtons: function (config) { + if (!config) { + config = this.__defaultButtonConfiguration; + } else { + config = Object.merge(this.__defaultButtonConfiguration, config); + this.__buttonConfiguration = config; + } + Object.keys(config).forEach(function (id) { + var button; + var buttonConf = config[id]; + if (!this.__buttons.hasOwnProperty(id)) { + // create button + var label = buttonConf.args[0]; + var icon = buttonConf.args[1]; + var command = buttonConf.args[2]; + var ButtonClass = buttonConf.clazz || qx.ui.menu.Button; + if (qx.lang.Type.isString(command) || !command) { + // no command connected + button = new ButtonClass(label, icon); + if (command) { + // just add the string as shortcut hint + button.getChildControl('shortcut').setValue(command); + } + } else { + button = new ButtonClass(label, icon, command); + } + button.addListener('execute', function () { + qx.event.message.Bus.dispatchByName('cv.manager.action.' + id); + }, this); + var menu = this.getChildControl(buttonConf.menu); + if (!menu) { + throw new Error('no menu named ' + buttonConf.menu + ' found!'); + } + if (buttonConf.separator === 'before') { + menu.add(new qx.ui.menu.Separator()); + } + menu.add(button); + if (buttonConf.separator === 'after') { + menu.add(new qx.ui.menu.Separator()); + } + this.__buttons[id] = button; + + if (buttonConf.hasOwnProperty('onAfterCreate')) { + buttonConf.onAfterCreate(button); + } + } else { + button = this.__buttons[id]; + } + button.setEnabled(buttonConf.enabled); + if (buttonConf.properties) { + button.set(buttonConf.properties); + } + + }, this); + }, + + getButton: function (id) { + return this.__buttons[id]; + }, + + getButtonConfiguration: function () { + return this.__buttonConfiguration || this.__defaultButtonConfiguration; + }, + + // overridden + _createChildControlImpl : function(id) { + var control; + + switch (id) { + case 'title': + control = new qx.ui.basic.Label(this.tr('CometVisu Manager')); + this.add(control); + break; + + case "file": + control = new qx.ui.menubar.Button(this.tr('File'), null, this.getChildControl('file-menu')); + this.add(control); + break; + + case "edit": + control = new qx.ui.menubar.Button(this.tr('Edit'), null, this.getChildControl('edit-menu')); + this.add(control); + break; + + case "new": + control = new qx.ui.menu.Button(this.tr('New'), null, null, this.getChildControl('new-menu')); + break; + + case "preferences": + control = new qx.ui.menubar.Button(this.tr('Preferences'), null, this.getChildControl('preferences-menu')); + this.add(control); + break; + + case 'new-menu': + control = new qx.ui.menu.Menu(); + break; + + case 'file-menu': + control = new qx.ui.menu.Menu(); + control.add(this.getChildControl('new')); + break; + + case 'edit-menu': + control = new qx.ui.menu.Menu(); + break; + + case 'preferences-menu': + control = new qx.ui.menu.Menu(); + break; + + } + + return control || this.base(arguments, id); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._commandGroup = null; + } +}); diff --git a/source/class/cv/ui/manager/Start.js b/source/class/cv/ui/manager/Start.js new file mode 100644 index 00000000000..5a285d60d61 --- /dev/null +++ b/source/class/cv/ui/manager/Start.js @@ -0,0 +1,256 @@ +/** + * Simple view that provides all of the file-related features of the old editor in an easy to use way. + */ +qx.Class.define('cv.ui.manager.Start', { + extend: qx.ui.core.Widget, + implement: [ + cv.ui.manager.editor.IEditor, + cv.ui.manager.IActionHandler + ], + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._setLayout(new qx.ui.layout.VBox(8)); + this._configRegex = /^visu_config_?([^.]+)?\.xml$/; + [ 'configs-title', 'configs-toolbar', 'configs', + 'demo-configs-title', 'demo-configs', + 'media-title', 'media-toolbar', 'media', + 'misc-title', 'misc' + ].forEach(this._createChildControl, this); + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + file: { + check: 'cv.ui.manager.model.FileItem', + apply: '_loadRoot' + }, + appearance: { + refine: true, + init: 'cv-start' + }, + + selectedItem: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_applySelectedItem' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _configRegex: null, + _ignoreSelectionChanges: false, + + save: function () {}, + getCurrentContent: function () {}, + canHandleAction: function () { + return false; + }, + handleAction: function () {}, + + _loadRoot: function (value) { + this.getChildControl('configs').setFile(value); + var found = 0; + + value.load(function () { + value.getChildren().some(function (file) { + if (file.getName() === 'media') { + this.getChildControl('media').setFile(file); + this.getChildControl('media-toolbar').setFolder(file); + found++; + } else if (file.getName() === 'demo') { + this.getChildControl('demo-configs').setFile(file); + found++; + } + return found === 2; + }, this); + }, this); + }, + + _onChangeSelection: function (ev) { + if (this._ignoreSelectionChanges === false) { + var list = ev.getTarget(); + var selection = ev.getData(); + this._ignoreSelectionChanges = true; + + // unselect the other lists + ['configs', 'demo-configs', 'media'].forEach(function (name) { + var control = this.getChildControl(name); + if (control !== list) { + control.resetSelection(); + } + }, this); + this._ignoreSelectionChanges = false; + if (selection.length > 0) { + this.setSelectedItem(selection[0].getModel()); + } + } + }, + + _applySelectedItem: function () { + }, + + _onToggleExpand: function (ev) { + var control = this.getChildControl(ev.getTarget().getUserData('control')); + if (control.getVisibility() === 'visible') { + control.exclude(); + ev.getTarget().setIcon(cv.theme.dark.Images.getIcon('drop-down', 18)); + } else { + control.show(); + ev.getTarget().setIcon(cv.theme.dark.Images.getIcon('drop-up', 18)); + } + }, + + // overridden + _createChildControlImpl : function(id) { + var control; + + switch (id) { + case 'configs-title': + control = new qx.ui.basic.Atom(this.tr('Configurations'), cv.theme.dark.Images.getIcon('drop-up', 18)); + control.setUserData('control', 'configs'); + control.addListener('tap', this._onToggleExpand, this); + this.getChildControl('configs-header').add(control); + break; + + case 'configs-header': + control = new qx.ui.container.Composite(new qx.ui.layout.HBox()); + this._add(control); + break; + + case 'configs-toolbar': + control = new cv.ui.manager.ToolBar(null, ['new-config-file', 'upload', 'reload']); + control.setFolder(cv.ui.manager.model.FileItem.ROOT); + control.addListener('reload', function () { + cv.ui.manager.model.FileItem.ROOT.reload(); + }, this); + this.getChildControl('configs-header').add(control); + break; + + case 'configs': + control = new cv.ui.manager.viewer.Folder(); + control.set({ + showTextFilter: false, + permanentFilter: function (file) { + var match = this._configRegex.exec(file.getName()); + return !!match && (!match[1] || !match[1].endsWith('temp')); + }.bind(this), + labelConverter: function (name, file) { + if (file.isFake()) { + return name; + } + var configName = cv.ui.manager.model.FileItem.getConfigName(name); + return configName ? qx.lang.String.firstUp(configName) : ''; + }, + file: cv.ui.manager.model.FileItem.ROOT + }); + control.addListener('changeSelection', this._onChangeSelection, this); + this._add(control); + break; + + case 'demo-configs-title': + control = new qx.ui.basic.Atom(this.tr('Demo configurations'), cv.theme.dark.Images.getIcon('drop-down', 18)); + control.setUserData('control', 'demo-configs'); + control.addListener('tap', this._onToggleExpand, this); + this._add(control); + break; + + case 'demo-configs': + control = new cv.ui.manager.viewer.Folder(); + control.set({ + showTextFilter: false, + permanentFilter: function (file) { + return this._configRegex.test(file.getName()); + }.bind(this), + labelConverter: function (name) { + var configName = cv.ui.manager.model.FileItem.getConfigName(name); + return configName ? qx.lang.String.firstUp(configName) : ''; + } + }); + control.exclude(); + control.addListener('changeSelection', this._onChangeSelection, this); + this._add(control); + break; + + case 'media-title': + control = new qx.ui.basic.Atom(this.tr('Media files'), cv.theme.dark.Images.getIcon('drop-up', 18)); + control.setUserData('control', 'media'); + control.addListener('tap', this._onToggleExpand, this); + this.getChildControl('media-header').add(control); + break; + + case 'media-header': + control = new qx.ui.container.Composite(new qx.ui.layout.HBox()); + this._add(control); + break; + + case 'media-toolbar': + control = new cv.ui.manager.ToolBar(null, ['new-file', 'upload', 'reload']); + control.addListener('reload', function () { + control.getFolder().reload(); + }, this); + this.getChildControl('media-header').add(control); + break; + + case 'media': + control = new cv.ui.manager.viewer.Folder(); + control.set({ + showTextFilter: false + }); + control.addListener('changeSelection', this._onChangeSelection, this); + this._add(control); + break; + + case 'misc-title': + control = new qx.ui.basic.Atom(this.tr('Miscellaneous'), cv.theme.dark.Images.getIcon('drop-up', 18)); + control.setUserData('control', 'misc'); + control.addListener('tap', this._onToggleExpand, this); + this._add(control); + break; + + case 'misc': + control = new cv.ui.manager.viewer.Folder(); + control.set({ + showTextFilter: false + }); + var fakeFolder = new cv.ui.manager.model.FileItem('fake', 'fake', cv.ui.manager.model.FileItem.ROOT, [ + cv.ui.manager.model.FileItem.getHiddenConfigFile(), + cv.ui.manager.model.FileItem.getIconFile() + ]).set({ + fake: true, + type: 'dir', + loaded: true + }); + control.setFile(fakeFolder); + control.addListener('changeSelection', this._onChangeSelection, this); + this._add(control, {flex: 1}); + break; + } + + return control || this.base(arguments, id); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._configRegex = null; + } +}); diff --git a/source/class/cv/ui/manager/ToolBar.js b/source/class/cv/ui/manager/ToolBar.js new file mode 100644 index 00000000000..1b41f4fd728 --- /dev/null +++ b/source/class/cv/ui/manager/ToolBar.js @@ -0,0 +1,198 @@ +/** + * + */ +qx.Class.define('cv.ui.manager.ToolBar', { + extend: qx.ui.toolbar.ToolBar, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function (uploadManager, showOnly) { + this.base(arguments); + + if (showOnly) { + this.__showOnly = showOnly; + } + + this._menuBar = cv.ui.manager.MenuBar.getInstance(); + this._menuButtonConfig = this._menuBar.getButtonConfiguration(); + this._uploadManager = uploadManager; + + this._init(); + }, + + /* + *********************************************** + EVENTS + *********************************************** + */ + events: { + 'reload': 'qx.event.type.Event' + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + appearance: { + refine: true, + init: 'cv-toolbar' + }, + + folder: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_applyFolder' + }, + + file: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_applyFile', + event: 'changeFile' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _menuButtonConfig: null, + _uploadManager: null, + _menuBar: null, + __showOnly: null, + + __show: function (name) { + return this.__showOnly === null || this.__showOnly.includes(name); + }, + + _init: function () { + if (!this._uploadManager) { + this._uploadManager = new cv.ui.manager.upload.UploadMgr(); + } + + var fileController = cv.ui.manager.control.FileController.getInstance(); + + var createPart = new qx.ui.toolbar.Part(); + createPart.set({ + marginLeft: 0 + }); + this.add(createPart); + var newButton; + + if (this.__show('new-menu')) { + newButton = new qx.ui.toolbar.MenuButton(null, + cv.theme.dark.Images.getIcon('new-file', 15), + this._menuBar.getChildControl('new-menu') + ); + createPart.add(newButton); + } else if (this.__show('new-config-file')) { + newButton = this._createButton('new-config-file', cv.theme.dark.Images.getIcon('new-file', 15)); + newButton.addListener('execute', function () { + qx.event.message.Bus.dispatchByName('cv.manager.action.new-config-file'); + }, this); + createPart.add(newButton); + } else if (this.__show('new-file')) { + newButton = this._createButton('new-file'); + createPart.add(newButton); + } + + if (this.__show('upload')) { + var upload = this._createButton('upload'); + this._uploadManager.addWidget(upload); + createPart.add(upload); + } + + if (this.__show('delete')) { + var deleteSelection = this._createButton('delete'); + deleteSelection.addListener('execute', function () { + fileController.delete(this.getFile()); + }, this); + this.bind('file', deleteSelection, 'enabled', { + converter: function (file) { + return !!file && file.isWriteable() && !file.isFake(); + } + }); + this.add(deleteSelection); + } + + if (this.__show('download')) { + var download = new qx.ui.toolbar.Button(null, cv.theme.dark.Images.getIcon('download', 15)); + download.setAppearance('cv-toolbar-button'); + download.setToolTipText(qx.locale.Manager.tr('Download')); + download.addListener('execute', function () { + fileController.download(this.getFile()); + }, this); + // download button is only enabled when a file is selected + this.bind('file', download, 'enabled', { + converter: function (file) { + return !!file && file.getType() === 'file' && !file.isFake(); + } + }); + createPart.add(download); + } + + if (this.__show('validate')) { + // config check + var checkConfig = new qx.ui.toolbar.Button(null, cv.theme.dark.Images.getIcon('validate', 15)); + checkConfig.setAppearance('cv-toolbar-button'); + checkConfig.setToolTipText(qx.locale.Manager.tr('Validate')); + checkConfig.addListener('execute', function () { + fileController.validate(this.getFile()); + }, this); + + // validate button is only enabled when a file is selected + this.bind('file', checkConfig, 'enabled', { + converter: function (file) { + return !!file && file.isConfigFile(); + } + }); + this.add(checkConfig); + } + + if (this.__show('reload')) { + var reload = new qx.ui.toolbar.Button(null, cv.theme.dark.Images.getIcon('reload', 15)); + reload.setAppearance('cv-toolbar-button'); + reload.setToolTipText(qx.locale.Manager.tr('Reload')); + reload.addListener('execute', function () { + this.fireEvent('reload'); + }, this); + this.add(new qx.ui.core.Spacer(), {flex: 1}); + this.add(reload); + } + }, + + _createButton: function (name, icon) { + var args = this._menuButtonConfig[name].args; + var button = new qx.ui.toolbar.Button(null, icon || args[1].replace(/\/[0-9]+$/, '/15'), args[2]); + button.setAppearance('cv-toolbar-button'); + button.setToolTipText(args[0]); + return button; + }, + + _applyFile: function () { + + }, + + _applyFolder: function () { + + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._menuButtonConfig = null; + this._uploadManager = null; + this.__menuBar = null; + } +}); diff --git a/source/class/cv/ui/manager/contextmenu/FileItem.js b/source/class/cv/ui/manager/contextmenu/FileItem.js new file mode 100644 index 00000000000..c6372ad222f --- /dev/null +++ b/source/class/cv/ui/manager/contextmenu/FileItem.js @@ -0,0 +1,302 @@ +/** + * + */ +qx.Class.define('cv.ui.manager.contextmenu.FileItem', { + extend: qx.ui.menu.Menu, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function (file) { + this.base(arguments); + this._commandGroup = qx.core.Init.getApplication().getCommandManager().getActive(); + this._init(); + this._dateFormat = new qx.util.format.DateFormat(qx.locale.Date.getDateFormat('medium')); + this._timeFormat = new qx.util.format.DateFormat(qx.locale.Date.getTimeFormat('medium')); + + if (file) { + this.configure(file); + } + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + appearance: { + refine: true, + init: 'cv-file-contextmenu' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _commandGroup: null, + _selectedNode: null, + _dateFormat: null, + _timeFormat: null, + + + configure: function (file) { + this._selectedNode = file; + if (file) { + var folder = file.getType() === 'folder' ? file : file.getParent(); + this.getChildControl('new-file-button').setEnabled(folder ? folder.isWriteable() : false); + this.getChildControl('clone-file-button').setVisibility(file.isConfigFile() ? 'visible' : 'excluded'); + this.getChildControl('new-folder-button').setEnabled(folder ? folder.isWriteable() : false); + this.getChildControl('delete-button').setLabel(file.isTrash() ? + this.tr('Clear') : + this.tr('Delete')); + + // create compare menu + var compareMenu = this.getChildControl('compare-menu'); + compareMenu.removeAll(); + var backups = cv.ui.manager.model.BackupFolder.getInstance().getBackupFiles(file); + this.getChildControl('compare-with-button').setEnabled(backups.length > 0); + backups.sort(function (a, b) { + return b.date.getTime() - a.date.getTime(); + }); + var group = null; + backups.forEach(function (backupEntry) { + var date = this._dateFormat.format(backupEntry.date); + if (group !== date) { + if (group !== null) { + compareMenu.add(new qx.ui.menu.Separator()); + } + var groupButton = new qx.ui.menu.Button(date); + groupButton.setEnabled(false); + compareMenu.add(groupButton); + group = date; + } + var button = new qx.ui.menu.Button(this.tr('Backup from %1', this._timeFormat.format(backupEntry.date))); + button.setUserData('file', backupEntry.file); + button.addListener('execute', this._onCompareWith, this); + compareMenu.add(button); + }, this); + + var defaultHandler = cv.ui.manager.control.FileHandlerRegistry.getInstance().getFileHandler(file); + + // open with menu + var availableHandlers = cv.ui.manager.control.FileHandlerRegistry.getInstance().getAllFileHandlers(file); + var openWithMenu = this.getChildControl('open-with-menu'); + openWithMenu.removeAll(); + // this menu only makes sense when there is more than one option to select from + this.getChildControl('open-with-button').setEnabled(availableHandlers.length > 1); + availableHandlers.sort(function (a, b) { + return a.Clazz.constructor.TITLE.toString().localeCompare(b.Clazz.constructor.TITLE.toString()); + }); + availableHandlers.forEach(function (handlerConf) { + var button = new qx.ui.menu.Button(handlerConf.Clazz.constructor.TITLE, handlerConf.Clazz.constructor.ICON); + button.setAppearance('open-with-button'); + if (defaultHandler.Clazz.classname === handlerConf.Clazz.classname) { + button.addState('default'); + } + button.setUserData('handlerId', handlerConf.Clazz.classname); + button.addListener('execute', this._onOpenWith, this); + openWithMenu.add(button); + }, this); + + // validate button + this.getChildControl('validate-config-button').setVisibility(file.isConfigFile() ? 'visible' : 'excluded'); + + // replacement button + if (file.getType() === 'file') { + this.getChildControl('replace-button').show(); + this._replacementManager.setFilename(file.getName()); + this._replacementManager.setFolder(file.getParent()); + } else { + this.getChildControl('replace-button').exclude(); + } + // buttons that need write access + ['delete-button', 'replace-button', 'rename-button'].forEach(function (controlName) { + this.getChildControl(controlName).setEnabled(file.isWriteable()); + }, this); + this.getChildControl('download-button').setEnabled(!file.isFake()); + + this.getChildControl('restore-button').setVisibility(file.isInTrash() ? 'visible' : 'excluded'); + } else { + this.getChildControl('delete-button').set({ + label: this.tr('Delete'), + enabled: false + }); + this.getChildControl('replace-button').exclude(); + this.getChildControl('download-button').setEnabled(false); + this.getChildControl('restore-button').exclude(); + } + }, + + _init: function () { + this.add(this.getChildControl('new-file-button')); + this.add(this.getChildControl('clone-file-button')); + this.add(this.getChildControl('new-folder-button')); + this.add(new qx.ui.menu.Separator()); + this.add(this.getChildControl('open-button')); + this.add(this.getChildControl('open-with-button')); + this.add(this.getChildControl('compare-with-button')); + this.add(new qx.ui.menu.Separator()); + this.add(this.getChildControl('rename-button')); + this.add(this.getChildControl('delete-button')); + this.add(this.getChildControl('restore-button')); + this.add(new qx.ui.menu.Separator()); + this.add(this.getChildControl('download-button')); + var sep = new qx.ui.menu.Separator(); + var button = this.getChildControl('replace-button'); + this.add(sep); + this.add(button); + button.bind('visibility', sep, 'visibility'); + sep = new qx.ui.menu.Separator(); + button = this.getChildControl('validate-config-button'); + button.bind('visibility', sep, 'visibility'); + this.add(sep); + this.add(button); + }, + + _onCompareWith: function (ev) { + var compareWith = ev.getTarget().getUserData('file'); + qx.event.message.Bus.dispatchByName('cv.manager.compareFiles', + new cv.ui.manager.model.CompareFiles(compareWith, this._selectedNode) + ); + }, + + _onOpenWith: function (ev) { + var handlerId = ev.getTarget().getUserData('handlerId'); + qx.event.message.Bus.dispatchByName('cv.manager.openWith', { + file: this._selectedNode, + handler: handlerId + }); + }, + + _onRename: function () { + if (this._selectedNode) { + this._selectedNode.setEditing(true); + } + }, + + _onDownload: function () { + if (this._selectedNode) { + cv.ui.manager.control.FileController.getInstance().download(this._selectedNode); + } + }, + + _onRestore: function () { + if (this._selectedNode) { + cv.ui.manager.control.FileController.getInstance().restore(this._selectedNode); + } + }, + + _onValidate: function () { + if (this._selectedNode) { + cv.ui.manager.control.FileController.getInstance().validate(this._selectedNode); + } + }, + + _onClone: function () { + if (this._selectedNode) { + qx.event.message.Bus.dispatchByName('cv.manager.action.clone', { + file: this._selectedNode + }); + } + }, + + // overridden + _createChildControlImpl : function(id) { + var control; + + switch (id) { + case 'new-file-button': + control = new qx.ui.menu.Button(this.tr('New file'), cv.theme.dark.Images.getIcon('new-file', 18), this._commandGroup.get('new-file')); + break; + + case 'clone-file-button': + control = new qx.ui.menu.Button(this.tr('Clone file'), cv.theme.dark.Images.getIcon('clone-file', 18)); + control.exclude(); + control.addListener('execute', this._onClone, this); + break; + + case 'new-folder-button': + control = new qx.ui.menu.Button(this.tr('New folder'), cv.theme.dark.Images.getIcon('new-folder', 18), this._commandGroup.get('new-folder')); + break; + + case 'rename-button': + control = new qx.ui.menu.Button(this.tr('Rename'), cv.theme.dark.Images.getIcon('rename', 18), this._commandGroup.get('rename')); + control.addListener('execute', this._onRename, this); + break; + + case 'delete-button': + control = new qx.ui.menu.Button(this.tr('Delete'), cv.theme.dark.Images.getIcon('delete', 18)); + control.addListener('execute', function () { + qx.event.message.Bus.dispatchByName('cv.manager.action.delete', this._selectedNode); + }, this); + break; + + case 'download-button': + control = new qx.ui.menu.Button(this.tr('Download'), cv.theme.dark.Images.getIcon('download', 18)); + control.addListener('execute', this._onDownload, this); + break; + + case 'open-button': + control = new qx.ui.menu.Button(this.tr('Open'), cv.theme.dark.Images.getIcon('open', 18)); + control.addListener('execute', function () { + qx.event.message.Bus.dispatchByName('cv.manager.open', this._selectedNode); + }, this); + break; + + case 'restore-button': + control = new qx.ui.menu.Button(this.tr('Restore'), cv.theme.dark.Images.getIcon('trash', 18)); + control.exclude(); + control.addListener('execute', this._onRestore, this); + break; + + case 'validate-config-button': + control = new qx.ui.menu.Button(this.tr('Validate'), cv.theme.dark.Images.getIcon('validate', 18)); + control.exclude(); + control.addListener('execute', this._onValidate, this); + break; + + case 'replace-button': + control = new com.zenesis.qx.upload.UploadMenuButton(this.tr('Replace'), cv.theme.dark.Images.getIcon('upload', 18)); + control.exclude(); + this._replacementManager = new cv.ui.manager.upload.UploadMgr(); + this._replacementManager.setForce(true); + this._replacementManager.addWidget(control); + break; + + case 'compare-menu': + control = new qx.ui.menu.Menu(); + break; + + case 'compare-with-button': + control = new qx.ui.menu.Button(this.tr('Compare with...'), cv.theme.dark.Images.getIcon('compare', 18), null, this.getChildControl('compare-menu')); + break; + + case 'open-with-button': + control = new qx.ui.menu.Button(this.tr('Open with...'), cv.theme.dark.Images.getIcon('open-with', 18), null, this.getChildControl('open-with-menu')); + break; + + case 'open-with-menu': + control = new qx.ui.menu.Menu(); + break; + } + + return control || this.base(arguments, id); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._commandGroup = null; + this._disposeObjects('_dateFormat', '_timeFormat'); + } +}); diff --git a/source/class/cv/ui/manager/contextmenu/GlobalFileItem.js b/source/class/cv/ui/manager/contextmenu/GlobalFileItem.js new file mode 100644 index 00000000000..6c475d49e70 --- /dev/null +++ b/source/class/cv/ui/manager/contextmenu/GlobalFileItem.js @@ -0,0 +1,7 @@ +/** + * + */ +qx.Class.define('cv.ui.manager.contextmenu.GlobalFileItem', { + extend: cv.ui.manager.contextmenu.FileItem, + type: 'singleton' +}); diff --git a/source/class/cv/ui/manager/control/ActionDispatcher.js b/source/class/cv/ui/manager/control/ActionDispatcher.js new file mode 100644 index 00000000000..23b4cf259e3 --- /dev/null +++ b/source/class/cv/ui/manager/control/ActionDispatcher.js @@ -0,0 +1,93 @@ +/** + * The ActionDispatcher listens to the events in the 'cv.manager.action' topic and + * dispatched those events to the currently relevant handler (e.g. the save event to the opened editor). + */ +qx.Class.define('cv.ui.manager.control.ActionDispatcher', { + extend: qx.core.Object, + type: 'singleton', + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + qx.event.message.Bus.subscribe('cv.manager.action.*', this._onAction, this); + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + focusedWidget: { + check: 'cv.ui.manager.IActionHandler', + nullable: true, + apply: '_applyFocusedWidget' + }, + + main: { + check: 'cv.ui.manager.Main', + nullable: true + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _applyFocusedWidget: function () { + var menuBar = cv.ui.manager.MenuBar.getInstance(); + var config = menuBar.getButtonConfiguration(); + var button; + Object.keys(config).forEach(function (actionId) { + button = menuBar.getButton(actionId); + if (button) { + button.setEnabled(config[actionId].general || this.hasHandler(actionId)); + } + }, this); + }, + + /** + * Check if there is an existing handler for the given actionName. + * @return {Boolean} + */ + hasHandler: function (actionName) { + return !!this._getHandler(actionName); + }, + + _getHandler: function (actionName) { + var handler = this.getFocusedWidget(); + var main = this.getMain(); + if (handler && handler.canHandleAction(actionName)) { + return handler; + } else if (main && main.canHandleAction(actionName)) { + return main; + } + }, + + _onAction: function (ev) { + var topic = ev.getName(); + var actionName = topic.split('.').pop(); + var handler = this._getHandler(actionName); + if (handler) { + handler.handleAction(actionName, ev.getData()); + } else { + this.warn('no action handler found for action: ' + actionName); + } + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + qx.event.message.Bus.subscribe('cv.manager.action.*', this._onAction, this); + } +}); diff --git a/source/class/cv/ui/manager/control/FileController.js b/source/class/cv/ui/manager/control/FileController.js new file mode 100644 index 00000000000..3a2dcf55e37 --- /dev/null +++ b/source/class/cv/ui/manager/control/FileController.js @@ -0,0 +1,230 @@ +/** + * The FileController is responsible for all file operations, like config check, move, replace, delete etc. + */ +qx.Class.define('cv.ui.manager.control.FileController', { + extend: qx.core.Object, + type: 'singleton', + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this.__fsClient = cv.io.rest.Client.getFsClient(); + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + __fsClient: null, + + rename: function (file, newName) { + var newPath = file.getPath() || ''; + if (newPath.length > 0 && !newPath.endsWith('/')) { + newPath += '/'; + } + newPath += newName; + if (file.isTemporary()) { + // create new item + this.__fsClient.createSync({path: newPath, type: file.getType()}, function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(file.getType() === 'file' ? + qx.locale.Manager.tr('File has been created') : + qx.locale.Manager.tr('Folder has been created') + ); + file.resetTenporary(); + file.resetModified(); + file.setName(newName); + file.reload(); + } + }, this); + } else if (file.getFullPath() !== newPath) { + this.__fsClient.moveSync({src: file.getFullPath(), target: newPath}, function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(file.getType() === 'file' ? + qx.locale.Manager.tr('File has been renamed') : + qx.locale.Manager.tr('Folder has been renamed') + ); + file.setName(newName); + file.resetModified(); + file.reload(); + } + file.resetEditing(); + }, this); + } + }, + + /** + * Move file to another path + * @param file {cv.ui.manager.model.FileItem} file to move + * @param target {String} new path of the file + */ + move: function (file, target) { + this.__fsClient.moveSync({src: file.getFullPath(), target: target}, function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(file.getType() === 'file' ? + qx.locale.Manager.tr('File has been moved') : + qx.locale.Manager.tr('Folder has been moved') + ); + qx.event.message.Bus.dispatchByName('cv.manager.file', { + action: 'moved', + path: file.getFullPath() + }); + } + }, this); + }, + + /** + * Restore file from trash by moving it out of the trash to the old path + * @param file {cv.ui.manager.model.FileItem} file to restore + */ + restore: function (file) { + if (file.isInTrash()) { + var target = file.getFullPath().replace('.trash/', ''); + this.__fsClient.moveSync({src: file.getFullPath(), target: target}, function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(file.getType() === 'file' ? + qx.locale.Manager.tr('File has been restored') : + qx.locale.Manager.tr('Folder has been restored') + ); + qx.event.message.Bus.dispatchByName('cv.manager.file', { + action: 'restored', + path: file.getFullPath() + }); + } + }, this); + } + }, + + 'delete': function(file, callback, context) { + if (file.isTemporary()) { + // new file, no need to call the backend + if (callback) { + callback.apply(context, true); + } + } else { + if (file) { + var message; + if (file.isTrash()) { + message = qx.locale.Manager.tr('Do you really want to clear the trash?'); + } else if (file.isInTrash()) { + message = file.getType() === 'file' ? + qx.locale.Manager.tr('Do you really want to delete this file from the trash?') : + qx.locale.Manager.tr('Do you really want to delete this folder from the trash?'); + } else { + message = file.getType() === 'file' ? + qx.locale.Manager.tr('Do you really want to delete this file?') : + qx.locale.Manager.tr('Do you really want to delete this folder?'); + } + dialog.Dialog.confirm(message, function (confirmed) { + if (confirmed) { + this.__doDelete(file, callback, context); + } else if (callback) { + callback.apply(context, false); + } + }, this, qx.locale.Manager.tr('Confirm deletion')); + } + } + }, + + __doDelete: function (file, callback, context) { + this.__fsClient.deleteSync({path: file.getFullPath(), force: file.isTrash()}, null, function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + if (callback) { + callback.apply(context, false); + } + } else { + var message; + if (file.isTrash()) { + message = qx.locale.Manager.tr('Trash has been cleared'); + } else if (file.isInTrash()) { + message = this.getType() === 'file' ? + qx.locale.Manager.tr('File has been removed from trash') : + qx.locale.Manager.tr('Folder has been removed from trash'); + } else { + message = file.getType() === 'file' ? + qx.locale.Manager.tr('File has been deleted') : + qx.locale.Manager.tr('Folder has been deleted'); + } + cv.ui.manager.snackbar.Controller.info(message); + if (callback) { + callback.apply(context, true); + } + qx.event.message.Bus.dispatchByName('cv.manager.file', { + action: 'deleted', + path: file.getFullPath() + }); + } + }, this); + }, + + download: function (file) { + if (file.getType() === 'file') { + var element = document.createElement('a'); + element.setAttribute('href', cv.io.rest.Client.BASE_URL + '/fs?download=true&path=' + file.getFullPath()); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + } + }, + + validate: function (file) { + if (qx.core.Environment.get('qx.debug')) { + qx.core.Assert.assertInstance(file, cv.ui.manager.model.FileItem); + } + if (file.isConfigFile()) { + this.__validateConfig(file); + } else { + this.info('no validation available for file: ' + file.getFullPath()); + } + }, + + __validateConfig: function (file) { + var d = dialog.Dialog.alert(qx.locale.Manager.tr('Validating %1', file.getFullPath())); + cv.ui.manager.editor.Worker.getInstance().validateConfig(file).then(function (res) { + d.close(); + if (res === true) { + file.setValid(true); + cv.ui.manager.snackbar.Controller.info(qx.locale.Manager.tr('%1 has no errors!', file.getFullPath())); + } else { + file.setValid(false); + qx.event.message.Bus.dispatchByName('cv.manager.openWith', { + file: file, + handler: 'cv.ui.manager.editor.Source' + }); + cv.ui.manager.snackbar.Controller.error(qx.locale.Manager.trn( + '%1 error found in %2!', + '%1 errors found in %2!', + res.length, + res.length, + file.getFullPath()) + ); + } + }.bind(this)); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this.__fsClient = null; + } +}); diff --git a/source/class/cv/ui/manager/control/FileHandlerRegistry.js b/source/class/cv/ui/manager/control/FileHandlerRegistry.js new file mode 100644 index 00000000000..1a9e7125aee --- /dev/null +++ b/source/class/cv/ui/manager/control/FileHandlerRegistry.js @@ -0,0 +1,220 @@ +/** + * Central registry for all available file editors/viewers. + */ +qx.Class.define('cv.ui.manager.control.FileHandlerRegistry', { + extend: qx.core.Object, + type: 'singleton', + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this.__registry = {}; + this.__defaults = []; + + // register viewers + this.registerFileHandler(new RegExp('\.(' + cv.ui.manager.viewer.Image.SUPPORTED_FILES.join('|') + ')$'), cv.ui.manager.viewer.Image, {type: 'view'}); + this.registerFileHandler(cv.ui.manager.viewer.Config.SUPPORTED_FILES, cv.ui.manager.viewer.Config, {type: 'view'}); + this.registerFileHandler(cv.ui.manager.viewer.Icons.SUPPORTED_FILES, cv.ui.manager.viewer.Icons, {type: 'view'}); + this.registerFileHandler(cv.ui.manager.viewer.Folder.SUPPORTED_FILES, cv.ui.manager.viewer.Folder, {type: 'view'}); + this.registerFileHandler(null, cv.ui.manager.Start, {type: 'view'}); + + // register the basic editors + this.registerFileHandler(new RegExp('\.(' + cv.ui.manager.editor.Source.SUPPORTED_FILES.join('|') + ')$'), cv.ui.manager.editor.Source, {type: 'edit'}); + this.registerFileHandler(/visu_config(_.+)?\.xml/, cv.ui.manager.editor.Xml, { + preview: false, + type: 'edit' + }); + this.registerFileHandler(cv.ui.manager.model.CompareFiles, cv.ui.manager.editor.Diff, {type: 'view'}); + + this.registerFileHandler("hidden.php", cv.ui.manager.editor.Config, {type: 'edit'}); + + cv.ui.manager.model.Preferences.getInstance().addListener('changeDefaultConfigEditor', this._onChangesDefaultConfigEditor, this); + this._onChangesDefaultConfigEditor(); + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + __registry: null, + __defaults: null, + + /** + * Registers an editor for a specific file, that is identified by the given selector. + * @param selector {String|RegExp|Class|Function|null} filename-/path or regular expression. If null this is a special handler that must be loaded manually (like cv.ui.manager.Start) + * @param clazz {qx.ui.core.Widget} widget class that handles those type of files + * @param options {Map?} additional options to store in the registry + */ + registerFileHandler: function (selector, clazz, options) { + if (qx.core.Environment.get('qx.debug')) { + qx.core.Assert.assertTrue(qx.Interface.classImplements(clazz, cv.ui.manager.editor.IEditor)); + } + var config = Object.assign({ + Clazz: clazz, + instance: null + }, options || {}); + if (qx.Class.isClass(selector)) { + config.instanceOf = selector; + config.selectorId = 'instanceOf:' + selector.classname; + // highest priority + config.priority = 0; + } else if (qx.lang.Type.isRegExp(selector)) { + config.regex = selector; + config.selectorId = 'regex:' + selector.toString(); + config.priority = 4; + } else if (qx.lang.Type.isFunction(selector)) { + config.selectorId = 'function:' + selector.name; + config.priority = 3; + config.function = selector; + } else if (qx.lang.Type.isString(selector)) { + // simple file matcher + if (selector.includes('/')) { + config.fullPath = selector; + config.selectorId = 'fullPath:' + selector; + config.priority = 1; + } else { + config.fileName = selector; + config.selectorId = 'fileName:' + selector; + config.priority = 2; + } + } else { + config.selectorId = 'none'; + config.priority = 10; + } + this.__registry[clazz.classname] = config; + }, + + getFileHandler: function (file, type) { + var handlers = []; + if (!(file instanceof cv.ui.manager.model.CompareFiles)) { + // check if there is a default first + var defaultHandler; + Object.keys(this.__defaults).some(function (key) { + if (this.__defaults[key].regex.test(file.getFullPath())) { + if (type) { + var config = this.getFileHandlerById(this.__defaults[key].clazz.classname); + if (config.type === type) { + defaultHandler = config; + } + } else { + defaultHandler = this.getFileHandlerById(this.__defaults[key].clazz.classname); + } + return !!defaultHandler; + } + }, this); + if (defaultHandler) { + return defaultHandler; + } + } + + Object.keys(this.__registry).forEach(function (classname) { + var config = this.__registry[classname]; + if (this.__canHandle(config, file) && (!type || config.type === type)) { + handlers.push(config); + } + }, this); + if (handlers.length === 0) { + // no editors found + return null; + } else if (handlers.length === 1) { + return handlers[0]; + } else { + // sort by selector priority (instance, fullpath, filename, regex) + handlers.sort(function (a, b) { + return a.priority - b.priority; + }); + // no default handler, just take the first one + return handlers[0]; + } + }, + + getFileHandlerById: function (handlerId) { + return this.__registry[handlerId]; + }, + + hasFileHandler: function (file, type) { + return Object.keys(this.__registry).some(function (classname) { + var config = this.__registry[classname]; + return this.__canHandle(config, file) && (!type || config.type === type); + }, this); + }, + + /** + * Mark the handler with the given classname as default for the selector-id and all others with the same selector id not, + * @param selectorId {RegExp} + * @param clazz {qx.Class} + */ + setDefault: function (selector, clazz) { + if (qx.core.Environment.get('qx.debug')) { + qx.core.Assert.assertRegExp(selector); + qx.core.Assert.assertTrue(qx.Class.isClass(clazz)); + } + this.__defaults[selector.toString()] = { + regex: selector, + clazz: clazz + }; + }, + + _onChangesDefaultConfigEditor: function () { + var selector = /visu_config(_.+)?\.xml/; + switch (cv.ui.manager.model.Preferences.getInstance().getDefaultConfigEditor()) { + case 'source': + this.setDefault(selector, cv.ui.manager.editor.Source); + break; + + case 'xml': + this.setDefault(selector, cv.ui.manager.editor.Xml); + break; + } + }, + + __canHandle: function(config, file) { + if (config.fileName && file.getName() === config.fileName) { + return true; + } else if (config.fullPath && file.getFullPath() === config.fullPath) { + return true; + } else if (config.regex && config.regex.test(file.getFullPath())) { + return true; + } else if (config.instanceOf && file instanceof config.instanceOf) { + return true; + } else if (config.function && config.function(file)) { + return true; + } + return false; + }, + + getAllFileHandlers: function (file, type) { + if (qx.core.Environment.get('qx.debug')) { + qx.core.Assert.assertInstance(file, cv.ui.manager.model.FileItem); + } + return Object.keys(this.__registry).filter(function (key) { + return this.__canHandle(this.__registry[key], file) && (!type || this.__registry[key].type === type); + }, this).map(function (key) { + return this.__registry[key]; + }, this); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + // cleanup handler instances + Object.keys(this.__registry).forEach(function (regex) { + if (this.__registry[regex].instance) { + this.__registry[regex].instance.dispose(); + this.__registry[regex].instance = null; + } + }, this); + + cv.ui.manager.model.Preferences.getInstance().removeListener('changeDefaultConfigEditor', this._onChangesDefaultConfigEditor, this); + } +}); diff --git a/source/class/cv/ui/manager/control/IFileEventHandler.js b/source/class/cv/ui/manager/control/IFileEventHandler.js new file mode 100644 index 00000000000..4c7756d89b4 --- /dev/null +++ b/source/class/cv/ui/manager/control/IFileEventHandler.js @@ -0,0 +1,13 @@ +/** + * + */ +qx.Interface.define('cv.ui.manager.control.IFileEventHandler', { + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _handleFileEvent: function (ev) {} + } +}); diff --git a/source/class/cv/ui/manager/control/MFileEventHandler.js b/source/class/cv/ui/manager/control/MFileEventHandler.js new file mode 100644 index 00000000000..3b58d139163 --- /dev/null +++ b/source/class/cv/ui/manager/control/MFileEventHandler.js @@ -0,0 +1,26 @@ +/** + * Mixin for all classes that have to handle event on the 'cv.manager.file' topic. + * Those classes need to implement the cv.ui.manager.control.IFileEventHandler interface. + */ +qx.Mixin.define('cv.ui.manager.control.MFileEventHandler', { + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + if (qx.core.Environment.get('qx.debug')) { + qx.core.Assert.assertInterface(this, cv.ui.manager.control.IFileEventHandler); + } + qx.event.message.Bus.subscribe('cv.manager.file', this._handleFileEvent, this); + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + qx.event.message.Bus.unsubscribe('cv.manager.file', this._handleFileEvent, this); + } +}); diff --git a/source/class/cv/ui/manager/core/IconAtom.js b/source/class/cv/ui/manager/core/IconAtom.js new file mode 100644 index 00000000000..7955b7971c2 --- /dev/null +++ b/source/class/cv/ui/manager/core/IconAtom.js @@ -0,0 +1,45 @@ +/** + * Atom with cv.ui.manager.viewer.SvgIcon instead ob an qx.ui.basic.Image + */ +qx.Class.define('cv.ui.manager.core.IconAtom', { + extend: qx.ui.basic.Atom, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + appearance: { + refine: true, + init: 'cv-icon' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _applyLabel: function (value) { + this.base(arguments, value); + this.getChildControl('icon').setName(value); + }, + + // overridden + _createChildControlImpl : function(id) { + var control; + + switch (id) { + case 'icon': + control = new cv.ui.manager.viewer.SvgIcon(); + control.setAnonymous(true); + this._addAt(control, 0); + break; + } + + return control || this.base(arguments, id); + } + } +}); diff --git a/source/class/cv/ui/manager/editor/AbstractEditor.js b/source/class/cv/ui/manager/editor/AbstractEditor.js new file mode 100644 index 00000000000..3215020c105 --- /dev/null +++ b/source/class/cv/ui/manager/editor/AbstractEditor.js @@ -0,0 +1,151 @@ +/** + * Abstract base class for all editors. + */ +qx.Class.define('cv.ui.manager.editor.AbstractEditor', { + extend: qx.ui.core.Widget, + implement: [ + cv.ui.manager.editor.IEditor, + cv.ui.manager.IActionHandler + ], + type: "abstract", + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._initClient(); + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + file: { + check: 'cv.ui.manager.model.FileItem || cv.ui.manager.model.CompareFiles', + nullable: true, + apply: '_loadFile' + }, + + content: { + nullable: true, + event: 'changeContent', + apply: '_applyContent' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _handledActions: null, + + canHandleAction: function (actionName) { + return this._handledActions && this._handledActions.includes(actionName); + }, + + handleAction: function (actionName) { + if (this.canHandleAction(actionName)) { + switch (actionName) { + case 'save': + this.save(); + break; + } + } + }, + + _initClient: function () { + this._client = cv.io.rest.Client.getFsClient(); + }, + + _loadFile: function (file) { + if (file && file.getType() === 'file') { + if (file.getContent() !== null) { + this.setContent(file.getContent()); + } else { + this._client.readSync({path: this.getFile().getFullPath()}, function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + this.setContent(res); + } + }, this); + } + } else { + this.resetContent(); + } + }, + + // must be overridden by inheriting classes + _applyContent: function() {}, + + // must be overridden by inheriting classes + getCurrentContent: function () {}, + + save: function () { + var file = this.getFile(); + if (file.isModified()) { + if (file.isTemporary()) { + this._client.createSync({ + path: file.getFullPath(), + hash: file.getHash(), + type: 'file' + }, this.getCurrentContent(), function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(this.tr('File has been created')); + this._onSaved(); + qx.event.message.Bus.dispatchByName(file.getBusTopic(), { + type: 'created', + file: file, + data: this.getCurrentContent(), + source: this + }); + } + }, this); + } else { + this._client.updateSync({ + path: file.getFullPath(), + hash: file.getHash() + }, this.getCurrentContent(), function (err) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + cv.ui.manager.snackbar.Controller.info(this.tr('File has been saved')); + this._onSaved(); + qx.event.message.Bus.dispatchByName(file.getBusTopic(), { + type: 'contentChanged', + data: this.getCurrentContent(), + source: this + }); + } + }, this); + } + } + }, + + _onSaved: function () { + var file = this.getFile(); + file.resetModified(); + file.resetTemporary(); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + if (this._client) { + this._client = null; + } + } +}); diff --git a/source/class/cv/ui/manager/editor/Config.js b/source/class/cv/ui/manager/editor/Config.js new file mode 100644 index 00000000000..be0fd8cc16a --- /dev/null +++ b/source/class/cv/ui/manager/editor/Config.js @@ -0,0 +1,145 @@ +/** + * Editor for the (hidden) configuration. + */ +qx.Class.define('cv.ui.manager.editor.Config', { + extend: cv.ui.manager.editor.AbstractEditor, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._handledActions = ['save']; + this._setLayout(new qx.ui.layout.VBox(8)); + this._createChildControl('list'); + this._createChildControl('add-section'); + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + TITLE: qx.locale.Manager.tr('Hidden configuration') + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + appearance: { + refine: true, + init: 'cv-editor-config' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _model: null, + _listController: null, + + _initClient: function () { + this._client = cv.io.rest.Client.getConfigClient(); + this._client.addListener('getSuccess', this._onModelValueChange, this); + this._client.addListener('updateSuccess', this._onSaved, this); + }, + + _loadFile: function () { + this._client.get({section: '*'}); + }, + + _onModelValueChange: function (ev) { + this.setContent(ev.getData()); + }, + + // overridden + _applyContent: function(value) { + var model = this._listController.getModel(); + model.removeAll(); + + Object.keys(value).forEach(function (sectionName) { + var section = new cv.ui.manager.model.config.Section(sectionName); + Object.keys(value[sectionName]).forEach(function (optionKey) { + section.addOption(optionKey, value[sectionName][optionKey]); + }, this); + model.push(section); + }, this); + }, + + // overridden + getCurrentContent: function () { + return this.getContent(); + }, + + _onDeleteSection: function (ev) { + var section = ev.getData(); + var model = this._listController.getModel(); + model.remove(section); + }, + + save: function () { + var data = qx.util.Serializer.toNativeObject(this._listController.getModel()); + this._client.save(null, data); + }, + + // overridden + _createChildControlImpl : function(id) { + var control; + + switch (id) { + case 'list': + control = new qx.ui.form.List(); + control.setEnableInlineFind(false); + this._listController = new qx.data.controller.List(new qx.data.Array(), control); + this._listController.setDelegate({ + createItem: function () { + return new cv.ui.manager.form.SectionListItem(); + }, + + configureItem: function (item) { + item.addListener('delete', this._onDeleteSection, this); + }.bind(this), + + bindItem: function (controller, item, index) { + controller.bindProperty('', 'model', null, item, index); + } + }); + this._add(control, {flex: 1}); + break; + + case 'buttons': + control = new qx.ui.container.Composite(new qx.ui.layout.HBox(8)); + this._add(control); + break; + + case 'add-section': + control = new qx.ui.form.Button(this.tr('Add section')); + control.addListener('execute', function () { + this._listController.getModel().push(new cv.ui.manager.model.config.Section('')); + }, this); + this.getChildControl('buttons').add(control); + break; + } + + return control || this.base(arguments, id); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._disposeObjects('_model', '_listController'); + } +}); diff --git a/source/class/cv/ui/manager/editor/Diff.js b/source/class/cv/ui/manager/editor/Diff.js new file mode 100644 index 00000000000..cf5beee160d --- /dev/null +++ b/source/class/cv/ui/manager/editor/Diff.js @@ -0,0 +1,125 @@ +/** + * Monaco Texteditor for file content comparison + */ +qx.Class.define('cv.ui.manager.editor.Diff', { + extend: cv.ui.manager.editor.Source, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._handledActions = []; + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + COUNTER: 0, + TITLE: qx.locale.Manager.tr('File compare'), + ICON: cv.theme.dark.Images.getIcon('compare', 18) + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + originalContent: { + check: 'String', + init: '', + apply: '_applyContent' + }, + + modifiedContent: { + check: 'String', + init: '', + apply: '_applyContent' + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + + // overridden, diff editor is read only, no worker needed + _initWorker: function () {}, + + _draw: function () { + if (!window.monaco) { + cv.ui.manager.editor.Source.load(this._draw, this); + } else { + var domElement = this.getContentElement().getDomElement(); + if (!domElement) { + this.addListenerOnce('appear', this._draw, this); + } else { + this._editor = window.monaco.editor.createDiffEditor(domElement, { + folding: true, + autoIndent: true, + automaticLayout: true, + theme: 'vs-dark', + readOnly: true + }); + if (this.getFile()) { + this._loadFile(this.getFile()); + } + } + } + }, + + _applyContent: function () { + var original = this.getOriginalContent(); + var modified = this.getModifiedContent(); + if (original && modified) { + var file = this.getFile(); + var originalModel = window.monaco.editor.createModel(original, this._getLanguage(file.getOriginalFile())); + originalModel.updateOptions(this._getDefaultModelOptions()); + var modifiedModel = window.monaco.editor.createModel(modified, this._getLanguage(file.getModifiedFile())); + modifiedModel.updateOptions(this._getDefaultModelOptions()); + this._editor.setModel({ + original: originalModel, + modified: modifiedModel + }); + } + }, + + clear: function () { + this._editor.getModel().original.dispose(); + this._editor.getModel().modified.dispose(); + }, + + _loadFile: function (file) { + if (this._editor) { + if (file && file instanceof cv.ui.manager.model.CompareFiles && this.isSupported(file.getModifiedFile())) { + this._client.readSync({path: file.getModifiedFile().getFullPath()}, function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + this.setModifiedContent(res); + } + }, this); + + this._client.readSync({path: file.getOriginalFile().getFullPath()}, function (err, res) { + if (err) { + cv.ui.manager.snackbar.Controller.error(err); + } else { + this.setOriginalContent(res); + } + }, this); + } else { + this.resetOriginalContent(); + this.resetModifiedContent(); + } + } + } + } +}); diff --git a/source/class/cv/ui/manager/editor/IEditor.js b/source/class/cv/ui/manager/editor/IEditor.js new file mode 100644 index 00000000000..7cb27a2537b --- /dev/null +++ b/source/class/cv/ui/manager/editor/IEditor.js @@ -0,0 +1,37 @@ +/** + * Interface all file editors must implement. + */ +qx.Interface.define('cv.ui.manager.editor.IEditor', { + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + file: { + check: 'cv.ui.manager.model.FileItem', + nullable: true, + apply: '_loadFile' + } + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + TITLE: '' + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + save: function () {}, + + getCurrentContent: function () {} + } +}); diff --git a/source/class/cv/ui/manager/editor/Source.js b/source/class/cv/ui/manager/editor/Source.js new file mode 100644 index 00000000000..093de70ae03 --- /dev/null +++ b/source/class/cv/ui/manager/editor/Source.js @@ -0,0 +1,332 @@ +/** + * Monaco Texteditor integration + */ +qx.Class.define('cv.ui.manager.editor.Source', { + extend: cv.ui.manager.editor.AbstractEditor, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._handledActions = ['save', 'cut', 'copy', 'paste', 'undo', 'redo']; + this._basePath = window.location.origin + window.location.pathname + qx.util.LibraryManager.getInstance().get("cv", "resourceUri") + '/config/'; + this.getContentElement().setAttribute('contentEditable', 'true'); + this.set({ + droppable: false, + focusable: true + }); + this.addListener('dragover', function (ev) { + ev.preventDefault(); + ev.dataTransfer.effectAllowed = "none"; + ev.dataTransfer.dropEffect = "none"; + }); + this.addListener('drop', function (ev) { + ev.preventDefault(); + }); + this.addListener('appear', function () { + qx.ui.core.FocusHandler.getInstance().setUseTabNavigation(false); + }); + this.addListener('disappear', function () { + qx.ui.core.FocusHandler.getInstance().setUseTabNavigation(true); + }); + this._draw(); + this._initWorker(); + this._currentDecorations = []; + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + TITLE: qx.locale.Manager.tr('Texteditor'), + COUNTER: 0, + SUPPORTED_FILES: ['xml', 'php', 'css', 'js', 'svg', 'json', 'md', 'yaml', 'conf', 'ts', 'rst', 'py', 'txt'], + ICON: cv.theme.dark.Images.getIcon('text', 18), + + load: function (callback, context) { + var version = qx.core.Environment.get('qx.debug') ? 'dev' : 'min'; + window.documentationMappingPrefix = "../source/editor/"; // jshint ignore:line + var loader = new qx.util.DynamicScriptLoader([ + '../source/editor/dependencies/jquery.min.js', + '../source/editor/dependencies/jquery.xpath.min.js', + '../source/editor/lib/Messages.js', + '../source/editor/lib/Schema.js', + '../../node_modules/monaco-editor/' + version + '/vs/loader.js', + 'manager/xml.js' + ]); + loader.addListener('ready', function () { + window.require.config({ + paths: { + 'vs': '../../node_modules/monaco-editor/' + version + '/vs' + } + }); + window.require.config({ + 'vs/nls' : { + availableLanguages: { + '*': qx.locale.Manager.getInstance().getLanguage() !== 'en' ? qx.locale.Manager.getInstance().getLanguage() : '' + } + } + }); + var noCacheSuffix = '?' + Math.random(); + window.require([ + 'xml!./resource/visu_config.xsd' + noCacheSuffix, + 'xml!*./resource/manager/completion-libs/qooxdoo.d.ts', // the xml loader can load any file by adding * before the path, + 'vs/editor/editor.main' + ], function (schema, qxLib) { + this.__schema = schema; + callback.apply(context); + window.monaco.languages.typescript.javascriptDefaults.addExtraLib(qxLib, 'qooxdoo.d.ts'); + var parsedSchema = new window.Schema("visu_config.xsd", schema); // jshint ignore:line + var completionProvider = new cv.ui.manager.editor.completion.Config(parsedSchema); + var cvCompletionProvider = new cv.ui.manager.editor.completion.CometVisu(); + window.monaco.languages.registerCompletionItemProvider('xml', completionProvider.getProvider()); + window.monaco.languages.registerCompletionItemProvider('javascript', cvCompletionProvider.getProvider()); + + }.bind(this)); + }, this); + loader.addListener('failed', function (ev) { + qx.log.Logger.error(this, ev.getData()); + }, this); + loader.start(); + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + __schema: null, + _editor: null, + _basePath: null, + _workerWrapper: null, + _currentDecorations: null, + + _initWorker: function () { + this._workerWrapper = cv.ui.manager.editor.Worker.getInstance(); + this._workerWrapper.setEditor(this); + }, + + _getDefaultModelOptions: function () { + return { + tabSize: 2, + indentSize: 2, + insertSpaces: true + }; + }, + + _draw: function () { + if (!window.monaco) { + cv.ui.manager.editor.Source.load(this._draw, this); + } else { + var domElement = this.getContentElement().getDomElement(); + if (!domElement) { + this.addListenerOnce('appear', this._draw, this); + } else { + this._editor = window.monaco.editor.create(domElement, { + suggestOnTriggerCharacters: true, + folding: true, + autoIndent: true, + automaticLayout: true, + dragAndDrop: true, + formatOnPaste: true, + formatOnType: true, + minimap: { + enabled: true + }, + theme: 'vs-dark' + }); + if (this.getFile()) { + this._loadFile(this.getFile()); + } + this._editor.onDidChangeModelContent(this._onContentChanged.bind(this)); + } + } + }, + + handleAction: function (actionName) { + if (this.canHandleAction(actionName)) { + var monacoAction; + switch (actionName) { + case 'cut': + monacoAction = this._editor.getAction('editor.action.clipboardCutAction'); + break; + case 'copy': + monacoAction = this._editor.getAction('editor.action.clipboardCopyAction'); + break; + + default: + this.base(arguments, actionName); + break; + } + if (monacoAction) { + monacoAction.run(); + } + } + }, + + _loadFile: function (file, old) { + if (old && this._workerWrapper) { + this._workerWrapper.close(old); + } + if (this._editor) { + if (file && file.getType() === 'file' && this.isSupported(file)) { + this.base(arguments, file, old); + } else { + this.resetContent(); + } + } + }, + + _applyContent: function(value) { + var model = this._editor.getModel(); + var file = this.getFile(); + if (!value) { + if (model) { + this._editor.setValue(''); + } + } else { + if (this._workerWrapper) { + this._workerWrapper.open(file, value); + } + var newModel = window.monaco.editor.getModel(file.getUri()); + if (!newModel) { + // create new model + if (qx.xml.Document.isXmlDocument(value)) { + value = value.documentElement.outerHTML; + } + newModel = window.monaco.editor.createModel(value, this._getLanguage(file), file.getUri()); + } + + if (model !== newModel) { + newModel.updateOptions(this._getDefaultModelOptions()); + this._editor.setModel(newModel); + } else { + this._editor.setValue(value); + } + this._editor.updateOptions({ readOnly: !file.isWriteable() }); + } + }, + + getCurrentContent: function () { + return this._editor.getValue(); + }, + + _onContentChanged: function () { + if (this._workerWrapper) { + this._workerWrapper.contentChanged(this.getFile(), this._editor.getValue()); + } + }, + + isSupported: function (file) { + var fileType = file.getName().split('.').pop(); + return cv.ui.manager.editor.Source.SUPPORTED_FILES.includes(fileType); + }, + + showErrors: function (path, errorList) { + var markers = []; + var model = this._editor.getModel(); + if (!model) { + return; + } + // "file_0.xml:286: element layout: Schemas validity error : Element 'layout': This element is not expected." + if (errorList) { +// console.error(errorList); + var currentMessage = null; + // collect complete error messages + errorList.forEach(function (error) { + if (/.*\.xml:[\d]+:.+/.test(error)) { + if (currentMessage !== null) { + markers.push({ + severity: window.monaco.MarkerSeverity.Error, + startLineNumber: currentMessage.line, + startColumn: 1, + endLineNumber: currentMessage.line, + endColumn: model.getLineContent(currentMessage.line).length, + message: currentMessage.message + }); + } + // add marker for completed message + var parts = error.split(":"); + var file = parts.shift(); + var line = parseInt(parts.shift()); + + // in the last part there might be a more precise line number for the error + var match = /.+line ([\d]+) -+/.exec(parts[parts.length-1]); + if (match) { + line = parseInt(match[1]); + } + if (isNaN(line)) { + return; + } + // new error line + currentMessage = { + line: line, + message: parts.slice(-2).join(":"), + file: file + }; + } else { + currentMessage.message += "\n"+error; + } + }); + if (currentMessage !== null) { + // show last error too + markers.push({ + severity: window.monaco.MarkerSeverity.Error, + startLineNumber: currentMessage.line, + startColumn: 1, + endLineNumber: currentMessage.line, + endColumn: model.getLineContent(currentMessage.line).length, + message: currentMessage.message + }); + } + } + if (this.getFile().getFullPath() === path) { + window.monaco.editor.setModelMarkers(model, '', markers); + } else { + // TODO: save errors for later + } + }, + + showDecorations: function (path, decorators) { + if (this.getFile().getFullPath() === path) { + this._editor.deltaDecorations(this._currentDecorations[path], decorators); + } + this._currentDecorations[path] = decorators; + }, + + _getLanguage: function (file) { + var type = file.getName().split('.').pop(); + switch (type) { + case 'svg': + return 'xml'; + case 'js': + return 'javascript'; + case 'md': + return 'markdown'; + default: + return type; + } + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._workerWrapper = null; + if (this._editor) { + this._editor.dispose(); + this._editor = null; + } + qx.ui.core.FocusHandler.getInstance().setUseTabNavigation(true); + } +}); diff --git a/source/class/cv/ui/manager/editor/Worker.js b/source/class/cv/ui/manager/editor/Worker.js new file mode 100644 index 00000000000..f90a3dc627a --- /dev/null +++ b/source/class/cv/ui/manager/editor/Worker.js @@ -0,0 +1,140 @@ +/** + * + */ +qx.Class.define('cv.ui.manager.editor.Worker', { + extend: qx.core.Object, + type: 'singleton', + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._files = {}; + // create WebWorker + this._worker = new Worker(qx.util.ResourceManager.getInstance().toUri('manager/worker.js')); + this._worker.onmessage = this._onMessage.bind(this); + this._validationCallbacks = {}; + }, + + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + editor: { + check: 'cv.ui.manager.editor.Source', + nullable: true + } + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _worker: null, + _files: null, + _validationCallbacks: null, + + open: function (file, code, schema) { + this._worker.postMessage(["openFile", { + path: file.getFullPath(), + code: qx.xml.Document.isXmlDocument(code) ? code.documentElement.outerHTML : code, + schema: schema + }]); + this._files[file.getFullPath()] = file; + }, + + close: function (file) { + this._worker.postMessage(["closeFile", { + path: file.getFullPath() + }]); + delete this._files[file.getFullPath()]; + }, + + contentChanged: function (file, content) { + this._worker.postMessage(["contentChange", { + path: file.getFullPath(), + code: content + }]); + }, + + validateConfig: function (file) { + if (file.isConfigFile()) { + return new Promise(function (resolve, reject) { + // check if there is already one validation request ongoing + var url = file.getServerPath(); + if (!this._validationCallbacks.hasOwnProperty(url)) { + this._validationCallbacks[url] = [resolve]; + this._worker.postMessage(["validateConfig", { + path: url + }]); + } else { + this._validationCallbacks[url].push(resolve); + } + }.bind(this)); + } else { + qx.log.Logger.error(this, file.getFullPath() + ' is no configuration file'); + } + }, + + _onMessage: function (e) { + var topic = e.data.shift(); + var data = e.data.shift(); + var path = e.data.shift(); + var file = this._files[path]; + if (!file && topic !== 'validationResult') { + qx.log.Logger.error(this, 'no file found for path ' + path + ' ignoring worker message for topic ' + topic); + return; + } + var editor = this.getEditor(); + switch(topic) { + case "modified": + // new files are always modified, to not override that state + if (!file.isTemporary()) { + file.setModified(data.modified); + } + file.setHash(data.currentHash); + break; + + case "errors": + file.setValid(!data || data.length === 0); + if (editor) { + editor.showErrors(path, data); + } + break; + + case "decorations": + if (editor) { + editor.showDecorations(path, data); + } + break; + + case 'validationResult': + if (this._validationCallbacks.hasOwnProperty(path)) { + var callbacks = this._validationCallbacks[path]; + delete this._validationCallbacks[path]; + callbacks.forEach(function(cb) { + cb(data); + }); + } + break; + } + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + this._worker.terminate(); + this._worker = null; + } +}); diff --git a/source/class/cv/ui/manager/editor/Xml.js b/source/class/cv/ui/manager/editor/Xml.js new file mode 100644 index 00000000000..a5f7ab30773 --- /dev/null +++ b/source/class/cv/ui/manager/editor/Xml.js @@ -0,0 +1,119 @@ +/** + * Default XML-Editor included as iframe. + */ +qx.Class.define('cv.ui.manager.editor.Xml', { + extend: cv.ui.manager.editor.AbstractEditor, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + this._setLayout(new qx.ui.layout.Grow()); + this._handledActions = ['save']; + this.__basePath = qx.util.Uri.getAbsolute(window.location.pathname + qx.util.LibraryManager.getInstance().get("cv", "resourceUri") + '/../editor/editor.html'); + this._draw(); + }, + + /* + *********************************************** + STATICS + *********************************************** + */ + statics: { + SUPPORTED_FILES: /visu_config.*\.xml/, + TITLE: qx.locale.Manager.tr('Xml-editor'), + ICON: cv.theme.dark.Images.getIcon('xml', 18) + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + _currentContent: null, + + _draw: function () { + + }, + + _loadFile: function (file) { + if (this._iframe) { + this._iframe.destroy(); + } + var match = /.*visu_config_?(.*)\.xml/.exec(file.getName()); + if (match) { + this._iframe = new qx.ui.embed.Iframe(qx.util.Uri.appendParamsToUrl(this.__basePath, 'embed=0&config=' + match[1])); + this._iframe.addListener('load', function () { + // inject save method + this._iframe.getWindow().saveFromIframe = this.saveFromIframe.bind(this); + }, this); + + this._add(this._iframe); + } + }, + + saveFromIframe: function (data) { + // create XML string from data + var xml = ''; + data.forEach(function (elem) { + xml += this._elemToXml(elem, ''); + }, this); + this._currentContent = xml; + this._onContentChanged(); + this.save(); + }, + + _elemToXml: function (elem) { + var xml = ''; + if (elem.nodeName === '#text') { + xml += elem.nodeValue; + } else { + xml += '<' + elem.nodeName; + Object.keys(elem.attributes).forEach(function (attrName) { + xml += ' ' + attrName + '="' + elem.attributes[attrName] + '"'; + }); + + if (!elem.nodeValue && elem.children.length === 0) { + xml += '/>'; + } else { + xml += '>'; + if (elem.nodeValue) { + xml += elem.nodeValue; + } + var children = []; + elem.children.forEach(function (child) { + children.push(this._elemToXml(child)); + }, this); + xml += children.join(''); + xml += ''; + } + } + return xml; + }, + + getCurrentContent: function () { + return this._currentContent; + }, + + _onContentChanged: function () { + this.getFile().setModified(true); + }, + + isSupported: function (file) { + return cv.ui.manager.editor.Xml.SUPPORTED_FILES.test(file.getName()); + } + }, + + /* + *********************************************** + DESTRUCTOR + *********************************************** + */ + destruct: function () { + + } +}); diff --git a/source/class/cv/ui/manager/editor/completion/CometVisu.js b/source/class/cv/ui/manager/editor/completion/CometVisu.js new file mode 100644 index 00000000000..0f957e1e808 --- /dev/null +++ b/source/class/cv/ui/manager/editor/completion/CometVisu.js @@ -0,0 +1,132 @@ +/** + * + */ +qx.Class.define('cv.ui.manager.editor.completion.CometVisu', { + extend: qx.core.Object, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function () { + this.base(arguments); + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + TEMPLATES: null, + + getTemplates: function () { + if (!this.TEMPLATES) { + this.TEMPLATES = [{ + filterText: "cvclass", + label: 'CometVisu-Class', + kind: window.monaco.languages.CompletionItemKind.Class, + detail: "A generic CometVisu class.", + insertText: '/**\n * TODO: Add documentation\n * \n * @since ' + cv.Version.VERSION.replace('-dev', '') + ' ($CURRENT_YEAR)\n */\nqx.Class.define("cv.$0", {\n extend: qx.core.Object,\n\n \n});\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvwidget", + label: 'CometVisu-Widget', + kind: window.monaco.languages.CompletionItemKind.Class, + detail: "A CometVisu class for a widget.", + insertText: '/**\n * TODO: Add documentation\n * \n * @since ' + cv.Version.VERSION.replace('-dev', '') + ' ($CURRENT_YEAR)\n */\nqx.Class.define("cv.ui.structure.pure.$0", {\n extend: cv.ui.structure.AbstractWidget,\n\n \n});\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvinterface", + label: 'CometVisu-Interface', + kind: window.monaco.languages.CompletionItemKind.Interface, + detail: "A generic CometVisu Interface.", + insertText: '/**\n * TODO: Add documentation\n * \n * @since ' + cv.Version.VERSION.replace('-dev', '') + ' ($CURRENT_YEAR)\n */\nqx.Interface.define("cv.$0", {\n \n});\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvmixin", + label: 'CometVisu-Mixin', + kind: window.monaco.languages.CompletionItemKind.Class, + detail: "A generic CometVisu Mixin.", + insertText: '/**\n * TODO: Add documentation\n * \n * @since ' + cv.Version.VERSION.replace('-dev', '') + ' ($CURRENT_YEAR)\n */\nqx.Mixin.define("cv.$0", {\n \n});\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvmembers", + label: 'CometVisu-Class members', + kind: window.monaco.languages.CompletionItemKind.Struct, + detail: "A CometVisu classes members section.", + insertText: ' /*\n ***********************************************\n MEMBERS\n ***********************************************\n */\n members: {\n $0\n },\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvproperties", + label: 'CometVisu-Class properties', + kind: window.monaco.languages.CompletionItemKind.Struct, + detail: "A CometVisu classes properties section.", + insertText: ' /*\n ***********************************************\n PROPERTIES\n ***********************************************\n */\n properties: {\n $0\n },\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvstatics", + label: 'CometVisu-Class statics', + kind: window.monaco.languages.CompletionItemKind.Struct, + detail: "statics section.", + insertText: ' /*\n ***********************************************\n STATICS\n ***********************************************\n */\n statics: {\n $0\n },\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvevents", + label: 'CometVisu-Class events', + kind: window.monaco.languages.CompletionItemKind.Struct, + detail: "events section.", + insertText: ' /*\n ***********************************************\n EVENTS\n ***********************************************\n */\n events: {\n $0\n },\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvconstructor", + label: 'Constructor', + kind: window.monaco.languages.CompletionItemKind.Method, + detail: "constructor.", + insertText: ' /*\n ***********************************************\n CONSTRUCTOR\n ***********************************************\n */\n construct: function () {\n this.base(arguments);\n $0\n },\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }, { + filterText: "cvdestructor", + label: 'Destructor', + kind: window.monaco.languages.CompletionItemKind.Method, + detail: "destructor.", + insertText: ' /*\n ***********************************************\n DESTRUCTOR\n ***********************************************\n */\n destruct: function () {\n this.base(arguments);\n $0\n }\n', + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }]; + + // load plugin template from backend + return new Promise(function (resolve, reject) { + cv.io.rest.Client.getFsClient().readSync({path: '.templates/Plugin.js'}, function (err, res) { + if (err) { + reject(err); + } else { + this.TEMPLATES.push({ + filterText: "cvplugin", + label: 'CometVisu-Plugin', + kind: window.monaco.languages.CompletionItemKind.Class, + detail: "A CometVisu class for a plugin.", + insertText: res.replace('###SINCE###', cv.Version.VERSION.replace('-dev', '')+ ' ($CURRENT_YEAR)'), + insertTextRules: window.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet | window.monaco.languages.CompletionItemInsertTextRule.KeepWhitespace + }); + resolve(this.TEMPLATES); + } + }, this); + }.bind(this)); + } + return Promise.resolve(this.TEMPLATES); + }, + + getProvider: function () { + return { + triggerCharacters: ['cv'], + provideCompletionItems: function () { + // get editor content before the pointer + return this.getTemplates().then(function (sugg) { + return {suggestions: sugg}; + }); + }.bind(this) + }; + } + } +}); diff --git a/source/class/cv/ui/manager/editor/completion/Config.js b/source/class/cv/ui/manager/editor/completion/Config.js new file mode 100644 index 00000000000..dd568f2fed9 --- /dev/null +++ b/source/class/cv/ui/manager/editor/completion/Config.js @@ -0,0 +1,503 @@ +/** + * XSD-based code completion provider for the monaco text editor. + * + * @since 0.11.0 + * @author Tobias Bräutigam + */ +qx.Class.define('cv.ui.manager.editor.completion.Config', { + extend: qx.core.Object, + + /* + *********************************************** + CONSTRUCTOR + *********************************************** + */ + construct: function (schemaNode) { + this.base(arguments); + this.__elementCache = {}; + this._schemaNode = schemaNode; + this._dataProvider = cv.ui.manager.editor.data.Provider.getInstance(); + + }, + + /* + *********************************************** + MEMBERS + *********************************************** + */ + members: { + __elementCache: null, + __metaElementCache: null, + _schemaNode: null, + _dataProvider: null, + + getLastOpenedTag: function (text) { + // get all tags inside of the content + var tags = text.match(/<\/*(?=\S*)([a-zA-Z-]+)/g); + if (!tags) { + return undefined; + } + // we need to know which tags are closed + var closingTags = []; + for (var i = tags.length - 1; i >= 0; i--) { + if (tags[i].indexOf('', tagPosition); + // if the tag wasn't closed + if (closingBracketIdx === -1) { + // if there are no closing tags or the current tag wasn't closed + if (!closingTags.length || closingTags[closingTags.length - 1] !== tag) { + // we found our tag, but let's get the information if we are looking for + // a child element or an attribute + text = text.substring(tagPosition); + + var openedTag = text.indexOf('<') > text.indexOf('>'); + var contentSearch = false; + var currentAttribute = null; + if (openedTag) { + var attrMatch = /([\w\-_\.\d]+)="[^"]*$/.exec(text); + contentSearch = !!attrMatch; + currentAttribute = attrMatch ? attrMatch[1] : null; + } + var filteredElementSearch = /<[\w-_\d]+$/.test(text); + return { + tagName: tag, + currentAttribute: currentAttribute, + filteredElementSearch: filteredElementSearch, + isAttributeSearch: !filteredElementSearch && openedTag && !contentSearch, + isContentSearch: contentSearch, + text: text + }; + } + // remove the last closed tag + closingTags.splice(closingTags.length - 1, 1); + } + // remove the last checked tag and continue processing the rest of the content + text = text.substring(0, tagPosition); + } + } + }, + + findElements: function (parent, elementName, maxDepth, currentDepth, inMeta) { + var cache = inMeta === true ? this.__metaElementCache : this.__elementCache; + if (elementName in cache) { + return cache[elementName]; + } + if (maxDepth < currentDepth) { + return null; + } + if (!parent) { + parent = this._schemaNode.allowedRootElements.pages; + } + if (currentDepth === undefined) { + currentDepth = 1; + } + var allowedElements = parent.getAllowedElements(); + // console.log(parent.name+" looking for "+elementName+" in tree level "+currentDepth+ "(<"+maxDepth+") ("+Object.getOwnPropertyNames(allowedElements).join(", ")+")"); + if (elementName in allowedElements) { + // console.log("found "+elementName+" in tree level "+currentDepth); + this.__elementCache[elementName] = allowedElements[elementName]; + return allowedElements[elementName]; + } else { + for (var element in allowedElements) { + if (inMeta !== true && element === 'meta') { + continue; + } + if (maxDepth > currentDepth) { + var result = this.findElements(allowedElements[element], elementName, maxDepth, currentDepth + 1); + if (result) { + cache[elementName] = result; + // console.log("found " + elementName + " in tree level " + currentDepth); + return result; + } + } + } + } + + }, + + isItemAvailable: function (itemName, maxOccurs, items) { + // the default for 'maxOccurs' is 1 + maxOccurs = maxOccurs || '1'; + // the element can appere infinite times, so it is available + if (maxOccurs && maxOccurs === 'unbounded') { + return true; + } + // count how many times the element appeared + var count = 0; + for (var i = 0; i < items.length; i++) { + if (items[i] === itemName) { + count++; + } + } + // if it didn't appear yet, or it can appear again, then it + // is available, otherwise it't not + return count === 0 || parseInt(maxOccurs) > count; + }, + + getElementString: function (element, indent, prefix) { + var insertText = indent+prefix+element.name+" "; + // add all required attributes with default values + Object.getOwnPropertyNames(element.allowedAttributes).forEach(function(attr) { + var attribute = element.allowedAttributes[attr]; + if (!attribute.isOptional) { + insertText += attr+'="'+(attribute.defaultValue ? attribute.defaultValue : "")+'" '; + } + }); + // add mandatory children + var requiredElements = element.getRequiredElements(); + var allowedContent = element.getAllowedContent(); + var isContentAllowed = allowedContent._text || requiredElements.length > 0 || !!allowedContent._grouping; + if (!isContentAllowed) { + // close tag + insertText = insertText.trim()+"/"; + } else { + // close open tag + insertText = insertText.trim()+">"; + + // insert required elements + var children = 0; + requiredElements.forEach(function(elemName) { + var elem = this.findElements(element, elemName, 1, 0); + if (elem) { + insertText += "\n " + this.getElementString(elem, indent + " ", "<") + ">"; + children++; + } + }, this); + // add closing tag + if (children > 0) { + insertText += "\n"+indent; + } + insertText += "'); + var textMeta = metaEndPos > 0 ? completeText.substring(0, metaEndPos) : completeText; + var mappingNames = []; + var stylingNames = []; + var templates = {}; + var map, vmap; + var regex = /'); + if (templatesStart >= 0) { + var templatesString = textMeta.substring(templatesStart + 11, textMeta.indexOf('') - 12).replace(/(?:\r\n|\r|\n)/g, ''); + templatesString.split('').forEach(function (rawTemplate) { + var nameMatch = /