diff --git a/package-lock.json b/package-lock.json index 70a80acd6..a957c16e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,475 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/cli": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.8.4.tgz", + "integrity": "sha512-XXLgAm6LBbaNxaGhMAznXXaxtCWfuv6PIDJ9Alsy9JYTOh+j2jJz+L/162kkfU1j/pTSxK1xGmlwI4pdIMkoag==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "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, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "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, + "optional": 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, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "optional": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "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, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "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, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "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, + "optional": 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, + "optional": 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, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "optional": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "optional": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "optional": true + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "optional": true + }, + "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, + "optional": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -15788,9 +16257,9 @@ } }, "scratch-gui": { - "version": "0.1.0-prerelease.20200330211052", - "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20200330211052.tgz", - "integrity": "sha512-ANInG5YteFY2HnCXKBA1weyxSljFIGI2rfIhft2FIXKlyJA28QO8WqCwD008kdiRg2Mj9IXQNpkjWJbP8y5dzQ==", + "version": "0.1.0-prerelease.20200325184934", + "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20200325184934.tgz", + "integrity": "sha512-9iwSyff0s3Y6FSoFVZPAMMkKFumuG8pzdIwkGQlBcADGZ6w7/7HJcXqhAVHwBeeb4kYL2cSkSdcTICEeaIze0g==", "dev": true }, "scratch-l10n": { @@ -15803,475 +16272,6 @@ "@babel/core": "^7.1.2", "babel-plugin-react-intl": "^3.0.1", "transifex": "1.6.6" - }, - "dependencies": { - "@babel/cli": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.8.4.tgz", - "integrity": "sha512-XXLgAm6LBbaNxaGhMAznXXaxtCWfuv6PIDJ9Alsy9JYTOh+j2jJz+L/162kkfU1j/pTSxK1xGmlwI4pdIMkoag==", - "dev": true, - "requires": { - "chokidar": "^2.1.8", - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "lodash": "^4.17.13", - "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "optional": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "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, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "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, - "optional": 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, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "optional": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "optional": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "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, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "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, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "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, - "optional": 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, - "optional": 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, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "optional": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "optional": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "optional": true - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "optional": true - }, - "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, - "optional": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } } }, "scratch-parser": { diff --git a/package.json b/package.json index 2596e9360..ccb1b57e2 100644 --- a/package.json +++ b/package.json @@ -128,8 +128,8 @@ "redux-mock-store": "^1.2.3", "redux-thunk": "2.0.1", "sass-loader": "6.0.6", - "scratch-gui": "0.1.0-prerelease.20200330211052", - "scratch-l10n": "^3.8.20200325112845", + "scratch-gui": "0.1.0-prerelease.20200325184934", + "scratch-l10n": "latest", "selenium-webdriver": "3.6.0", "slick-carousel": "1.6.0", "source-map-support": "0.3.2", diff --git a/src/components/captcha/captcha.jsx b/src/components/captcha/captcha.jsx new file mode 100644 index 000000000..f6ba27efe --- /dev/null +++ b/src/components/captcha/captcha.jsx @@ -0,0 +1,76 @@ +const bindAll = require('lodash.bindall'); +const PropTypes = require('prop-types'); +const React = require('react'); + +class Captcha extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'setCaptchaRef', + 'onCaptchaLoad', + 'executeCaptcha' + ]); + + } + componentDidMount () { + if (window.grecaptcha) { + this.onCaptchaLoad(); + } else { + // If grecaptcha doesn't exist on window, we havent loaded the captcha js yet. Load it. + // ReCaptcha calls a callback when the grecatpcha object is usable. That callback + // needs to be global so set it on the window. + window.grecaptchaOnLoad = this.onCaptchaLoad; + // Load Google ReCaptcha script. + const script = document.createElement('script'); + script.async = true; + script.onerror = this.props.onCaptchaError; + script.src = `https://www.recaptcha.net/recaptcha/api.js?onload=grecaptchaOnLoad&render=explicit&hl=${window._locale}`; + document.body.appendChild(script); + } + } + componentWillUnmount () { + window.grecaptchaOnLoad = null; + } + + onCaptchaLoad () { + // Let the owner of this component do some work + // when captcha is done loading (e.g. enabling a button) + this.props.onCaptchaLoad(); + this.grecaptcha = window.grecaptcha; + if (!this.grecaptcha) { + // According to the reCaptcha documentation, this callback shouldn't get + // called unless window.grecaptcha exists. This is just here to be extra defensive. + this.props.onCaptchaError(); + return; + } + this.widgetId = this.grecaptcha.render(this.captchaRef, + { + callback: this.props.onCaptchaSolved, + sitekey: process.env.RECAPTCHA_SITE_KEY + }, + true); + } + setCaptchaRef (ref) { + this.captchaRef = ref; + } + executeCaptcha () { + this.grecaptcha.execute(this.widgetId); + } + render () { + return ( +
+ ); + } +} +Captcha.propTypes = { + onCaptchaError: PropTypes.func.isRequired, + onCaptchaLoad: PropTypes.func.isRequired, + onCaptchaSolved: PropTypes.func.isRequired +}; +module.exports = Captcha; diff --git a/src/components/cats/cats.jsx b/src/components/cats/cats.jsx deleted file mode 100644 index 6545e0b7c..000000000 --- a/src/components/cats/cats.jsx +++ /dev/null @@ -1,149 +0,0 @@ -const React = require('react'); -const bindAll = require('lodash.bindall'); - -const Modal = require('../modal/base/modal.jsx'); -const ModalTitle = require('../modal/base/modal-title.jsx'); - -require('./cats.scss'); - -const catImages = [ - '/images/cats/IMG_9775.jpg', - '/images/cats/IMG_9766.jpg', - '/images/cats/IMG_9587.jpg', - '/images/cats/IMG_6558.jpg', - '/images/cats/IMG_6521.jpg', - '/images/cats/IMG_6020.jpg', - '/images/cats/IMG_5880.jpg', - '/images/cats/IMG_3218.jpg', - '/images/cats/IMG_2776.jpg', - '/images/cats/IMG_2775.jpg', - '/images/cats/IMG_2681.jpg', - '/images/cats/IMG_1092.jpg', - '/images/cats/IMG_0684.jpg', - '/images/cats/IMG_0698.jpg', - '/images/cats/IMG_0504.jpg', - '/images/cats/IMG_0288.jpg', - '/images/cats/IMG_0122.jpg', - '/images/cats/IMG_2507.jpg', - '/images/cats/IMG_1977.jpg', - '/images/cats/IMG_1696.jpg', - '/images/cats/IMG_1463.jpg', - '/images/cats/IMG_1157.jpg', - '/images/cats/IMG_0681.jpg', - '/images/cats/IMG_0135.jpg', - '/images/cats/IMG_0071.jpg', - '/images/cats/1.jpg', - '/images/cats/2.jpg', - '/images/cats/3.jpg', - '/images/cats/4.jpg', - '/images/cats/Cat1.jpg', - '/images/cats/Cat2.jpg', - '/images/cats/Cat3.jpg', - '/images/cats/Cat4.jpg', - '/images/cats/Cat5.jpg', - '/images/cats/Cat6.png', - '/images/cats/Cat7.jpg', - '/images/cats/Cat8.jpg', - '/images/cats/Cat9.jpg', - '/images/cats/Cat10.png', - '/images/cats/Cat11.png', - '/images/cats/Cat12.png', - '/images/cats/IMG_2167.jpg', - '/images/cats/IMG_4316.jpg', - '/images/cats/IMG_5396.jpg' -]; - -/* eslint-disable max-len */ -const mysteryFacts = [ - 'How small can they make a t-shirt?', - 'Why do hotdogs come in packages of 8?', - 'Who let the dogs out?', - 'Why are cats so cute?', - 'Where is the other sock?', - 'Why is the sky blue?', - 'Why does everyday end in y?', - 'How many licks does it take to get to the center of a lollipop? ', - 'How many bites does it take to get to the center of a corndog?', - 'How many hours can a cat sleep in one day?', - 'Am I hungry?', - 'What should I eat?', - 'Who will make me a sandwich?', - 'Where are my glasses?', - 'Why did I walk into this room?', - 'Where is the bathroom?', - 'Where is the mop?', - 'Why are ants so strong?', - 'Why do I wake up before my alarm goes off?', - 'Where do almonds come from?', - 'When is the sky blue?', - 'Wherefore art thou Romeo?', - 'What was the Scratch Cat like as a kitten?', - 'What is the plural of Moose?', - 'Whose chair is that?', - 'Who paid for that floor?', - 'What is my cat\'s favorite color?', - 'What is that cat\'s favorite color?', - 'Does the "close door" button on an elevator really work?' -]; - -/* eslint-enable max-len */ - -class Cats extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleCatsClick', - 'handleClose', - 'pickRandomFact' - ]); - this.state = { - open: false - }; - } - - handleCatsClick () { - this.setState({open: true}); - } - - handleClose () { - this.setState({open: false}); - } - - pickRandomFact () { - const randomNumber = Math.floor(Math.random() * (mysteryFacts.length - 1)); - const catFact = mysteryFacts[randomNumber]; - return catFact; - } - - pickRandomCatImage () { - const randomNumber = Math.floor(Math.random() * (catImages.length - 1)); - const catImage = catImages[randomNumber]; - return catImage; - } - - render () { - return ( -
- {'Mystery'} -
- -
- -
-
-

{this.pickRandomFact()}

- -
-
-
- ); - - } -} - -module.exports = Cats; diff --git a/src/components/cats/cats.scss b/src/components/cats/cats.scss deleted file mode 100644 index 83b546e3f..000000000 --- a/src/components/cats/cats.scss +++ /dev/null @@ -1,34 +0,0 @@ -@import "../../colors"; -@import "../../frameless"; - -.mod-cats { - min-height: 15rem; - max-height: calc(100% - 5rem); - - overflow: hidden; -} - -.cats-modal-header { - box-shadow: inset 0 -1px 0 0 $ui-blue-dark; - background-color: $ui-blue; -} - -.cats-modal-content { - margin: 0 auto; - box-shadow: none; - width: 100%; - - display: flex; - flex-direction: column; - align-items: center; - - padding: 20px 50px; -} - -.cats-modal-content img { - width: 400px; - - @media #{$small}, #{$small-height} { - width: 100%; - } -} diff --git a/src/components/footer/www/footer.jsx b/src/components/footer/www/footer.jsx index 64a0b7f95..f533c8a3c 100644 --- a/src/components/footer/www/footer.jsx +++ b/src/components/footer/www/footer.jsx @@ -6,7 +6,6 @@ const React = require('react'); const FooterBox = require('../container/footer.jsx'); const LanguageChooser = require('../../languagechooser/languagechooser.jsx'); -const Cats = require('../../cats/cats.jsx'); const frameless = require('../../../lib/frameless'); @@ -32,9 +31,6 @@ const Footer = props => ( -
- -
@@ -96,9 +92,6 @@ const Footer = props => (
-
- -
diff --git a/src/components/join-flow/email-step.jsx b/src/components/join-flow/email-step.jsx index d73b08d89..48fe7dad7 100644 --- a/src/components/join-flow/email-step.jsx +++ b/src/components/join-flow/email-step.jsx @@ -11,7 +11,7 @@ const JoinFlowStep = require('./join-flow-step.jsx'); const FormikInput = require('../../components/formik-forms/formik-input.jsx'); const FormikCheckbox = require('../../components/formik-forms/formik-checkbox.jsx'); const InfoButton = require('../info-button/info-button.jsx'); - +const Captcha = require('../../components/captcha/captcha.jsx'); require('./join-flow-steps.scss'); class EmailStep extends React.Component { @@ -24,8 +24,8 @@ class EmailStep extends React.Component { 'validateEmailRemotelyWithCache', 'validateForm', 'setCaptchaRef', - 'captchaSolved', - 'onCaptchaLoad' + 'handleCaptchaSolved', + 'handleCaptchaLoad' ]); this.state = { captchaIsLoading: true @@ -40,43 +40,12 @@ class EmailStep extends React.Component { } // automatically start with focus on username field if (this.emailInput) this.emailInput.focus(); - - if (window.grecaptcha) { - this.onCaptchaLoad(); - } else { - // If grecaptcha doesn't exist on window, we havent loaded the captcha js yet. Load it. - // ReCaptcha calls a callback when the grecatpcha object is usable. That callback - // needs to be global so set it on the window. - window.grecaptchaOnLoad = this.onCaptchaLoad; - // Load Google ReCaptcha script. - const script = document.createElement('script'); - script.async = true; - script.onerror = this.props.onCaptchaError; - script.src = `https://www.recaptcha.net/recaptcha/api.js?onload=grecaptchaOnLoad&render=explicit&hl=${window._locale}`; - document.body.appendChild(script); - } - } - componentWillUnmount () { - window.grecaptchaOnLoad = null; } handleSetEmailRef (emailInputRef) { this.emailInput = emailInputRef; } - onCaptchaLoad () { + handleCaptchaLoad () { this.setState({captchaIsLoading: false}); - this.grecaptcha = window.grecaptcha; - if (!this.grecaptcha) { - // According to the reCaptcha documentation, this callback shouldn't get - // called unless window.grecaptcha exists. This is just here to be extra defensive. - this.props.onCaptchaError(); - return; - } - this.widgetId = this.grecaptcha.render(this.captchaRef, - { - callback: this.captchaSolved, - sitekey: process.env.RECAPTCHA_SITE_KEY - }, - true); } // simple function to memoize remote requests for usernames validateEmailRemotelyWithCache (email) { @@ -116,9 +85,9 @@ class EmailStep extends React.Component { // Change set submitting to false so that if the user clicks out of // the captcha, the button is clickable again (instead of a disabled button with a spinner). this.formikBag.setSubmitting(false); - this.grecaptcha.execute(this.widgetId); + this.captchaRef.executeCaptcha(); } - captchaSolved (token) { + handleCaptchaSolved (token) { // Now thatcaptcha is done, we can tell Formik we're submitting. this.formikBag.setSubmitting(true); this.formData['g-recaptcha-response'] = token; @@ -224,12 +193,11 @@ class EmailStep extends React.Component { name="subscribe" />
-
); diff --git a/src/components/registration/steps.jsx b/src/components/registration/steps.jsx index e525b2c38..42fe4714f 100644 --- a/src/components/registration/steps.jsx +++ b/src/components/registration/steps.jsx @@ -12,6 +12,7 @@ const intl = require('../../lib/intl.jsx'); const Avatar = require('../../components/avatar/avatar.jsx'); const Button = require('../../components/forms/button.jsx'); +const Captcha = require('../../components/captcha/captcha.jsx'); const Card = require('../../components/card/card.jsx'); const CharCount = require('../../components/forms/charcount.jsx'); const Checkbox = require('../../components/forms/checkbox.jsx'); @@ -1198,12 +1199,36 @@ class EmailStep extends React.Component { constructor (props) { super(props); bindAll(this, [ - 'handleValidSubmit' + 'handleCaptchaError', + 'handleCaptchaLoad', + 'handleCaptchaSolved', + 'handleValidSubmit', + 'setCaptchaRef' ]); this.state = { waiting: false }; } + handleCaptchaLoad () { + this.setState({ + waiting: true + }); + } + handleCaptchaSolved (token) { + this.setState({ + waiting: false + }); + this.formData['g-recaptcha-response'] = token; + this.setState({'g-recaptcha-response': token}); + this.props.onNextStep(this.formData); + } + handleCaptchaError () { + this.props.setRegistrationError( + this.props.intl.formatMessage({id: 'registration.errorCaptcha'})); + } + setCaptchaRef (ref) { + this.captchaRef = ref; + } handleValidSubmit (formData, reset, invalidate) { this.setState({waiting: true}); api({ @@ -1219,7 +1244,8 @@ class EmailStep extends React.Component { res = res[0]; switch (res.msg) { case 'valid email': - return this.props.onNextStep(formData); + this.formData = formData; + return this.captchaRef.executeCaptcha(); default: return invalidate({'user.email': res.msg}); } @@ -1283,6 +1309,12 @@ class EmailStep extends React.Component { active={this.props.activeStep} steps={this.props.totalSteps - 1} /> + ); } @@ -1292,6 +1324,7 @@ EmailStep.propTypes = { activeStep: PropTypes.number, intl: intlShape, onNextStep: PropTypes.func, + setRegistrationError: PropTypes.func, totalSteps: PropTypes.number, waiting: PropTypes.bool }; diff --git a/src/template.ejs b/src/template.ejs index 37a721d80..dc46b019e 100644 --- a/src/template.ejs +++ b/src/template.ejs @@ -79,5 +79,5 @@ } <% } %> -
;
+ diff --git a/src/views/teacherregistration/teacherregistration.jsx b/src/views/teacherregistration/teacherregistration.jsx index a1d2eae3a..2936ad82f 100644 --- a/src/views/teacherregistration/teacherregistration.jsx +++ b/src/views/teacherregistration/teacherregistration.jsx @@ -23,7 +23,8 @@ class TeacherRegistration extends React.Component { super(props); bindAll(this, [ 'handleAdvanceStep', - 'handleRegister' + 'handleRegister', + 'setRegistrationError' ]); this.state = { formData: {}, @@ -32,6 +33,9 @@ class TeacherRegistration extends React.Component { waiting: false }; } + setRegistrationError (err) { + this.setState({registrationError: err}); + } handleAdvanceStep (formData) { formData = formData || {}; this.setState({ @@ -47,34 +51,35 @@ class TeacherRegistration extends React.Component { method: 'post', useCsrf: true, formData: { - username: this.state.formData.user.username, - email: formData.user.email, - password: this.state.formData.user.password, - birth_month: this.state.formData.user.birth.month, - birth_year: this.state.formData.user.birth.year, - gender: ( + 'username': this.state.formData.user.username, + 'email': formData.user.email, + 'g-recaptcha-response': formData['g-recaptcha-response'], + 'password': this.state.formData.user.password, + 'birth_month': this.state.formData.user.birth.month, + 'birth_year': this.state.formData.user.birth.year, + 'gender': ( this.state.formData.user.gender === 'other' ? this.state.formData.user.genderOther : this.state.formData.user.gender ), - country: this.state.formData.user.country, - subscribe: formData.subscribe, - is_robot: this.state.formData.user.isRobot, - first_name: this.state.formData.user.name.first, - last_name: this.state.formData.user.name.last, - phone_number: this.state.formData.phone.national_number, - organization_name: this.state.formData.organization.name, - organization_title: this.state.formData.organization.title, - organization_type: this.state.formData.organization.type, - organization_other: this.state.formData.organization.other, - organization_url: this.state.formData.organization.url, - address_country: this.state.formData.address.country, - address_line1: this.state.formData.address.line1, - address_line2: this.state.formData.address.line2, - address_city: this.state.formData.address.city, - address_state: this.state.formData.address.state, - address_zip: this.state.formData.address.zip, - how_use_scratch: this.state.formData.useScratch + 'country': this.state.formData.user.country, + 'subscribe': formData.subscribe, + 'is_robot': this.state.formData.user.isRobot, + 'first_name': this.state.formData.user.name.first, + 'last_name': this.state.formData.user.name.last, + 'phone_number': this.state.formData.phone.national_number, + 'organization_name': this.state.formData.organization.name, + 'organization_title': this.state.formData.organization.title, + 'organization_type': this.state.formData.organization.type, + 'organization_other': this.state.formData.organization.other, + 'organization_url': this.state.formData.organization.url, + 'address_country': this.state.formData.address.country, + 'address_line1': this.state.formData.address.line1, + 'address_line2': this.state.formData.address.line2, + 'address_city': this.state.formData.address.city, + 'address_state': this.state.formData.address.state, + 'address_zip': this.state.formData.address.zip, + 'how_use_scratch': this.state.formData.useScratch } }, (err, body, res) => { this.setState({waiting: false}); @@ -133,6 +138,7 @@ class TeacherRegistration extends React.Component { onNextStep={this.handleAdvanceStep} /> diff --git a/static/images/cats/1.jpg b/static/images/cats/1.jpg deleted file mode 100644 index 88df1b50d..000000000 Binary files a/static/images/cats/1.jpg and /dev/null differ diff --git a/static/images/cats/2.jpg b/static/images/cats/2.jpg deleted file mode 100644 index f4fd33633..000000000 Binary files a/static/images/cats/2.jpg and /dev/null differ diff --git a/static/images/cats/3.jpg b/static/images/cats/3.jpg deleted file mode 100644 index a97ae3c4d..000000000 Binary files a/static/images/cats/3.jpg and /dev/null differ diff --git a/static/images/cats/4.jpg b/static/images/cats/4.jpg deleted file mode 100644 index 53492ff29..000000000 Binary files a/static/images/cats/4.jpg and /dev/null differ diff --git a/static/images/cats/Cat1.jpg b/static/images/cats/Cat1.jpg deleted file mode 100644 index 580ccfe6a..000000000 Binary files a/static/images/cats/Cat1.jpg and /dev/null differ diff --git a/static/images/cats/Cat10.png b/static/images/cats/Cat10.png deleted file mode 100644 index 380d8ffb6..000000000 Binary files a/static/images/cats/Cat10.png and /dev/null differ diff --git a/static/images/cats/Cat11.png b/static/images/cats/Cat11.png deleted file mode 100644 index e344ddaad..000000000 Binary files a/static/images/cats/Cat11.png and /dev/null differ diff --git a/static/images/cats/Cat12.png b/static/images/cats/Cat12.png deleted file mode 100644 index bb300279f..000000000 Binary files a/static/images/cats/Cat12.png and /dev/null differ diff --git a/static/images/cats/Cat2.jpg b/static/images/cats/Cat2.jpg deleted file mode 100644 index 002ad0ad1..000000000 Binary files a/static/images/cats/Cat2.jpg and /dev/null differ diff --git a/static/images/cats/Cat3.jpg b/static/images/cats/Cat3.jpg deleted file mode 100644 index 3d7cc6400..000000000 Binary files a/static/images/cats/Cat3.jpg and /dev/null differ diff --git a/static/images/cats/Cat4.jpg b/static/images/cats/Cat4.jpg deleted file mode 100644 index b739f23ad..000000000 Binary files a/static/images/cats/Cat4.jpg and /dev/null differ diff --git a/static/images/cats/Cat5.jpg b/static/images/cats/Cat5.jpg deleted file mode 100644 index 5b9105b1a..000000000 Binary files a/static/images/cats/Cat5.jpg and /dev/null differ diff --git a/static/images/cats/Cat6.png b/static/images/cats/Cat6.png deleted file mode 100644 index 45725c933..000000000 Binary files a/static/images/cats/Cat6.png and /dev/null differ diff --git a/static/images/cats/Cat7.jpg b/static/images/cats/Cat7.jpg deleted file mode 100644 index e6658e5aa..000000000 Binary files a/static/images/cats/Cat7.jpg and /dev/null differ diff --git a/static/images/cats/Cat8.jpg b/static/images/cats/Cat8.jpg deleted file mode 100644 index 5b721cf2c..000000000 Binary files a/static/images/cats/Cat8.jpg and /dev/null differ diff --git a/static/images/cats/Cat9.jpg b/static/images/cats/Cat9.jpg deleted file mode 100644 index bd1bef3c9..000000000 Binary files a/static/images/cats/Cat9.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0071.jpg b/static/images/cats/IMG_0071.jpg deleted file mode 100644 index 03f608775..000000000 Binary files a/static/images/cats/IMG_0071.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0122.jpg b/static/images/cats/IMG_0122.jpg deleted file mode 100644 index 36691f24b..000000000 Binary files a/static/images/cats/IMG_0122.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0135.jpg b/static/images/cats/IMG_0135.jpg deleted file mode 100644 index 0bc2e3271..000000000 Binary files a/static/images/cats/IMG_0135.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0288.jpg b/static/images/cats/IMG_0288.jpg deleted file mode 100644 index d6485b376..000000000 Binary files a/static/images/cats/IMG_0288.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0504.jpg b/static/images/cats/IMG_0504.jpg deleted file mode 100644 index 46b690ced..000000000 Binary files a/static/images/cats/IMG_0504.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0681.jpg b/static/images/cats/IMG_0681.jpg deleted file mode 100644 index 1f8a41eaf..000000000 Binary files a/static/images/cats/IMG_0681.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0684.jpg b/static/images/cats/IMG_0684.jpg deleted file mode 100644 index 159c126eb..000000000 Binary files a/static/images/cats/IMG_0684.jpg and /dev/null differ diff --git a/static/images/cats/IMG_0698.jpg b/static/images/cats/IMG_0698.jpg deleted file mode 100644 index 53b92d4dd..000000000 Binary files a/static/images/cats/IMG_0698.jpg and /dev/null differ diff --git a/static/images/cats/IMG_1092.jpg b/static/images/cats/IMG_1092.jpg deleted file mode 100644 index b26377019..000000000 Binary files a/static/images/cats/IMG_1092.jpg and /dev/null differ diff --git a/static/images/cats/IMG_1157.jpg b/static/images/cats/IMG_1157.jpg deleted file mode 100644 index c7f3a1d15..000000000 Binary files a/static/images/cats/IMG_1157.jpg and /dev/null differ diff --git a/static/images/cats/IMG_1463.jpg b/static/images/cats/IMG_1463.jpg deleted file mode 100644 index 17649f55a..000000000 Binary files a/static/images/cats/IMG_1463.jpg and /dev/null differ diff --git a/static/images/cats/IMG_1696.jpg b/static/images/cats/IMG_1696.jpg deleted file mode 100644 index b84e8e237..000000000 Binary files a/static/images/cats/IMG_1696.jpg and /dev/null differ diff --git a/static/images/cats/IMG_1977.jpg b/static/images/cats/IMG_1977.jpg deleted file mode 100644 index f0d1e6fcc..000000000 Binary files a/static/images/cats/IMG_1977.jpg and /dev/null differ diff --git a/static/images/cats/IMG_2167.jpg b/static/images/cats/IMG_2167.jpg deleted file mode 100644 index 8e3f0c994..000000000 Binary files a/static/images/cats/IMG_2167.jpg and /dev/null differ diff --git a/static/images/cats/IMG_2507.jpg b/static/images/cats/IMG_2507.jpg deleted file mode 100644 index 6209adf94..000000000 Binary files a/static/images/cats/IMG_2507.jpg and /dev/null differ diff --git a/static/images/cats/IMG_2681.jpg b/static/images/cats/IMG_2681.jpg deleted file mode 100644 index 632b7b31e..000000000 Binary files a/static/images/cats/IMG_2681.jpg and /dev/null differ diff --git a/static/images/cats/IMG_2775.jpg b/static/images/cats/IMG_2775.jpg deleted file mode 100644 index 6b4091c2d..000000000 Binary files a/static/images/cats/IMG_2775.jpg and /dev/null differ diff --git a/static/images/cats/IMG_2776.jpg b/static/images/cats/IMG_2776.jpg deleted file mode 100644 index 5f564302b..000000000 Binary files a/static/images/cats/IMG_2776.jpg and /dev/null differ diff --git a/static/images/cats/IMG_3218.jpg b/static/images/cats/IMG_3218.jpg deleted file mode 100644 index b3b98a87a..000000000 Binary files a/static/images/cats/IMG_3218.jpg and /dev/null differ diff --git a/static/images/cats/IMG_4316.jpg b/static/images/cats/IMG_4316.jpg deleted file mode 100644 index 293ab4429..000000000 Binary files a/static/images/cats/IMG_4316.jpg and /dev/null differ diff --git a/static/images/cats/IMG_5396.jpg b/static/images/cats/IMG_5396.jpg deleted file mode 100644 index f351faea8..000000000 Binary files a/static/images/cats/IMG_5396.jpg and /dev/null differ diff --git a/static/images/cats/IMG_5880.jpg b/static/images/cats/IMG_5880.jpg deleted file mode 100644 index 971488cce..000000000 Binary files a/static/images/cats/IMG_5880.jpg and /dev/null differ diff --git a/static/images/cats/IMG_6020.jpg b/static/images/cats/IMG_6020.jpg deleted file mode 100644 index 5557eff2f..000000000 Binary files a/static/images/cats/IMG_6020.jpg and /dev/null differ diff --git a/static/images/cats/IMG_6521.jpg b/static/images/cats/IMG_6521.jpg deleted file mode 100644 index e8b744d0c..000000000 Binary files a/static/images/cats/IMG_6521.jpg and /dev/null differ diff --git a/static/images/cats/IMG_6558.jpg b/static/images/cats/IMG_6558.jpg deleted file mode 100644 index b1250b48b..000000000 Binary files a/static/images/cats/IMG_6558.jpg and /dev/null differ diff --git a/static/images/cats/IMG_9587.jpg b/static/images/cats/IMG_9587.jpg deleted file mode 100644 index 3a2dd5761..000000000 Binary files a/static/images/cats/IMG_9587.jpg and /dev/null differ diff --git a/static/images/cats/IMG_9766.jpg b/static/images/cats/IMG_9766.jpg deleted file mode 100644 index 0e9041b37..000000000 Binary files a/static/images/cats/IMG_9766.jpg and /dev/null differ diff --git a/static/images/cats/IMG_9775.jpg b/static/images/cats/IMG_9775.jpg deleted file mode 100644 index 72d361b20..000000000 Binary files a/static/images/cats/IMG_9775.jpg and /dev/null differ diff --git a/test/unit/components/captcha.test.jsx b/test/unit/components/captcha.test.jsx new file mode 100644 index 000000000..027f721c6 --- /dev/null +++ b/test/unit/components/captcha.test.jsx @@ -0,0 +1,57 @@ +const React = require('react'); +const enzyme = require('enzyme'); + + +const Captcha = require('../../../src/components/captcha/captcha.jsx'); + +describe('Captcha test', () => { + global.grecaptcha = { + execute: jest.fn(), + render: jest.fn() + }; + + test('Captcha load calls props captchaOnLoad', () => { + const props = { + onCaptchaLoad: jest.fn() + }; + const wrapper = enzyme.shallow(); + wrapper.instance().onCaptchaLoad(); + expect(global.grecaptcha.render).toHaveBeenCalled(); + expect(props.onCaptchaLoad).toHaveBeenCalled(); + }); + + test('Captcha execute calls grecatpcha execute', () => { + const props = { + onCaptchaLoad: jest.fn() + }; + const wrapper = enzyme.shallow(); + wrapper.instance().executeCaptcha(); + expect(global.grecaptcha.execute).toHaveBeenCalled(); + }); + + test('Captcha load calls props captchaOnLoad', () => { + const props = { + onCaptchaLoad: jest.fn() + }; + const wrapper = enzyme.shallow(); + wrapper.instance().onCaptchaLoad(); + expect(global.grecaptcha.render).toHaveBeenCalled(); + expect(props.onCaptchaLoad).toHaveBeenCalled(); + }); + + test('Captcha renders the div google wants', () => { + const props = { + onCaptchaLoad: jest.fn() + }; + const wrapper = enzyme.mount(); + expect(wrapper.find('div.g-recaptcha')).toHaveLength(1); + }); +}); diff --git a/test/unit/components/email-step.test.jsx b/test/unit/components/email-step.test.jsx index 3f2c866d0..25b813d5a 100644 --- a/test/unit/components/email-step.test.jsx +++ b/test/unit/components/email-step.test.jsx @@ -115,9 +115,9 @@ describe('EmailStep test', () => { const formikBag = { setSubmitting: jest.fn() }; - global.grecaptcha = { - execute: jest.fn(), - render: jest.fn() + + const captchaRef = { + executeCaptcha: jest.fn() }; const formData = {item1: 'thing', item2: 'otherthing'}; const intlWrapper = shallowWithIntl( @@ -125,13 +125,12 @@ describe('EmailStep test', () => { {...defaultProps()} />); - const emailStepWrapper = intlWrapper.dive(); - emailStepWrapper.instance().onCaptchaLoad(); // to setup catpcha state + emailStepWrapper.instance().setCaptchaRef(captchaRef); emailStepWrapper.instance().handleValidSubmit(formData, formikBag); expect(formikBag.setSubmitting).toHaveBeenCalledWith(false); - expect(global.grecaptcha.execute).toHaveBeenCalled(); + expect(captchaRef.executeCaptcha).toHaveBeenCalled(); }); test('captchaSolved sets token and goes to next step', () => { @@ -141,9 +140,8 @@ describe('EmailStep test', () => { const formikBag = { setSubmitting: jest.fn() }; - global.grecaptcha = { - execute: jest.fn(), - render: jest.fn() + const captchaRef = { + executeCaptcha: jest.fn() }; const formData = {item1: 'thing', item2: 'otherthing'}; const intlWrapper = shallowWithIntl( @@ -154,11 +152,11 @@ describe('EmailStep test', () => { const emailStepWrapper = intlWrapper.dive(); // Call these to setup captcha. - emailStepWrapper.instance().onCaptchaLoad(); // to setup catpcha state + emailStepWrapper.instance().setCaptchaRef(captchaRef); // to setup catpcha state emailStepWrapper.instance().handleValidSubmit(formData, formikBag); const captchaToken = 'abcd'; - emailStepWrapper.instance().captchaSolved(captchaToken); + emailStepWrapper.instance().handleCaptchaSolved(captchaToken); // Make sure captchaSolved calls onNextStep with formData that has // a captcha token and left everything else in the object in place. expect(props.onNextStep).toHaveBeenCalledWith( @@ -170,29 +168,13 @@ describe('EmailStep test', () => { expect(formikBag.setSubmitting).toHaveBeenCalledWith(true); }); - test('Captcha load error calls error function', () => { - const props = { - onCaptchaError: jest.fn() - }; - // Set this to null to force an error. - global.grecaptcha = null; - const intlWrapper = shallowWithIntl( - - ); - - const emailStepWrapper = intlWrapper.dive(); - emailStepWrapper.instance().onCaptchaLoad(); - expect(props.onCaptchaError).toHaveBeenCalled(); - }); - test('Component logs analytics', () => { const sendAnalyticsFn = jest.fn(); + const onCaptchaError = jest.fn(); mountWithIntl( ); expect(sendAnalyticsFn).toHaveBeenCalledWith('join-email'); });