From 008c9380b15dbfeeafb7261883161254fc6e20fe Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 25 Feb 2020 00:38:03 -0500 Subject: [PATCH 01/64] Switched notice to react --- package-lock.json | 925 +++++++++++++++++++++++-- package.json | 10 +- src/background.ts | 4 - src/components/SkipNoticeComponent.tsx | 406 +++++++++++ src/content.ts | 12 +- src/render/SkipNotice.tsx | 50 ++ tsconfig.json | 3 +- 7 files changed, 1329 insertions(+), 81 deletions(-) create mode 100644 src/components/SkipNoticeComponent.tsx create mode 100644 src/render/SkipNotice.tsx diff --git a/package-lock.json b/package-lock.json index 1521214b12..870edfa295 100644 --- a/package-lock.json +++ b/package-lock.json @@ -694,6 +694,28 @@ "integrity": "sha512-hx6zWtudh3Arsbl3cXay+JnkvVgCKzCWKv42C9J01N2T2np4h8w5X8u6Tpz5mj38kE3M9FM0Pazx8vKFFMnjLQ==", "dev": true }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/react": { + "version": "16.9.22", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.22.tgz", + "integrity": "sha512-7OSt4EGiLvy0h5R7X+r0c7S739TCU/LvWbkNOrm10lUwNHe7XPz5OLhLOSZeCkqO9JSCly1NkYJ7ODTUqVnHJQ==", + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-dom": { + "version": "16.9.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.5.tgz", + "integrity": "sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg==", + "requires": { + "@types/react": "*" + } + }, "@types/sizzle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", @@ -1417,11 +1439,15 @@ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, + "babel": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel/-/babel-6.23.0.tgz", + "integrity": "sha1-0NHn2APpdHZb7qMjLU4VPA77kPQ=" + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, "requires": { "chalk": "^1.1.3", "esutils": "^2.0.2", @@ -1431,20 +1457,17 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, "requires": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -1456,14 +1479,12 @@ "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1471,11 +1492,213 @@ "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, "babel-jest": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", @@ -1499,6 +1722,33 @@ } } }, + "babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, "babel-plugin-istanbul": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", @@ -1520,6 +1770,314 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "babel-preset-jest": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", @@ -1530,11 +2088,126 @@ "babel-plugin-jest-hoist": "^24.9.0" } }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "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==", + "requires": { + "source-map": "^0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -1609,8 +2282,7 @@ "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, "binary-extensions": { "version": "1.13.1", @@ -1770,7 +2442,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1905,6 +2576,15 @@ "pako": "~1.0.5" } }, + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + }, "bs-logger": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", @@ -2152,6 +2832,11 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, + "caniuse-lite": { + "version": "1.0.30001028", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001028.tgz", + "integrity": "sha512-Vnrq+XMSHpT7E+LWoIYhs3Sne8h9lx9YJV3acH3THNCwU/9zV93/ta4xVfzTtnqd3rvnuVpVjE3DFqf56tr3aQ==" + }, "capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -2986,8 +3671,7 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, "component-emitter": { "version": "1.3.0", @@ -3042,8 +3726,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -3242,7 +3925,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, "requires": { "safe-buffer": "~5.1.1" }, @@ -3250,8 +3932,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==" } } }, @@ -3317,8 +3998,7 @@ "core-js": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", - "dev": true + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, "core-util-is": { "version": "1.0.2", @@ -3493,6 +4173,11 @@ "cssom": "0.3.x" } }, + "csstype": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -3701,6 +4386,14 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "^2.0.0" + } + }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", @@ -3880,6 +4573,11 @@ "safe-buffer": "^5.0.1" } }, + "electron-to-chromium": { + "version": "1.3.360", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.360.tgz", + "integrity": "sha512-RE1pv2sjQiDRRN1nI0fJ0eQHZ9le4oobu16OArnwEUV5ycAU5SNjFyvzjZ1gPUAqBa2Ud1XagtW8j3ZXfHuQHA==" + }, "elliptic": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", @@ -3904,8 +4602,7 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "end-of-stream": { "version": "1.4.4", @@ -4180,8 +4877,7 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "event-emitter": { "version": "0.3.5", @@ -4553,7 +5249,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, "requires": { "commondir": "^1.0.1", "make-dir": "^2.0.0", @@ -5069,7 +5764,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" }, @@ -5077,8 +5771,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" } } }, @@ -5162,6 +5855,15 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -5325,7 +6027,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, "requires": { "loose-envify": "^1.0.0" } @@ -5463,6 +6164,11 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -6027,12 +6733,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6052,7 +6760,8 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -6200,6 +6909,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6910,8 +7620,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.13.1", @@ -7060,7 +7769,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, "requires": { "minimist": "^1.2.0" }, @@ -7068,8 +7776,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -7334,7 +8041,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, "requires": { "big.js": "^5.2.2", "emojis-list": "^2.0.0", @@ -7413,7 +8119,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -7437,7 +8142,6 @@ "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" @@ -7446,8 +8150,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -7655,7 +8358,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7663,8 +8365,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mississippi": { "version": "3.0.0", @@ -7709,7 +8410,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -8038,8 +8738,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-copy": { "version": "0.1.0", @@ -8171,8 +8870,7 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "4.0.0", @@ -8194,8 +8892,7 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "p-cancelable": { "version": "1.1.0", @@ -8379,8 +9076,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -8450,8 +9146,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "pino": { "version": "5.14.0", @@ -8486,7 +9181,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, "requires": { "find-up": "^3.0.0" } @@ -8563,6 +9257,11 @@ } } }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, "probe-image-size": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-5.0.0.tgz", @@ -8651,6 +9350,16 @@ "sisteransi": "^1.0.3" } }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -8785,11 +9494,31 @@ } } }, + "react": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz", + "integrity": "sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", + "integrity": "sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.18.0" + } + }, "react-is": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", - "dev": true + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" }, "read-pkg": { "version": "3.0.0", @@ -8912,12 +9641,27 @@ "resolve": "^1.1.6" } }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, "regenerator-runtime": { "version": "0.13.3", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", "dev": true }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -8944,6 +9688,36 @@ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, "relaxed-json": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.3.tgz", @@ -8972,6 +9746,14 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -9239,6 +10021,15 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scheduler": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz", + "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -9462,8 +10253,7 @@ "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "slice-ansi": { "version": "2.1.0", @@ -10457,6 +11247,11 @@ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, "ts-jest": { "version": "24.3.0", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.3.0.tgz", diff --git a/package.json b/package.json index f68cda87cb..c778277c32 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,15 @@ "description": "", "main": "background.js", "dependencies": { - "concurrently": "^5.1.0" + "@types/react": "^16.9.22", + "@types/react-dom": "^16.9.5", + "babel": "^6.23.0", + "babel-core": "^6.26.3", + "babel-loader": "^8.0.6", + "babel-preset-env": "^1.7.0", + "concurrently": "^5.1.0", + "react": "^16.12.0", + "react-dom": "^16.12.0" }, "devDependencies": { "web-ext": "^4.0.0", diff --git a/src/background.ts b/src/background.ts index 62d0827e3b..d0508d2c9c 100644 --- a/src/background.ts +++ b/src/background.ts @@ -85,10 +85,6 @@ chrome.runtime.onInstalled.addListener(function (object) { const newUserID = utils.generateUserID(); //save this UUID Config.config.userID = newUserID; - - //TODO: Remove when mobile support is old - // Don't show this to new users - // Config.config.mobileUpdateShowCount = 1; } }, 1500); }); diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx new file mode 100644 index 0000000000..89ac388cc2 --- /dev/null +++ b/src/components/SkipNoticeComponent.tsx @@ -0,0 +1,406 @@ +import * as React from "react"; + +export interface SkipNoticeProps { + UUID: string; + manualSkip: boolean; + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; +} + +class SkipNoticeComponent extends React.Component { + UUID: string; + manualSkip: boolean; + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; + + noticeTitle: string; + amountOfPreviousNotices: number; + + maxCountdownTime: () => number; + countdownTime: any; + countdownInterval: NodeJS.Timeout; + unskipCallback: any; + idSuffix: any; + + constructor(props: SkipNoticeComponent) { + super(props); + + this.UUID = props.UUID; + this.manualSkip = props.manualSkip; + this.contentContainer = props.contentContainer; + + this.noticeTitle = chrome.i18n.getMessage("noticeTitle"); + + if (this.manualSkip) { + this.noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped"); + } + + this.maxCountdownTime = () => 4; + //the countdown until this notice closes + this.countdownTime = this.maxCountdownTime(); + //the id for the setInterval running the countdown + this.countdownInterval = null; + + //the unskip button's callback + this.unskipCallback = this.unskip.bind(this); + + //add notice + this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; + + //this is the suffix added at the end of every id + this.idSuffix = this.UUID + this.amountOfPreviousNotices; + + if (this.amountOfPreviousNotices > 0) { + //another notice exists + + let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0]; + previousNotice.classList.add("secondSkipNotice") + } + } + + render() { + let noticeStyle: React.CSSProperties = { + zIndex: 50 + this.amountOfPreviousNotices + } + if (this.contentContainer().onMobileYouTube) { + noticeStyle.bottom = "4em"; + noticeStyle.transform = "scale(0.8) translate(10%, 10%)"; + } + + return ( +
+ + {/* First row */} + + {/* Left column */} + + {/* Logo */} + + + + + + {this.noticeTitle} + + + + {/* Right column */} + + + {/* Time left */} + + + {this.countdownTime + "s"} + + + {/* Close button */} + + + + + + {/* Spacer */} +
+ + + {/* Last Row */} + + + {/* Vote Button Container */} + + + {/* Report Text */} + + + {chrome.i18n.getMessage("reportButtonTitle")} + + + {/* Report Button */} + this.contentContainer().vote(0, this.UUID, this)}> + + + + + + {/* Unskip Button */} + + + + + {/* Never show button if manualSkip is disabled */} + {this.manualSkip ? "" : + + + + } + +
+ ); + } + + //called every second to lower the countdown before hiding the notice + countdown() { + this.countdownTime--; + + if (this.countdownTime <= 0) { + //remove this from setInterval + clearInterval(this.countdownInterval); + + //time to close this notice + this.close(); + + return; + } + + if (this.countdownTime == 3) { + //start fade out animation + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + notice.style.removeProperty("animation"); + notice.classList.add("sponsorSkipNoticeFadeOut"); + } + + this.updateTimerDisplay(); + } + + pauseCountdown() { + //remove setInterval + clearInterval(this.countdownInterval); + this.countdownInterval = null; + + //reset countdown + this.countdownTime = this.maxCountdownTime(); + + //inform the user + let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); + timeLeft.innerText = chrome.i18n.getMessage("paused"); + + //remove the fade out class if it exists + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + notice.classList.remove("sponsorSkipNoticeFadeOut"); + notice.style.animation = "none"; + } + + startCountdown() { + //if it has already started, don't start it again + if (this.countdownInterval !== null) return; + + this.countdownInterval = setInterval(this.countdown.bind(this), 1000); + + this.updateTimerDisplay(); + } + + updateTimerDisplay() { + //update the timer display + let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); + timeLeft.innerText = this.countdownTime + "s"; + } + + unskip() { + this.contentContainer().unskipSponsorTime(this.UUID); + + this.unskippedMode(chrome.i18n.getMessage("reskip")); + } + + /** Sets up notice to be not skipped yet */ + unskippedMode(buttonText) { + //change unskip button to a reskip button + let unskipButton = this.changeUnskipButton(buttonText); + + //setup new callback + this.unskipCallback = this.reskip.bind(this); + unskipButton.addEventListener("click", this.unskipCallback); + + //change max duration to however much of the sponsor is left + this.maxCountdownTime = function() { + let sponsorTime = this.contentContainer().sponsorTimes[this.contentContainer().UUIDs.indexOf(this.UUID)]; + let duration = Math.round(sponsorTime[1] - this.contentContainer().v.currentTime); + + return Math.max(duration, 4); + }; + + this.countdownTime = this.maxCountdownTime(); + this.updateTimerDisplay(); + } + + reskip() { + this.contentContainer().reskipSponsorTime(this.UUID); + + //change reskip button to a unskip button + let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip")); + + //setup new callback + this.unskipCallback = this.unskip.bind(this); + unskipButton.addEventListener("click", this.unskipCallback); + + //reset duration + this.maxCountdownTime = () => 4; + this.countdownTime = this.maxCountdownTime(); + this.updateTimerDisplay(); + + // See if the title should be changed + if (this.manualSkip) { + this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle")); + + this.contentContainer().vote(1, this.UUID, this); + } + } + + /** + * Changes the text on the reskip button + * + * @param {string} text + * @returns {HTMLElement} unskipButton + */ + changeUnskipButton(text) { + let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix); + unskipButton.innerText = text; + unskipButton.removeEventListener("click", this.unskipCallback); + + return unskipButton; + } + + afterDownvote() { + this.addVoteButtonInfo(chrome.i18n.getMessage("voted")); + this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack")); + + //remove this sponsor from the sponsors looked up + //find which one it is + for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) { + if (this.contentContainer().UUIDs[i] == this.UUID) { + //this one is the one to hide + + //add this as a hidden sponsorTime + this.contentContainer().hiddenSponsorTimes.push(i); + + this.contentContainer().updatePreviewBar(); + break; + } + } + } + + changeNoticeTitle(title) { + let noticeElement = document.getElementById("sponsorSkipMessage" + this.idSuffix); + + noticeElement.innerText = title; + } + + addNoticeInfoMessage(message: string, message2: string = "") { + let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage); + } + + let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2"); + if (previousInfoMessage2 != null) { + //remove it + document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2); + } + + //add info + let thanksForVotingText = document.createElement("p"); + thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix; + thanksForVotingText.className = "sponsorTimesInfoMessage"; + thanksForVotingText.innerText = message; + + //add element to div + document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + + if (message2 !== undefined) { + let thanksForVotingText2 = document.createElement("p"); + thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2"; + thanksForVotingText2.className = "sponsorTimesInfoMessage"; + thanksForVotingText2.innerText = message2; + + //add element to div + document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + } + } + + addVoteButtonInfo(message) { + this.resetVoteButtonInfo(); + + //hide report button and text for it + let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix); + if (downvoteButton != null) { + downvoteButton.style.display = "none"; + } + let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix); + if (downvoteButtonText != null) { + downvoteButtonText.style.display = "none"; + } + + //add info + let thanksForVotingText = document.createElement("td"); + thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix; + thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"; + thanksForVotingText.innerText = message; + + //add element to div + document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText); + } + + resetVoteButtonInfo() { + let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage); + } + + //show button again + document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display"); + } + + resetNoticeInfoMessage() { + let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage); + } + } + + //close this notice + close() { + //reset message + this.resetNoticeInfoMessage(); + + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + if (notice != null) { + notice.remove(); + } + + //remove setInterval + if (this.countdownInterval !== null) clearInterval(this.countdownInterval); + } +} + +export default SkipNoticeComponent; \ No newline at end of file diff --git a/src/content.ts b/src/content.ts index dcf8395f06..03515e28da 100644 --- a/src/content.ts +++ b/src/content.ts @@ -6,7 +6,7 @@ var utils = new Utils(); import runThePopup from "./popup"; import PreviewBar from "./js-components/previewBar"; -import SkipNotice from "./js-components/skipNotice"; +import SkipNotice from "./render/SkipNotice"; // Hack to get the CSS loaded on permission-based sites (Invidious) utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); @@ -819,15 +819,7 @@ function skipToTime(v, index, sponsorTimes, openNotice) { if (openNotice) { //send out the message saying that a sponsor message was skipped if (!Config.config.dontShowNotice) { - - let skipNotice = new SkipNotice(this, currentUUID, Config.config.disableAutoSkip, skipNoticeContentContainer); - - //TODO: Remove this when Mobile support is old - if (Config.config.mobileUpdateShowCount < 1) { - skipNotice.addNoticeInfoMessage(chrome.i18n.getMessage("mobileUpdateInfo")); - - Config.config.mobileUpdateShowCount += 1; - } + let skipNotice = new SkipNotice(currentUUID, Config.config.disableAutoSkip, skipNoticeContentContainer); //auto-upvote this sponsor if (Config.config.trackViewCount && !Config.config.disableAutoSkip && Config.config.autoUpvote) { diff --git a/src/render/SkipNotice.tsx b/src/render/SkipNotice.tsx new file mode 100644 index 0000000000..d137e47e1d --- /dev/null +++ b/src/render/SkipNotice.tsx @@ -0,0 +1,50 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; + +import SkipNoticeComponent from "../components/SkipNoticeComponent"; + +class SkipNotice { + UUID: string; + manualSkip: boolean; + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; + + constructor(UUID: string, manualSkip: boolean = false, contentContainer) { + this.UUID = UUID; + this.manualSkip = manualSkip; + this.contentContainer = contentContainer; + + //get reference node + let referenceNode = document.getElementById("player-container-id") + || document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); + if (referenceNode == null) { + //for embeds + let player = document.getElementById("player"); + referenceNode = player.firstChild as HTMLElement; + let index = 1; + + //find the child that is the video player (sometimes it is not the first) + while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) { + referenceNode = player.children[index] as HTMLElement; + + index++; + } + } + + let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; + //this is the suffix added at the end of every id + let idSuffix = this.UUID + amountOfPreviousNotices; + + let noticeElement = document.createElement("div"); + noticeElement.id = "sponsorSkipNoticeContainer" + idSuffix; + + referenceNode.prepend(noticeElement); + + ReactDOM.render( + , + noticeElement + ); + } +} + +export default SkipNotice; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index cc0b77e67b..873516c66c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "outDir": "dist/js", "noEmitOnError": true, "typeRoots": [ "node_modules/@types" ], - "resolveJsonModule": true + "resolveJsonModule": true, + "jsx": "react" } } \ No newline at end of file From 0d9b624fd536ed227f0693f82d437655536fd211 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 25 Feb 2020 00:43:20 -0500 Subject: [PATCH 02/64] Delete old skip notice --- src/js-components/skipNotice.ts | 442 -------------------------------- 1 file changed, 442 deletions(-) delete mode 100644 src/js-components/skipNotice.ts diff --git a/src/js-components/skipNotice.ts b/src/js-components/skipNotice.ts deleted file mode 100644 index 3e9818516d..0000000000 --- a/src/js-components/skipNotice.ts +++ /dev/null @@ -1,442 +0,0 @@ -'use strict'; - -/** - * The notice that tells the user that a sponsor was just skipped - */ -class SkipNotice { - parent: HTMLElement; - UUID: string; - manualSkip: boolean; - // Contains functions and variables from the content script needed by the skip notice - contentContainer: () => any; - - maxCountdownTime: () => number; - countdownTime: any; - countdownInterval: NodeJS.Timeout; - unskipCallback: any; - idSuffix: any; - - constructor(parent: HTMLElement, UUID: string, manualSkip: boolean = false, contentContainer) { - this.parent = parent; - this.UUID = UUID; - this.manualSkip = manualSkip; - this.contentContainer = contentContainer; - - let noticeTitle = chrome.i18n.getMessage("noticeTitle"); - - if (manualSkip) { - noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped"); - } - - this.maxCountdownTime = () => 4; - //the countdown until this notice closes - this.countdownTime = this.maxCountdownTime(); - //the id for the setInterval running the countdown - this.countdownInterval = null; - - //the unskip button's callback - this.unskipCallback = this.unskip.bind(this); - - //add notice - let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; - - //this is the suffix added at the end of every id - this.idSuffix = this.UUID + amountOfPreviousNotices; - - if (amountOfPreviousNotices > 0) { - //already exists - - let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0]; - previousNotice.classList.add("secondSkipNotice") - } - - let noticeElement = document.createElement("div"); - //what sponsor time this is about - noticeElement.id = "sponsorSkipNotice" + this.idSuffix; - noticeElement.classList.add("sponsorSkipObject"); - noticeElement.classList.add("sponsorSkipNotice"); - noticeElement.style.zIndex = String(50 + amountOfPreviousNotices); - if (contentContainer().onMobileYouTube) { - noticeElement.style.bottom = "4em"; - noticeElement.style.transform = "scale(0.8) translate(10%, 10%)"; - } - - //add mouse enter and leave listeners - noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this)); - noticeElement.addEventListener("mouseleave", this.startCountdown.bind(this)); - - //the row that will contain the info - let firstRow = document.createElement("tr"); - firstRow.id = "sponsorSkipNoticeFirstRow" + this.idSuffix; - - let logoColumn = document.createElement("td"); - - let logoElement = document.createElement("img"); - logoElement.id = "sponsorSkipLogo" + this.idSuffix; - logoElement.className = "sponsorSkipLogo sponsorSkipObject"; - logoElement.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png"); - - let noticeMessage = document.createElement("span"); - noticeMessage.id = "sponsorSkipMessage" + this.idSuffix; - noticeMessage.classList.add("sponsorSkipMessage"); - noticeMessage.classList.add("sponsorSkipObject"); - noticeMessage.innerText = noticeTitle; - - //create the first column - logoColumn.appendChild(logoElement); - logoColumn.appendChild(noticeMessage); - - //add the x button - let closeButtonContainer = document.createElement("td"); - closeButtonContainer.className = "sponsorSkipNoticeRightSection"; - closeButtonContainer.style.top = "11px"; - - let timeLeft = document.createElement("span"); - timeLeft.id = "sponsorSkipNoticeTimeLeft" + this.idSuffix; - timeLeft.innerText = this.countdownTime + "s"; - timeLeft.className = "sponsorSkipObject sponsorSkipNoticeTimeLeft"; - - let hideButton = document.createElement("img"); - hideButton.src = chrome.extension.getURL("icons/close.png"); - hideButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton"; - hideButton.addEventListener("click", this.close.bind(this)); - - closeButtonContainer.appendChild(timeLeft); - closeButtonContainer.appendChild(hideButton); - - //add all objects to first row - firstRow.appendChild(logoColumn); - firstRow.appendChild(closeButtonContainer); - - let spacer = document.createElement("hr"); - spacer.id = "sponsorSkipNoticeSpacer" + this.idSuffix; - spacer.className = "sponsorBlockSpacer"; - - //the row that will contain the buttons - let secondRow = document.createElement("tr"); - secondRow.id = "sponsorSkipNoticeSecondRow" + this.idSuffix; - - //thumbs up and down buttons - let voteButtonsContainer = document.createElement("td"); - voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + this.idSuffix; - voteButtonsContainer.className = "sponsorTimesVoteButtonsContainer" - - let reportText = document.createElement("span"); - reportText.id = "sponsorTimesReportText" + this.idSuffix; - reportText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"; - reportText.innerText = chrome.i18n.getMessage("reportButtonTitle"); - reportText.style.marginRight = "5px"; - reportText.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo")); - - let downvoteButton = document.createElement("img"); - downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + this.idSuffix; - downvoteButton.className = "sponsorSkipObject voteButton"; - downvoteButton.src = chrome.extension.getURL("icons/report.png"); - downvoteButton.addEventListener("click", () => this.contentContainer().vote(0, this.UUID, this)); - downvoteButton.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo")); - - //add downvote and report text to container - voteButtonsContainer.appendChild(reportText); - voteButtonsContainer.appendChild(downvoteButton); - - //add unskip button - let unskipContainer = document.createElement("td"); - unskipContainer.className = "sponsorSkipNoticeUnskipSection"; - - let unskipButton = document.createElement("button"); - unskipButton.id = "sponsorSkipUnskipButton" + this.idSuffix; - unskipButton.innerText = chrome.i18n.getMessage("unskip"); - unskipButton.className = "sponsorSkipObject sponsorSkipNoticeButton"; - unskipButton.addEventListener("click", this.unskipCallback); - - unskipButton.style.marginLeft = "4px"; - - unskipContainer.appendChild(unskipButton); - - //add don't show again button - let dontshowContainer = document.createElement("td"); - dontshowContainer.className = "sponsorSkipNoticeRightSection"; - - let dontShowAgainButton = document.createElement("button"); - dontShowAgainButton.innerText = chrome.i18n.getMessage("Hide"); - dontShowAgainButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton"; - dontShowAgainButton.addEventListener("click", this.contentContainer().dontShowNoticeAgain); - - // Don't let them hide it if manually skipping - if (!this.manualSkip) { - dontshowContainer.appendChild(dontShowAgainButton); - } - - //add to row - secondRow.appendChild(voteButtonsContainer); - secondRow.appendChild(unskipContainer); - secondRow.appendChild(dontshowContainer); - - noticeElement.appendChild(firstRow); - noticeElement.appendChild(spacer); - noticeElement.appendChild(secondRow); - - //get reference node - let referenceNode = document.getElementById("player-container-id") - || document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); - if (referenceNode == null) { - //for embeds - let player = document.getElementById("player"); - referenceNode = player.firstChild; - let index = 1; - - //find the child that is the video player (sometimes it is not the first) - while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) { - referenceNode = player.children[index]; - - index++; - } - } - - referenceNode.prepend(noticeElement); - - if (manualSkip) { - this.unskippedMode(chrome.i18n.getMessage("skip")); - } - - this.startCountdown(); - } - - //called every second to lower the countdown before hiding the notice - countdown() { - this.countdownTime--; - - if (this.countdownTime <= 0) { - //remove this from setInterval - clearInterval(this.countdownInterval); - - //time to close this notice - this.close(); - - return; - } - - if (this.countdownTime == 3) { - //start fade out animation - let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); - notice.style.removeProperty("animation"); - notice.classList.add("sponsorSkipNoticeFadeOut"); - } - - this.updateTimerDisplay(); - } - - pauseCountdown() { - //remove setInterval - clearInterval(this.countdownInterval); - this.countdownInterval = null; - - //reset countdown - this.countdownTime = this.maxCountdownTime(); - - //inform the user - let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); - timeLeft.innerText = chrome.i18n.getMessage("paused"); - - //remove the fade out class if it exists - let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); - notice.classList.remove("sponsorSkipNoticeFadeOut"); - notice.style.animation = "none"; - } - - startCountdown() { - //if it has already started, don't start it again - if (this.countdownInterval !== null) return; - - this.countdownInterval = setInterval(this.countdown.bind(this), 1000); - - this.updateTimerDisplay(); - } - - updateTimerDisplay() { - //update the timer display - let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); - timeLeft.innerText = this.countdownTime + "s"; - } - - unskip() { - this.contentContainer().unskipSponsorTime(this.UUID); - - this.unskippedMode(chrome.i18n.getMessage("reskip")); - } - - /** Sets up notice to be not skipped yet */ - unskippedMode(buttonText) { - //change unskip button to a reskip button - let unskipButton = this.changeUnskipButton(buttonText); - - //setup new callback - this.unskipCallback = this.reskip.bind(this); - unskipButton.addEventListener("click", this.unskipCallback); - - //change max duration to however much of the sponsor is left - this.maxCountdownTime = function() { - let sponsorTime = this.contentContainer().sponsorTimes[this.contentContainer().UUIDs.indexOf(this.UUID)]; - let duration = Math.round(sponsorTime[1] - this.contentContainer().v.currentTime); - - return Math.max(duration, 4); - }; - - this.countdownTime = this.maxCountdownTime(); - this.updateTimerDisplay(); - } - - reskip() { - this.contentContainer().reskipSponsorTime(this.UUID); - - //change reskip button to a unskip button - let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip")); - - //setup new callback - this.unskipCallback = this.unskip.bind(this); - unskipButton.addEventListener("click", this.unskipCallback); - - //reset duration - this.maxCountdownTime = () => 4; - this.countdownTime = this.maxCountdownTime(); - this.updateTimerDisplay(); - - // See if the title should be changed - if (this.manualSkip) { - this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle")); - - this.contentContainer().vote(1, this.UUID, this); - } - } - - /** - * Changes the text on the reskip button - * - * @param {string} text - * @returns {HTMLElement} unskipButton - */ - changeUnskipButton(text) { - let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix); - unskipButton.innerText = text; - unskipButton.removeEventListener("click", this.unskipCallback); - - return unskipButton; - } - - afterDownvote() { - this.addVoteButtonInfo(chrome.i18n.getMessage("voted")); - this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack")); - - //remove this sponsor from the sponsors looked up - //find which one it is - for (let i = 0; i < this.contentContainer().sponsorTimes.length; i++) { - if (this.contentContainer().UUIDs[i] == this.UUID) { - //this one is the one to hide - - //add this as a hidden sponsorTime - this.contentContainer().hiddenSponsorTimes.push(i); - - this.contentContainer().updatePreviewBar(); - break; - } - } - } - - changeNoticeTitle(title) { - let noticeElement = document.getElementById("sponsorSkipMessage" + this.idSuffix); - - noticeElement.innerText = title; - } - - addNoticeInfoMessage(message: string, message2: string = "") { - let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix); - if (previousInfoMessage != null) { - //remove it - document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage); - } - - let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2"); - if (previousInfoMessage2 != null) { - //remove it - document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2); - } - - //add info - let thanksForVotingText = document.createElement("p"); - thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix; - thanksForVotingText.className = "sponsorTimesInfoMessage"; - thanksForVotingText.innerText = message; - - //add element to div - document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); - - if (message2 !== undefined) { - let thanksForVotingText2 = document.createElement("p"); - thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2"; - thanksForVotingText2.className = "sponsorTimesInfoMessage"; - thanksForVotingText2.innerText = message2; - - //add element to div - document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); - } - } - - resetNoticeInfoMessage() { - let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix); - if (previousInfoMessage != null) { - //remove it - document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage); - } - } - - addVoteButtonInfo(message) { - this.resetVoteButtonInfo(); - - //hide report button and text for it - let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix); - if (downvoteButton != null) { - downvoteButton.style.display = "none"; - } - let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix); - if (downvoteButtonText != null) { - downvoteButtonText.style.display = "none"; - } - - //add info - let thanksForVotingText = document.createElement("td"); - thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix; - thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage"; - thanksForVotingText.innerText = message; - - //add element to div - document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText); - } - - resetVoteButtonInfo() { - let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix); - if (previousInfoMessage != null) { - //remove it - document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage); - } - - //show button again - document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display"); - } - - //close this notice - close() { - //reset message - this.resetNoticeInfoMessage(); - - let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); - if (notice != null) { - notice.remove(); - } - - //remove setInterval - if (this.countdownInterval !== null) clearInterval(this.countdownInterval); - } - -} - -export default SkipNotice; \ No newline at end of file From ccbc0456f9996c667dfadb4665a55097e35bffad Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 9 Mar 2020 21:51:44 -0400 Subject: [PATCH 03/64] Made skip notice use react states --- src/components/SkipNoticeComponent.tsx | 141 +++++++++++++------------ 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 89ac388cc2..28ae024c01 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -7,19 +7,26 @@ export interface SkipNoticeProps { contentContainer: () => any; } -class SkipNoticeComponent extends React.Component { +export interface SkipNoticeState { + noticeTitle: string, + + countdownTime: number, + countdownText: string, + + unskipText: string, + unskipCallback: () => void +} + +class SkipNoticeComponent extends React.Component { UUID: string; manualSkip: boolean; // Contains functions and variables from the content script needed by the skip notice contentContainer: () => any; - noticeTitle: string; amountOfPreviousNotices: number; maxCountdownTime: () => number; - countdownTime: any; countdownInterval: NodeJS.Timeout; - unskipCallback: any; idSuffix: any; constructor(props: SkipNoticeComponent) { @@ -29,21 +36,16 @@ class SkipNoticeComponent extends React.Component { this.manualSkip = props.manualSkip; this.contentContainer = props.contentContainer; - this.noticeTitle = chrome.i18n.getMessage("noticeTitle"); + let noticeTitle = chrome.i18n.getMessage("noticeTitle"); if (this.manualSkip) { - this.noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped"); + noticeTitle = chrome.i18n.getMessage("noticeTitleNotSkipped"); } this.maxCountdownTime = () => 4; - //the countdown until this notice closes - this.countdownTime = this.maxCountdownTime(); //the id for the setInterval running the countdown this.countdownInterval = null; - //the unskip button's callback - this.unskipCallback = this.unskip.bind(this); - //add notice this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; @@ -56,6 +58,22 @@ class SkipNoticeComponent extends React.Component { let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0]; previousNotice.classList.add("secondSkipNotice") } + + // Setup state + this.state = { + noticeTitle, + + //the countdown until this notice closes + countdownTime: this.maxCountdownTime(), + countdownText: null, + + unskipText: chrome.i18n.getMessage("unskip"), + unskipCallback: this.unskip.bind(this) + } + } + + componentDidMount() { + this.startCountdown(); } render() { @@ -68,10 +86,10 @@ class SkipNoticeComponent extends React.Component { } return ( -
+ onMouseLeave={this.startCountdown.bind(this)}> {/* First row */} @@ -86,7 +104,7 @@ class SkipNoticeComponent extends React.Component { - {this.noticeTitle} + {this.state.noticeTitle} @@ -98,7 +116,7 @@ class SkipNoticeComponent extends React.Component { - {this.countdownTime + "s"} + {this.state.countdownText || (this.state.countdownTime + "s")} {/* Close button */} @@ -110,9 +128,9 @@ class SkipNoticeComponent extends React.Component { {/* Spacer */} -
- + {/* Last Row */} @@ -146,9 +164,9 @@ class SkipNoticeComponent extends React.Component { @@ -163,15 +181,15 @@ class SkipNoticeComponent extends React.Component { } -
+ ); } //called every second to lower the countdown before hiding the notice countdown() { - this.countdownTime--; + let countdownTime = this.state.countdownTime - 1; - if (this.countdownTime <= 0) { + if (countdownTime <= 0) { //remove this from setInterval clearInterval(this.countdownInterval); @@ -181,14 +199,16 @@ class SkipNoticeComponent extends React.Component { return; } - if (this.countdownTime == 3) { + if (countdownTime == 3) { //start fade out animation let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); notice.style.removeProperty("animation"); notice.classList.add("sponsorSkipNoticeFadeOut"); } - this.updateTimerDisplay(); + this.setState({ + countdownTime + }) } pauseCountdown() { @@ -196,13 +216,12 @@ class SkipNoticeComponent extends React.Component { clearInterval(this.countdownInterval); this.countdownInterval = null; - //reset countdown - this.countdownTime = this.maxCountdownTime(); + //reset countdown and inform the user + this.setState({ + countdownTime: this.maxCountdownTime(), + countdownText: chrome.i18n.getMessage("paused") + }); - //inform the user - let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); - timeLeft.innerText = chrome.i18n.getMessage("paused"); - //remove the fade out class if it exists let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); notice.classList.remove("sponsorSkipNoticeFadeOut"); @@ -213,15 +232,12 @@ class SkipNoticeComponent extends React.Component { //if it has already started, don't start it again if (this.countdownInterval !== null) return; - this.countdownInterval = setInterval(this.countdown.bind(this), 1000); - - this.updateTimerDisplay(); - } + this.setState({ + countdownTime: this.maxCountdownTime(), + countdownText: null + }); - updateTimerDisplay() { - //update the timer display - let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix); - timeLeft.innerText = this.countdownTime + "s"; + this.countdownInterval = setInterval(this.countdown.bind(this), 1000); } unskip() { @@ -232,12 +248,11 @@ class SkipNoticeComponent extends React.Component { /** Sets up notice to be not skipped yet */ unskippedMode(buttonText) { - //change unskip button to a reskip button - let unskipButton = this.changeUnskipButton(buttonText); - //setup new callback - this.unskipCallback = this.reskip.bind(this); - unskipButton.addEventListener("click", this.unskipCallback); + this.setState({ + unskipText: buttonText, + unskipCallback: this.reskip.bind(this) + }); //change max duration to however much of the sponsor is left this.maxCountdownTime = function() { @@ -247,24 +262,28 @@ class SkipNoticeComponent extends React.Component { return Math.max(duration, 4); }; - this.countdownTime = this.maxCountdownTime(); - this.updateTimerDisplay(); + //reset countdown + this.setState({ + countdownTime: this.maxCountdownTime() + }); } reskip() { this.contentContainer().reskipSponsorTime(this.UUID); - //change reskip button to a unskip button - let unskipButton = this.changeUnskipButton(chrome.i18n.getMessage("unskip")); - //setup new callback - this.unskipCallback = this.unskip.bind(this); - unskipButton.addEventListener("click", this.unskipCallback); + this.setState({ + unskipText: chrome.i18n.getMessage("unskip"), + unskipCallback: this.unskip.bind(this) + }); //reset duration this.maxCountdownTime = () => 4; - this.countdownTime = this.maxCountdownTime(); - this.updateTimerDisplay(); + + //reset countdown + this.setState({ + countdownTime: this.maxCountdownTime() + }); // See if the title should be changed if (this.manualSkip) { @@ -274,20 +293,6 @@ class SkipNoticeComponent extends React.Component { } } - /** - * Changes the text on the reskip button - * - * @param {string} text - * @returns {HTMLElement} unskipButton - */ - changeUnskipButton(text) { - let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix); - unskipButton.innerText = text; - unskipButton.removeEventListener("click", this.unskipCallback); - - return unskipButton; - } - afterDownvote() { this.addVoteButtonInfo(chrome.i18n.getMessage("voted")); this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack")); @@ -333,7 +338,7 @@ class SkipNoticeComponent extends React.Component { thanksForVotingText.innerText = message; //add element to div - document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); if (message2 !== undefined) { let thanksForVotingText2 = document.createElement("p"); @@ -342,7 +347,7 @@ class SkipNoticeComponent extends React.Component { thanksForVotingText2.innerText = message2; //add element to div - document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); } } From c526a812e0ff119633f130f3385e8aa3dd73c2de Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 9 Mar 2020 22:50:07 -0400 Subject: [PATCH 04/64] Made manual skip vote follow config --- src/components/SkipNoticeComponent.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 28ae024c01..972299c4dd 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import Config from "../config" export interface SkipNoticeProps { UUID: string; @@ -289,7 +290,7 @@ class SkipNoticeComponent extends React.Component Date: Mon, 9 Mar 2020 23:04:01 -0400 Subject: [PATCH 05/64] Fixed manual skip vote check using wrong variable --- src/components/SkipNoticeComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 972299c4dd..7ede17c539 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -290,7 +290,7 @@ class SkipNoticeComponent extends React.Component Date: Tue, 10 Mar 2020 03:01:20 -0400 Subject: [PATCH 06/64] Moved timing mechanism to separate component --- src/components/SkipNoticeComponent.tsx | 183 ++++--------------- src/components/TimedNoticeComponent.tsx | 223 ++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 151 deletions(-) create mode 100644 src/components/TimedNoticeComponent.tsx diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 7ede17c539..7ce28d3a77 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import Config from "../config" +import TimedNoticeComponent from "./TimedNoticeComponent"; + export interface SkipNoticeProps { UUID: string; manualSkip: boolean; @@ -12,6 +14,7 @@ export interface SkipNoticeState { noticeTitle: string, countdownTime: number, + maxCountdownTime: () => number; countdownText: string, unskipText: string, @@ -26,12 +29,13 @@ class SkipNoticeComponent extends React.Component number; - countdownInterval: NodeJS.Timeout; idSuffix: any; - constructor(props: SkipNoticeComponent) { + noticeRef: React.MutableRefObject; + + constructor(props: SkipNoticeProps) { super(props); + this.noticeRef = React.createRef(); this.UUID = props.UUID; this.manualSkip = props.manualSkip; @@ -43,10 +47,6 @@ class SkipNoticeComponent extends React.Component 4; - //the id for the setInterval running the countdown - this.countdownInterval = null; - //add notice this.amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length; @@ -65,7 +65,8 @@ class SkipNoticeComponent extends React.Component 4, + countdownTime: 4, countdownText: null, unskipText: chrome.i18n.getMessage("unskip"), @@ -73,10 +74,6 @@ class SkipNoticeComponent extends React.Component - - {/* First row */} - - {/* Left column */} - - {/* Logo */} - - - - - - {this.state.noticeTitle} - - - - {/* Right column */} - - - {/* Time left */} - - - {this.state.countdownText || (this.state.countdownTime + "s")} - - - {/* Close button */} - - - - - + + {/* Spacer */} @@ -182,63 +144,9 @@ class SkipNoticeComponent extends React.Component } - - ); - } - - //called every second to lower the countdown before hiding the notice - countdown() { - let countdownTime = this.state.countdownTime - 1; - - if (countdownTime <= 0) { - //remove this from setInterval - clearInterval(this.countdownInterval); - - //time to close this notice - this.close(); - - return; - } - - if (countdownTime == 3) { - //start fade out animation - let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); - notice.style.removeProperty("animation"); - notice.classList.add("sponsorSkipNoticeFadeOut"); - } - - this.setState({ - countdownTime - }) - } - pauseCountdown() { - //remove setInterval - clearInterval(this.countdownInterval); - this.countdownInterval = null; - - //reset countdown and inform the user - this.setState({ - countdownTime: this.maxCountdownTime(), - countdownText: chrome.i18n.getMessage("paused") - }); - - //remove the fade out class if it exists - let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); - notice.classList.remove("sponsorSkipNoticeFadeOut"); - notice.style.animation = "none"; - } - - startCountdown() { - //if it has already started, don't start it again - if (this.countdownInterval !== null) return; - - this.setState({ - countdownTime: this.maxCountdownTime(), - countdownText: null - }); - - this.countdownInterval = setInterval(this.countdown.bind(this), 1000); + + ); } unskip() { @@ -255,40 +163,41 @@ class SkipNoticeComponent extends React.Component { + this.noticeRef.current.resetCountdown(); }); } reskip() { this.contentContainer().reskipSponsorTime(this.UUID); - //setup new callback + //reset countdown this.setState({ unskipText: chrome.i18n.getMessage("unskip"), - unskipCallback: this.unskip.bind(this) - }); + unskipCallback: this.unskip.bind(this), - //reset duration - this.maxCountdownTime = () => 4; - - //reset countdown - this.setState({ - countdownTime: this.maxCountdownTime() + maxCountdownTime: () => 4, + countdownTime: 4 }); // See if the title should be changed if (this.manualSkip) { - this.changeNoticeTitle(chrome.i18n.getMessage("noticeTitle")); + this.setState({ + noticeTitle: chrome.i18n.getMessage("noticeTitle") + }); if(Config.config.autoUpvote) this.contentContainer().vote(1, this.UUID); } @@ -313,12 +222,6 @@ class SkipNoticeComponent extends React.Component number, + amountOfPreviousNotices?: number, + idSuffix: string +} + +export interface TimedNoticeState { + noticeTitle: string, + + countdownTime: number, + countdownText: string, +} + +class TimedNoticeComponent extends React.Component { + countdownInterval: NodeJS.Timeout; + idSuffix: any; + + amountOfPreviousNotices: number; + + constructor(props: TimedNoticeProps) { + super(props); + + if (props.maxCountdownTime === undefined) props.maxCountdownTime = () => 4; + + //the id for the setInterval running the countdown + this.countdownInterval = null; + + this.amountOfPreviousNotices = props.amountOfPreviousNotices || 0; + + this.idSuffix = props.idSuffix; + + // Setup state + this.state = { + noticeTitle: props.noticeTitle, + + //the countdown until this notice closes + countdownTime: props.maxCountdownTime(), + countdownText: null, + } + } + + componentDidMount() { + this.startCountdown(); + } + + // forwardRef(props, ref) { + + // } + + render() { + let noticeStyle: React.CSSProperties = { + zIndex: 50 + this.amountOfPreviousNotices + } + + return ( + + + {/* First row */} + + {/* Left column */} + + + {/* Right column */} + + + + {this.props.children} + +
+ {/* Logo */} + + + + + + {this.state.noticeTitle} + + + + {/* Time left */} + + + {this.state.countdownText || (this.state.countdownTime + "s")} + + + {/* Close button */} + + +
+ ); + } + + //called every second to lower the countdown before hiding the notice + countdown() { + let countdownTime = this.state.countdownTime - 1; + + if (countdownTime <= 0) { + //remove this from setInterval + clearInterval(this.countdownInterval); + + //time to close this notice + this.close(); + + return; + } + + if (countdownTime == 3) { + //start fade out animation + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + notice.style.removeProperty("animation"); + notice.classList.add("sponsorSkipNoticeFadeOut"); + } + + this.setState({ + countdownTime + }) + } + + pauseCountdown() { + //remove setInterval + clearInterval(this.countdownInterval); + this.countdownInterval = null; + + //reset countdown and inform the user + this.setState({ + countdownTime: this.props.maxCountdownTime(), + countdownText: chrome.i18n.getMessage("paused") + }); + + //remove the fade out class if it exists + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + notice.classList.remove("sponsorSkipNoticeFadeOut"); + notice.style.animation = "none"; + } + + startCountdown() { + //if it has already started, don't start it again + if (this.countdownInterval !== null) return; + + this.setState({ + countdownTime: this.props.maxCountdownTime(), + countdownText: null + }); + + this.countdownInterval = setInterval(this.countdown.bind(this), 1000); + } + + resetCountdown() { + this.setState({ + countdownTime: this.props.maxCountdownTime(), + countdownText: null + }); + } + + //close this notice + close() { + //TODO: Change to a listener in the renderer (not component) + let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); + if (notice != null) { + notice.remove(); + } + + //remove setInterval + if (this.countdownInterval !== null) clearInterval(this.countdownInterval); + } + + changeNoticeTitle(title) { + this.setState({ + noticeTitle: title + }); + } + + addNoticeInfoMessage(message: string, message2: string = "") { + //TODO: Replace + + let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix); + if (previousInfoMessage != null) { + //remove it + document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage); + } + + let previousInfoMessage2 = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix + "2"); + if (previousInfoMessage2 != null) { + //remove it + document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage2); + } + + //add info + let thanksForVotingText = document.createElement("p"); + thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix; + thanksForVotingText.className = "sponsorTimesInfoMessage"; + thanksForVotingText.innerText = message; + + //add element to div + document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + + if (message2 !== undefined) { + let thanksForVotingText2 = document.createElement("p"); + thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2"; + thanksForVotingText2.className = "sponsorTimesInfoMessage"; + thanksForVotingText2.innerText = message2; + + //add element to div + document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); + } + } +} + +export default TimedNoticeComponent; \ No newline at end of file From 92a6065c987db40fe55fa884f3cbcd030d381118 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 10 Mar 2020 03:08:15 -0400 Subject: [PATCH 07/64] Added support for untimed notice --- ...oticeComponent.tsx => NoticeComponent.tsx} | 36 ++++++++++++++----- src/components/SkipNoticeComponent.tsx | 8 ++--- 2 files changed, 31 insertions(+), 13 deletions(-) rename src/components/{TimedNoticeComponent.tsx => NoticeComponent.tsx} (88%) diff --git a/src/components/TimedNoticeComponent.tsx b/src/components/NoticeComponent.tsx similarity index 88% rename from src/components/TimedNoticeComponent.tsx rename to src/components/NoticeComponent.tsx index 12dd1637e5..a988207edd 100644 --- a/src/components/TimedNoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -1,29 +1,36 @@ import * as React from "react"; -export interface TimedNoticeProps { +export interface NoticeProps { noticeTitle: string, maxCountdownTime?: () => number, amountOfPreviousNotices?: number, + timed?: boolean, idSuffix: string } -export interface TimedNoticeState { +export interface NoticeState { noticeTitle: string, countdownTime: number, countdownText: string, } -class TimedNoticeComponent extends React.Component { +class NoticeComponent extends React.Component { countdownInterval: NodeJS.Timeout; idSuffix: any; + timed: boolean + amountOfPreviousNotices: number; - constructor(props: TimedNoticeProps) { + constructor(props: NoticeProps) { super(props); + // Set default to timed + this.timed = props.timed; + if (this.timed === undefined) this.timed = true; + if (props.maxCountdownTime === undefined) props.maxCountdownTime = () => 4; //the id for the setInterval running the countdown @@ -84,11 +91,14 @@ class TimedNoticeComponent extends React.Component {/* Time left */} - + {this.timed ? ( + - {this.state.countdownText || (this.state.countdownTime + "s")} - + {this.state.countdownText || (this.state.countdownTime + "s")} + + ) : ""} + {/* Close button */} ; + noticeRef: React.MutableRefObject; constructor(props: SkipNoticeProps) { super(props); @@ -84,7 +84,7 @@ class SkipNoticeComponent extends React.Component -
+ ); } From 1a92265e65026173e83942886e3de994a4425700 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 10 Mar 2020 12:08:54 -0400 Subject: [PATCH 08/64] Made non timed notice the default --- src/components/NoticeComponent.tsx | 16 +++++----------- src/components/SkipNoticeComponent.tsx | 1 + 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index a988207edd..3aa330c82a 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -20,17 +20,11 @@ class NoticeComponent extends React.Component { countdownInterval: NodeJS.Timeout; idSuffix: any; - timed: boolean - amountOfPreviousNotices: number; constructor(props: NoticeProps) { super(props); - // Set default to timed - this.timed = props.timed; - if (this.timed === undefined) this.timed = true; - if (props.maxCountdownTime === undefined) props.maxCountdownTime = () => 4; //the id for the setInterval running the countdown @@ -91,7 +85,7 @@ class NoticeComponent extends React.Component { style={{top: "11px"}}> {/* Time left */} - {this.timed ? ( + {this.props.timed ? ( @@ -116,7 +110,7 @@ class NoticeComponent extends React.Component { //called every second to lower the countdown before hiding the notice countdown() { - if (!this.timed) return; + if (!this.props.timed) return; let countdownTime = this.state.countdownTime - 1; @@ -143,7 +137,7 @@ class NoticeComponent extends React.Component { } pauseCountdown() { - if (!this.timed) return; + if (!this.props.timed) return; //remove setInterval clearInterval(this.countdownInterval); @@ -162,7 +156,7 @@ class NoticeComponent extends React.Component { } startCountdown() { - if (!this.timed) return; + if (!this.props.timed) return; //if it has already started, don't start it again if (this.countdownInterval !== null) return; @@ -176,7 +170,7 @@ class NoticeComponent extends React.Component { } resetCountdown() { - if (!this.timed) return; + if (!this.props.timed) return; this.setState({ countdownTime: this.props.maxCountdownTime(), diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 236f4f05ac..50cc34a96e 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -87,6 +87,7 @@ class SkipNoticeComponent extends React.Component From a02aef591e8b9b890d7af5f6c259a65569d5e694 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Tue, 10 Mar 2020 12:57:26 -0400 Subject: [PATCH 09/64] Split notice text into a separate component --- src/components/NoticeComponent.tsx | 4 -- src/components/NoticeTextSectionComponent.tsx | 32 +++++++++ src/components/SkipNoticeComponent.tsx | 72 +++++++++---------- src/content.ts | 9 +-- 4 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 src/components/NoticeTextSectionComponent.tsx diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index 3aa330c82a..9a81ce4e48 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -48,10 +48,6 @@ class NoticeComponent extends React.Component { this.startCountdown(); } - // forwardRef(props, ref) { - - // } - render() { let noticeStyle: React.CSSProperties = { zIndex: 50 + this.amountOfPreviousNotices diff --git a/src/components/NoticeTextSectionComponent.tsx b/src/components/NoticeTextSectionComponent.tsx new file mode 100644 index 0000000000..3b64f10660 --- /dev/null +++ b/src/components/NoticeTextSectionComponent.tsx @@ -0,0 +1,32 @@ +import * as React from "react"; + +export interface NoticeTextSelectionProps { + text: string, + idSuffix: string +} + +export interface NoticeTextSelectionState { + +} + +class NoticeTextSelectionComponent extends React.Component { + countdownInterval: NodeJS.Timeout; + idSuffix: any; + + amountOfPreviousNotices: number; + + constructor(props: NoticeTextSelectionProps) { + super(props); + } + + render() { + return ( +

+ {this.props.text} +

+ ); + } +} + +export default NoticeTextSelectionComponent; \ No newline at end of file diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 50cc34a96e..85f9589322 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import Config from "../config" import NoticeComponent from "./NoticeComponent"; +import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; export interface SkipNoticeProps { UUID: string; @@ -13,6 +14,8 @@ export interface SkipNoticeProps { export interface SkipNoticeState { noticeTitle: string, + messages: string[], + countdownTime: number, maxCountdownTime: () => number; countdownText: string, @@ -63,6 +66,7 @@ class SkipNoticeComponent extends React.Component 4, @@ -90,12 +94,10 @@ class SkipNoticeComponent extends React.Component - - {/* Spacer */} - - + {/* Text Boxes */} + {this.getMessageBoxes()} + {/* Last Row */} @@ -150,6 +152,29 @@ class SkipNoticeComponent extends React.Component + + ); + } + + let elements: JSX.Element[] = []; + + for (let i = 0; i < this.state.messages.length; i++) { + elements.push( + + + ) + } + + return elements; + } + unskip() { this.contentContainer().unskipSponsorTime(this.UUID); @@ -206,7 +231,7 @@ class SkipNoticeComponent extends React.Component tbody").insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); - - if (message2 !== undefined) { - let thanksForVotingText2 = document.createElement("p"); - thanksForVotingText2.id = "sponsorTimesInfoMessage" + this.idSuffix + "2"; - thanksForVotingText2.className = "sponsorTimesInfoMessage"; - thanksForVotingText2.innerText = message2; - - //add element to div - document.querySelector("#sponsorSkipNotice" + this.idSuffix + " > tbody").insertBefore(thanksForVotingText2, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix)); - } + setNoticeInfoMessage(...messages: string[]) { + this.setState({ + messages + }) } addVoteButtonInfo(message) { diff --git a/src/content.ts b/src/content.ts index 03515e28da..e071f03356 100644 --- a/src/content.ts +++ b/src/content.ts @@ -7,6 +7,7 @@ import runThePopup from "./popup"; import PreviewBar from "./js-components/previewBar"; import SkipNotice from "./render/SkipNotice"; +import SkipNoticeComponent from "./components/SkipNoticeComponent"; // Hack to get the CSS loaded on permission-based sites (Invidious) utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); @@ -1129,11 +1130,11 @@ function clearSponsorTimes() { } //if skipNotice is null, it will not affect the UI -function vote(type, UUID, skipNotice) { +function vote(type, UUID, skipNotice: SkipNoticeComponent) { if (skipNotice != null) { //add loading info skipNotice.addVoteButtonInfo.bind(skipNotice)("Loading...") - skipNotice.resetNoticeInfoMessage.bind(skipNotice)(); + skipNotice.setNoticeInfoMessage.bind(skipNotice)(); } let sponsorIndex = UUIDs.indexOf(UUID); @@ -1168,10 +1169,10 @@ function vote(type, UUID, skipNotice) { } } else if (response.successType == 0) { //failure: duplicate vote - skipNotice.addNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail")) + skipNotice.setNoticeInfoMessage.bind(skipNotice)(chrome.i18n.getMessage("voteFail")) skipNotice.resetVoteButtonInfo.bind(skipNotice)(); } else if (response.successType == -1) { - skipNotice.addNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode)) + skipNotice.setNoticeInfoMessage.bind(skipNotice)(utils.getErrorMessage(response.statusCode)) skipNotice.resetVoteButtonInfo.bind(skipNotice)(); } } From a18235425499d1ecb508652957b73056a1fe080a Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 11 Mar 2020 17:50:50 -0400 Subject: [PATCH 10/64] Added basic react submission confirmation notice --- public/_locales/en/messages.json | 18 +++ public/content.css | 6 +- src/components/NoticeComponent.tsx | 23 ++- src/components/NoticeTextSectionComponent.tsx | 4 - src/components/SkipNoticeComponent.tsx | 4 +- src/components/SponsorTimeEditComponent.tsx | 46 ++++++ src/components/SubmissionNoticeComponent.tsx | 141 ++++++++++++++++++ src/content.ts | 41 +++-- src/render/SubmissionNotice.tsx | 47 ++++++ src/utils.ts | 15 ++ 10 files changed, 307 insertions(+), 38 deletions(-) create mode 100644 src/components/SponsorTimeEditComponent.tsx create mode 100644 src/components/SubmissionNoticeComponent.tsx create mode 100644 src/render/SubmissionNotice.tsx diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 48b25279e7..788f9a93e1 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -425,5 +425,23 @@ }, "mobileUpdateInfo": { "message": "m.youtube.com is now supported" + }, + "confirmNoticeTitle" : { + "message": "Submit Segment" + }, + "submit": { + "message": "Submit" + }, + "cancel": { + "message": "Cancel" + }, + "delete": { + "message": "Delete" + }, + "preview": { + "message": "Preview" + }, + "edit": { + "message": "Edit" } } diff --git a/public/content.css b/public/content.css index c76484ad82..04385c44cd 100644 --- a/public/content.css +++ b/public/content.css @@ -80,13 +80,15 @@ border-radius: 5px; - animation: fadeIn 0.5s; - border-spacing: 5px 10px; padding-left: 5px; padding-right: 5px; } +.sponsorSkipNoticeFadeIn { + animation: fadeIn 0.5s; +} + .sponsorSkipNoticeFadeOut { animation: fadeOut 3s cubic-bezier(0.55, 0.055, 0.675, 0.19); } diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index 9a81ce4e48..91eedbebe2 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -6,12 +6,16 @@ export interface NoticeProps { maxCountdownTime?: () => number, amountOfPreviousNotices?: number, timed?: boolean, - idSuffix: string + idSuffix?: string, + + fadeIn?: boolean } export interface NoticeState { noticeTitle: string, + maxCountdownTime?: () => number, + countdownTime: number, countdownText: string, } @@ -25,21 +29,23 @@ class NoticeComponent extends React.Component { constructor(props: NoticeProps) { super(props); - if (props.maxCountdownTime === undefined) props.maxCountdownTime = () => 4; + let maxCountdownTime = props.maxCountdownTime || (() => 4); //the id for the setInterval running the countdown this.countdownInterval = null; this.amountOfPreviousNotices = props.amountOfPreviousNotices || 0; - this.idSuffix = props.idSuffix; + this.idSuffix = props.idSuffix || ""; // Setup state this.state = { noticeTitle: props.noticeTitle, + maxCountdownTime, + //the countdown until this notice closes - countdownTime: props.maxCountdownTime(), + countdownTime: maxCountdownTime(), countdownText: null, } } @@ -55,7 +61,8 @@ class NoticeComponent extends React.Component { return ( @@ -141,7 +148,7 @@ class NoticeComponent extends React.Component { //reset countdown and inform the user this.setState({ - countdownTime: this.props.maxCountdownTime(), + countdownTime: this.state.maxCountdownTime(), countdownText: chrome.i18n.getMessage("paused") }); @@ -158,7 +165,7 @@ class NoticeComponent extends React.Component { if (this.countdownInterval !== null) return; this.setState({ - countdownTime: this.props.maxCountdownTime(), + countdownTime: this.state.maxCountdownTime(), countdownText: null }); @@ -169,7 +176,7 @@ class NoticeComponent extends React.Component { if (!this.props.timed) return; this.setState({ - countdownTime: this.props.maxCountdownTime(), + countdownTime: this.state.maxCountdownTime(), countdownText: null }); } diff --git a/src/components/NoticeTextSectionComponent.tsx b/src/components/NoticeTextSectionComponent.tsx index 3b64f10660..839d74480c 100644 --- a/src/components/NoticeTextSectionComponent.tsx +++ b/src/components/NoticeTextSectionComponent.tsx @@ -10,10 +10,6 @@ export interface NoticeTextSelectionState { } class NoticeTextSelectionComponent extends React.Component { - countdownInterval: NodeJS.Timeout; - idSuffix: any; - - amountOfPreviousNotices: number; constructor(props: NoticeTextSelectionProps) { super(props); diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 85f9589322..e15407c1c1 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -91,6 +91,7 @@ class SkipNoticeComponent extends React.Component @@ -167,7 +168,8 @@ class SkipNoticeComponent extends React.Component + text={this.state.messages[i]} + key={i}> ) } diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx new file mode 100644 index 0000000000..9a52896f5e --- /dev/null +++ b/src/components/SponsorTimeEditComponent.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; + +export interface SponsorTimeEditProps { + index: number, + + idSuffix: string, + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; +} + +export interface SponsorTimeEditState { + +} + +class SponsorTimeEditComponent extends React.Component { + + constructor(props: SponsorTimeEditProps) { + super(props); + } + + render() { + return ( + <> +
+ {this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0] + + " to " + this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1]} +
+ + + {chrome.i18n.getMessage("delete")} + + + + {chrome.i18n.getMessage("preview")} + + + + {chrome.i18n.getMessage("edit")} + + + ); + } +} + +export default SponsorTimeEditComponent; \ No newline at end of file diff --git a/src/components/SubmissionNoticeComponent.tsx b/src/components/SubmissionNoticeComponent.tsx new file mode 100644 index 0000000000..69c57c0f00 --- /dev/null +++ b/src/components/SubmissionNoticeComponent.tsx @@ -0,0 +1,141 @@ +import * as React from "react"; +import Config from "../config" + +import NoticeComponent from "./NoticeComponent"; +import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; +import SponsorTimeEditComponent from "./SponsorTimeEditComponent"; + +export interface SkipNoticeProps { + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; + + callback: () => any; +} + +export interface SkipNoticeState { + noticeTitle: string, + messages: string[], + idSuffix: string; +} + +class SkipNoticeComponent extends React.Component { + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; + + callback: () => any; + + noticeRef: React.MutableRefObject; + + constructor(props: SkipNoticeProps) { + super(props); + this.noticeRef = React.createRef(); + + this.contentContainer = props.contentContainer; + this.callback = props.callback; + + let noticeTitle = chrome.i18n.getMessage("confirmNoticeTitle"); + + // Setup state + this.state = { + noticeTitle, + messages: [], + idSuffix: "SubmissionNotice" + } + } + + render() { + let noticeStyle: React.CSSProperties = {}; + if (this.contentContainer().onMobileYouTube) { + noticeStyle.bottom = "4em"; + noticeStyle.transform = "scale(0.8) translate(10%, 10%)"; + } + + return ( + + + {/* Text Boxes */} + {this.getMessageBoxes()} + + {/* Sponsor Time List */} +
+ + + + {/* Last Row */} + + + + + + + ); + } + + getSponsorTimeMessages(): JSX.Element[] | JSX.Element { + let elements: JSX.Element[] = []; + + let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting; + + for (let i = 0; i < sponsorTimes.length; i++) { + elements.push( + + + ) + } + + return elements; + } + + getMessageBoxes(): JSX.Element[] | JSX.Element { + let elements: JSX.Element[] = []; + + for (let i = 0; i < this.state.messages.length; i++) { + elements.push( + + + ) + } + + return elements; + } + + cancel() { + this.noticeRef.current.close(); + + this.contentContainer().resetSponsorSubmissionNotice(); + } + + submit() { + this.props.callback(); + + this.cancel(); + } + +} + +export default SkipNoticeComponent; \ No newline at end of file diff --git a/src/content.ts b/src/content.ts index e071f03356..75bcb9d031 100644 --- a/src/content.ts +++ b/src/content.ts @@ -8,6 +8,7 @@ import runThePopup from "./popup"; import PreviewBar from "./js-components/previewBar"; import SkipNotice from "./render/SkipNotice"; import SkipNoticeComponent from "./components/SkipNoticeComponent"; +import SubmissionNotice from "./render/SubmissionNotice"; // Hack to get the CSS loaded on permission-based sites (Invidious) utils.wait(() => Config.config !== null, 5000, 10).then(addCSS); @@ -87,18 +88,23 @@ var sponsorTimesSubmitting = []; //this is used to close the popup on YouTube when the other popup opens var popupInitialised = false; +var submissionNotice: SubmissionNotice = null; + // Contains all of the functions and variables needed by the skip notice var skipNoticeContentContainer = () => ({ vote, dontShowNoticeAgain, unskipSponsorTime, sponsorTimes, + sponsorTimesSubmitting, UUIDs, v: video, reskipSponsorTime, hiddenSponsorTimes, updatePreviewBar, - onMobileYouTube + onMobileYouTube, + sponsorSubmissionNotice: submissionNotice, + resetSponsorSubmissionNotice }); //get messages from the background script and the popup @@ -1205,12 +1211,21 @@ function sponsorMessageStarted(callback) { toggleStartSponsorButton(); } +/** + * Helper method for the submission notice to clear itself when it closes + */ +function resetSponsorSubmissionNotice() { + submissionNotice = null; +} + function submitSponsorTimes() { if (document.getElementById("submitButton").style.display == "none") { //don't submit, not ready return; } + if (submissionNotice !== null) return; + //it can't update to this info yet closeInfoMenu(); @@ -1242,11 +1257,7 @@ function submitSponsorTimes() { } } - let confirmMessage = chrome.i18n.getMessage("submitCheck") + "\n\n" + getSponsorTimesMessage(sponsorTimes) - + "\n\n" + chrome.i18n.getMessage("confirmMSG") + "\n\n" + chrome.i18n.getMessage("guildlinesSummary"); - if(!confirm(confirmMessage)) return; - - sendSubmitMessage(); + submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage); } } @@ -1314,7 +1325,7 @@ function getSponsorTimesMessage(sponsorTimes) { for (let i = 0; i < sponsorTimes.length; i++) { for (let s = 0; s < sponsorTimes[i].length; s++) { - let timeMessage = getFormattedTime(sponsorTimes[i][s]); + let timeMessage = utils.getFormattedTime(sponsorTimes[i][s]); //if this is an end time if (s == 1) { timeMessage = " to " + timeMessage; @@ -1377,22 +1388,6 @@ function addCSS() { } } -//converts time in seconds to minutes:seconds -function getFormattedTime(seconds) { - let minutes = Math.floor(seconds / 60); - let secondsNum: number = Math.round(seconds - minutes * 60); - let secondsDisplay: string = String(secondsNum); - - if (secondsNum < 10) { - //add a zero - secondsDisplay = "0" + secondsNum; - } - - let formatted = minutes + ":" + secondsDisplay; - - return formatted; -} - function sendRequestToCustomServer(type, fullAddress, callback) { let xmlhttp = new XMLHttpRequest(); diff --git a/src/render/SubmissionNotice.tsx b/src/render/SubmissionNotice.tsx new file mode 100644 index 0000000000..0c961fcd86 --- /dev/null +++ b/src/render/SubmissionNotice.tsx @@ -0,0 +1,47 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; + +import SubmissionNoticeComponent from "../components/SubmissionNoticeComponent"; + +class SubmissionNotice { + // Contains functions and variables from the content script needed by the skip notice + contentContainer: () => any; + + callback: () => any; + + constructor(contentContainer: () => any, callback: () => any) { + this.contentContainer = contentContainer; + this.callback = callback; + + //get reference node + let referenceNode = document.getElementById("player-container-id") + || document.getElementById("movie_player") || document.querySelector("#player-container .video-js"); + if (referenceNode == null) { + //for embeds + let player = document.getElementById("player"); + referenceNode = player.firstChild as HTMLElement; + let index = 1; + + //find the child that is the video player (sometimes it is not the first) + while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) { + referenceNode = player.children[index] as HTMLElement; + + index++; + } + } + + let noticeElement = document.createElement("div"); + noticeElement.id = "submissionNoticeContainer"; + + referenceNode.prepend(noticeElement); + + ReactDOM.render( + , + noticeElement + ); + } +} + +export default SubmissionNotice; \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 2134c6d794..4c5e4a0eff 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -256,6 +256,21 @@ class Utils { xmlhttp.send(); } + getFormattedTime(seconds) { + let minutes = Math.floor(seconds / 60); + let secondsNum: number = Math.round(seconds - minutes * 60); + let secondsDisplay: string = String(secondsNum); + + if (secondsNum < 10) { + //add a zero + secondsDisplay = "0" + secondsNum; + } + + let formatted = minutes + ":" + secondsDisplay; + + return formatted; + } + /** * Is this Firefox (web-extensions) */ From 3063591a4c147212b128001aae62eaf6e2ee224d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 11 Mar 2020 19:35:20 -0400 Subject: [PATCH 11/64] Added delete function to new dialog --- public/content.css | 17 +++++ src/background.ts | 2 +- src/components/SkipNoticeComponent.tsx | 5 +- src/components/SponsorTimeEditComponent.tsx | 68 +++++++++++++++++--- src/components/SubmissionNoticeComponent.tsx | 21 +++--- src/content.ts | 14 ++-- src/types.ts | 29 ++++++++- 7 files changed, 127 insertions(+), 29 deletions(-) diff --git a/public/content.css b/public/content.css index 04385c44cd..fb600aa469 100644 --- a/public/content.css +++ b/public/content.css @@ -313,4 +313,21 @@ .sponsorSkipDontShowButton:active { position:relative; top:1px; +} + +/* Submission Notice */ + +.sponsorTimeDisplay { + font-size: 15px; +} + +.sponsorTimeEditButton { + text-decoration: underline; + + margin-left: 20px; + margin-right: 20px; + + font-size: 13px; + + cursor: pointer; } \ No newline at end of file diff --git a/src/background.ts b/src/background.ts index d0508d2c9c..9fedf5fc40 100644 --- a/src/background.ts +++ b/src/background.ts @@ -187,7 +187,7 @@ async function submitTimes(videoID, callback) { let userID = Config.config.userID; if (sponsorTimes != undefined && sponsorTimes.length > 0) { - let durationResult = await new Promise((resolve, reject) => { + let durationResult = await new Promise((resolve, reject) => { chrome.tabs.query({ active: true, currentWindow: true diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index e15407c1c1..a366af7a02 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import Config from "../config" +import { ContentContainer } from "../types"; import NoticeComponent from "./NoticeComponent"; import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; @@ -8,7 +9,7 @@ export interface SkipNoticeProps { UUID: string; manualSkip: boolean; // Contains functions and variables from the content script needed by the skip notice - contentContainer: () => any; + contentContainer: ContentContainer; } export interface SkipNoticeState { @@ -28,7 +29,7 @@ class SkipNoticeComponent extends React.Component any; + contentContainer: ContentContainer; amountOfPreviousNotices: number; diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 9a52896f5e..a958aa16e8 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -1,11 +1,20 @@ import * as React from "react"; +import Config from "../config" + +import Utils from "../utils"; +import { ContentContainer } from "../types"; +import SubmissionNoticeComponent from "./SubmissionNoticeComponent"; +var utils = new Utils(); + export interface SponsorTimeEditProps { index: number, idSuffix: string, // Contains functions and variables from the content script needed by the skip notice - contentContainer: () => any; + contentContainer: ContentContainer, + + submissionNotice: SubmissionNoticeComponent; } export interface SponsorTimeEditState { @@ -19,28 +28,69 @@ class SponsorTimeEditComponent extends React.Component +
- {this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0] - + " to " + this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1]} + className="sponsorTimeDisplay"> + {utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0]) + + " to " + utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1])}
- + {chrome.i18n.getMessage("delete")} - + {chrome.i18n.getMessage("preview")} - + {chrome.i18n.getMessage("edit")} - +
); } + + deleteTime(): void { + let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting; + let index = this.props.index; + + //if it is not a complete sponsor time + if (sponsorTimes[index].length < 2) { + //update video player + this.props.contentContainer().changeStartSponsorButton(true, false); + } + + sponsorTimes.splice(index, 1); + + //save this + Config.config.sponsorTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimes); + + this.props.contentContainer().updatePreviewBar(); + + //if they are all removed + if (sponsorTimes.length == 0) { + this.props.submissionNotice.cancel(); + + //update video player + this.props.contentContainer().changeStartSponsorButton(true, false); + } else { + //update display + this.props.submissionNotice.forceUpdate(); + } + } } export default SponsorTimeEditComponent; \ No newline at end of file diff --git a/src/components/SubmissionNoticeComponent.tsx b/src/components/SubmissionNoticeComponent.tsx index 69c57c0f00..b85efce8c8 100644 --- a/src/components/SubmissionNoticeComponent.tsx +++ b/src/components/SubmissionNoticeComponent.tsx @@ -1,32 +1,33 @@ import * as React from "react"; import Config from "../config" +import { ContentContainer } from "../types"; import NoticeComponent from "./NoticeComponent"; import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; import SponsorTimeEditComponent from "./SponsorTimeEditComponent"; -export interface SkipNoticeProps { +export interface SubmissionNoticeProps { // Contains functions and variables from the content script needed by the skip notice - contentContainer: () => any; + contentContainer: ContentContainer; callback: () => any; } -export interface SkipNoticeState { +export interface SubmissionNoticeeState { noticeTitle: string, messages: string[], idSuffix: string; } -class SkipNoticeComponent extends React.Component { +class SubmissionNoticeComponent extends React.Component { // Contains functions and variables from the content script needed by the skip notice - contentContainer: () => any; + contentContainer: ContentContainer; callback: () => any; noticeRef: React.MutableRefObject; - constructor(props: SkipNoticeProps) { + constructor(props: SubmissionNoticeProps) { super(props); this.noticeRef = React.createRef(); @@ -101,7 +102,8 @@ class SkipNoticeComponent extends React.Component + contentContainer={this.props.contentContainer} + submissionNotice={this}> ) } @@ -118,7 +120,7 @@ class SkipNoticeComponent extends React.Component - ) + ); } return elements; @@ -135,7 +137,6 @@ class SkipNoticeComponent extends React.Component ({ +var skipNoticeContentContainer: ContentContainer = () => ({ vote, dontShowNoticeAgain, unskipSponsorTime, sponsorTimes, sponsorTimesSubmitting, + hiddenSponsorTimes, UUIDs, v: video, + sponsorVideoID, reskipSponsorTime, - hiddenSponsorTimes, updatePreviewBar, onMobileYouTube, sponsorSubmissionNotice: submissionNotice, - resetSponsorSubmissionNotice + resetSponsorSubmissionNotice, + changeStartSponsorButton }); //get messages from the background script and the popup @@ -1136,8 +1140,8 @@ function clearSponsorTimes() { } //if skipNotice is null, it will not affect the UI -function vote(type, UUID, skipNotice: SkipNoticeComponent) { - if (skipNotice != null) { +function vote(type, UUID, skipNotice?: SkipNoticeComponent) { + if (skipNotice !== null && skipNotice !== undefined) { //add loading info skipNotice.addVoteButtonInfo.bind(skipNotice)("Loading...") skipNotice.setNoticeInfoMessage.bind(skipNotice)(); diff --git a/src/types.ts b/src/types.ts index 7b50adaba1..3ee9743ae0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,32 @@ -interface videoDurationResponse { +import SubmissionNotice from "./render/SubmissionNotice"; +import SkipNoticeComponent from "./components/SkipNoticeComponent"; + +interface ContentContainer { + (): { + vote: (type: any, UUID: any, skipNotice?: SkipNoticeComponent) => void, + dontShowNoticeAgain: () => void, + unskipSponsorTime: (UUID: any) => void, + sponsorTimes: number[][], + sponsorTimesSubmitting: number[][], + hiddenSponsorTimes: any[], + UUIDs: any[], + v: HTMLVideoElement, + sponsorVideoID, + reskipSponsorTime: (UUID: any) => void, + updatePreviewBar: () => void, + onMobileYouTube: boolean, + sponsorSubmissionNotice: SubmissionNotice, + resetSponsorSubmissionNotice: () => void, + changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise + } +} + +interface VideoDurationResponse { duration: number; } + export { - videoDurationResponse + VideoDurationResponse, + ContentContainer }; \ No newline at end of file From 37662138df225cc07ecedf590f4eec0d4bc7b534 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 11 Mar 2020 19:48:51 -0400 Subject: [PATCH 12/64] Increase precision in submission preview --- src/components/SponsorTimeEditComponent.tsx | 4 ++-- src/utils.ts | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index a958aa16e8..bed005b91e 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -40,8 +40,8 @@ class SponsorTimeEditComponent extends React.Component
- {utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0]) - + " to " + utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1])} + {utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0], true) + + " to " + utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1], true)}
Date: Wed, 11 Mar 2020 19:56:16 -0400 Subject: [PATCH 13/64] Made preview button functional --- src/components/SponsorTimeEditComponent.tsx | 21 +++++++++++++++++- src/content.ts | 24 ++++++++++++++++++++- src/types.ts | 3 ++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index bed005b91e..42f84f80c2 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -51,7 +51,8 @@ class SponsorTimeEditComponent extends React.Component + className="sponsorTimeEditButton" + onClick={this.previewTime.bind(this)}> {chrome.i18n.getMessage("preview")} @@ -63,6 +64,24 @@ class SponsorTimeEditComponent extends React.Component ({ onMobileYouTube, sponsorSubmissionNotice: submissionNotice, resetSponsorSubmissionNotice, - changeStartSponsorButton + changeStartSponsorButton, + previewTime }); //get messages from the background script and the popup @@ -861,6 +862,27 @@ function getStartTimes(sponsorTimes: number[][], minimum?: number, hideHiddenSpo return startTimes; } +/** + * Skip to exact time in a video and autoskips + * + * @param time + */ +function previewTime(time: number) { + video.currentTime = time; + + // Unpause the video if needed + if (video.paused){ + video.play(); + } + + // Start preview resetter + if (previewResetter !== null){ + clearTimeout(previewResetter); + } + + previewResetter = setTimeout(() => previewResetter = null, 4000); +} + //skip from the start time to the end time for a certain index sponsor time function skipToTime(v, index, sponsorTimes, openNotice) { if (!Config.config.disableAutoSkip || previewResetter !== null) { diff --git a/src/types.ts b/src/types.ts index 3ee9743ae0..7008f2e18b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -17,7 +17,8 @@ interface ContentContainer { onMobileYouTube: boolean, sponsorSubmissionNotice: SubmissionNotice, resetSponsorSubmissionNotice: () => void, - changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise + changeStartSponsorButton: (showStartSponsor: any, uploadButtonVisible: any) => Promise, + previewTime: (time: number) => void } } From 0d08e11b1dd7ef95619838208f6504c315d6b324 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 1 Apr 2020 20:06:46 -0400 Subject: [PATCH 14/64] Added basic time editing. The button presses don't work yet as YouTube steals the events. --- public/_locales/en/messages.json | 4 + public/content.css | 20 +++ src/components/SponsorTimeEditComponent.tsx | 165 ++++++++++++++++++-- src/utils.ts | 12 ++ 4 files changed, 184 insertions(+), 17 deletions(-) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index db4453417b..e7c760df99 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -479,5 +479,9 @@ }, "keyAlreadyUsed": { "message": "is bound to another action. Please select another key." + }, + "to": { + "message": "to", + "description": "Used between sponsor times. Example: 1:20 to 1:30" } } diff --git a/public/content.css b/public/content.css index fb600aa469..3402725a36 100644 --- a/public/content.css +++ b/public/content.css @@ -330,4 +330,24 @@ font-size: 13px; cursor: pointer; +} + +.sponsorTimeEdit > input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +.sponsorTimeEdit { + font-size: 14px; + + -moz-appearance: textfield; +} + +.sponsorTimeEditMinutes { + width: 30px; +} + +.sponsorTimeEditSeconds { + width: 60px; } \ No newline at end of file diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 42f84f80c2..ef920e7b3c 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -18,13 +18,32 @@ export interface SponsorTimeEditProps { } export interface SponsorTimeEditState { - + editing: boolean; + sponsorTimeEdits: Array>; } class SponsorTimeEditComponent extends React.Component { + idSuffix: string; + constructor(props: SponsorTimeEditProps) { super(props); + + this.idSuffix = this.idSuffix; + + this.state = { + editing: false, + sponsorTimeEdits: [[null, null], [null, null]] + }; + } + + componentDidMount() { + // // Prevent inputs from triggering key events + // document.addEventListener("keydown", (event) => { + // if (document.activeElement.classList.contains("sponsorTimeEdit")) { + // event.stopPropagation(); + // } + // }); } render() { @@ -36,34 +55,146 @@ class SponsorTimeEditComponent extends React.Component -
{ + // if (document.activeElement.classList.contains("sponsorTimeEdit")) { + // event.stopImmediatePropagation(); + // event.stopPropagation(); + // event.preventDefault(); + // } + // }); + + // Create time display + let timeDisplay: JSX.Element; + let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; + if (this.state.editing) { + + timeDisplay = ( +
- {utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][0], true) - + " to " + utils.getFormattedTime(this.props.contentContainer().sponsorTimesSubmitting[this.props.index][1], true)} + event.stopPropagation()} + onKeyDown={(event) => { + event.stopPropagation(); + }} + onKeyPress={(event) => event.stopPropagation()} + onKeyPressCapture={(event) => event.stopPropagation()} + onChange={(e) => { + let sponsorTimeEdits = this.state.sponsorTimeEdits; + sponsorTimeEdits[0][0] = parseFloat(e.target.value); + + this.setState({sponsorTimeEdits}); + }}> + + + { + let sponsorTimeEdits = this.state.sponsorTimeEdits; + sponsorTimeEdits[0][1] = parseFloat(e.target.value); + + this.setState({sponsorTimeEdits}); + }}> + + + + {" " + chrome.i18n.getMessage("to") + " "} + + + { + let sponsorTimeEdits = this.state.sponsorTimeEdits; + sponsorTimeEdits[1][0] = parseFloat(e.target.value); + + this.setState({sponsorTimeEdits}); + }}> + + + { + let sponsorTimeEdits = this.state.sponsorTimeEdits; + sponsorTimeEdits[1][1] = parseFloat(e.target.value); + + this.setState({sponsorTimeEdits}); + }}> +
+ ); + } else { + timeDisplay = ( +
+ {utils.getFormattedTime(sponsorTime[0], true) + + ((sponsorTime.length >= 1) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(sponsorTime[1], true) : "")} +
+ ); + } - + + {timeDisplay} + + {chrome.i18n.getMessage("delete")} - - {chrome.i18n.getMessage("preview")} - - - - {chrome.i18n.getMessage("edit")} - + {(sponsorTime.length >= 1) ? ( + + {chrome.i18n.getMessage("preview")} + + ): ""} + + {(sponsorTime.length >= 1) ? ( + + {this.state.editing ? chrome.i18n.getMessage("save") : chrome.i18n.getMessage("edit")} + + ): ""}
); } + toggleEditTime(): void { + if (this.state.editing) { + + this.setState({ + editing: false + }); + + // Save sponsorTimes + this.props.contentContainer().sponsorTimesSubmitting[this.props.index] = + [utils.getRawSeconds(this.state.sponsorTimeEdits[0][0], this.state.sponsorTimeEdits[0][1]), + utils.getRawSeconds(this.state.sponsorTimeEdits[1][0], this.state.sponsorTimeEdits[1][1])]; + + this.props.contentContainer().updatePreviewBar(); + } else { + let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; + + this.setState({ + editing: true, + sponsorTimeEdits: [[utils.getFormattedMinutes(sponsorTime[0]), utils.getFormattedSeconds(sponsorTime[0])], + [utils.getFormattedMinutes(sponsorTime[1]), utils.getFormattedSeconds(sponsorTime[1])]] + }); + } + } + previewTime(): void { let sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting; let index = this.props.index; diff --git a/src/utils.ts b/src/utils.ts index 5b392e0e0a..1eefd27472 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -256,6 +256,14 @@ class Utils { xmlhttp.send(); } + getFormattedMinutes(seconds: number) { + return Math.floor(seconds / 60); + } + + getFormattedSeconds(seconds: number) { + return seconds % 60; + } + getFormattedTime(seconds: number, precise?: boolean) { let minutes = Math.floor(seconds / 60); let secondsNum: number = seconds - minutes * 60; @@ -275,6 +283,10 @@ class Utils { return formatted; } + getRawSeconds(minutes: number, seconds: number): number { + return minutes * 60 + seconds; + } + /** * Is this Firefox (web-extensions) */ From 24f2ce4a327c9e6fd8dc4634cdb0752debd4c8ab Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 1 Apr 2020 20:19:31 -0400 Subject: [PATCH 15/64] Fixed event propagation issues --- src/components/SponsorTimeEditComponent.tsx | 25 ++++----------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index ef920e7b3c..66bf876e99 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -38,12 +38,10 @@ class SponsorTimeEditComponent extends React.Component { - // if (document.activeElement.classList.contains("sponsorTimeEdit")) { - // event.stopPropagation(); - // } - // }); + // Prevent inputs from triggering key events + document.getElementById("sponsorTimesContainer" + this.idSuffix).addEventListener('keydown', function (event) { + event.stopPropagation(); + }); } render() { @@ -55,15 +53,6 @@ class SponsorTimeEditComponent extends React.Component { - // if (document.activeElement.classList.contains("sponsorTimeEdit")) { - // event.stopImmediatePropagation(); - // event.stopPropagation(); - // event.preventDefault(); - // } - // }); - // Create time display let timeDisplay: JSX.Element; let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; @@ -76,12 +65,6 @@ class SponsorTimeEditComponent extends React.Component event.stopPropagation()} - onKeyDown={(event) => { - event.stopPropagation(); - }} - onKeyPress={(event) => event.stopPropagation()} - onKeyPressCapture={(event) => event.stopPropagation()} onChange={(e) => { let sponsorTimeEdits = this.state.sponsorTimeEdits; sponsorTimeEdits[0][0] = parseFloat(e.target.value); From 242fbf800997f0c63d24002acf4ace74b9ccd749 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 1 Apr 2020 20:22:51 -0400 Subject: [PATCH 16/64] Save edits correctly --- src/components/SponsorTimeEditComponent.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 66bf876e99..4b847050ae 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -166,6 +166,8 @@ class SponsorTimeEditComponent extends React.Component Date: Wed, 1 Apr 2020 20:24:50 -0400 Subject: [PATCH 17/64] Save edits before previewing --- src/components/SponsorTimeEditComponent.tsx | 32 ++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 4b847050ae..971f48bca9 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -161,14 +161,7 @@ class SponsorTimeEditComponent extends React.Component Date: Wed, 1 Apr 2020 20:38:10 -0400 Subject: [PATCH 18/64] Added now button to editor --- public/_locales/en/messages.json | 3 ++ public/content.css | 7 ++++ src/components/SponsorTimeEditComponent.tsx | 42 ++++++++++++++++++--- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index e7c760df99..69ef638669 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -483,5 +483,8 @@ "to": { "message": "to", "description": "Used between sponsor times. Example: 1:20 to 1:30" + }, + "bracketNow": { + "message": "(Now)" } } diff --git a/public/content.css b/public/content.css index 3402725a36..11d20ff919 100644 --- a/public/content.css +++ b/public/content.css @@ -350,4 +350,11 @@ input::-webkit-inner-spin-button { .sponsorTimeEditSeconds { width: 60px; +} + +.sponsorNowButton { + font-size: 11px; + + cursor: pointer; + text-decoration: underline; } \ No newline at end of file diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 971f48bca9..128516018a 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -19,7 +19,7 @@ export interface SponsorTimeEditProps { export interface SponsorTimeEditState { editing: boolean; - sponsorTimeEdits: Array>; + sponsorTimeEdits: number[][]; } class SponsorTimeEditComponent extends React.Component { @@ -61,6 +61,13 @@ class SponsorTimeEditComponent extends React.Component + + this.setTimeToNow.bind(this)(0)).bind(this)}> + {chrome.i18n.getMessage("bracketNow")} + + + + this.setTimeToNow.bind(this)(1)).bind(this)}> + {chrome.i18n.getMessage("bracketNow")} + ); } else { timeDisplay = (
+ className="sponsorTimeDisplay" + onClick={this.toggleEditTime.bind(this)}> {utils.getFormattedTime(sponsorTime[0], true) + ((sponsorTime.length >= 1) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(sponsorTime[1], true) : "")}
@@ -154,6 +168,17 @@ class SponsorTimeEditComponent extends React.Component Date: Thu, 2 Apr 2020 00:44:38 -0400 Subject: [PATCH 19/64] Fixed close button on submission confirmation notice --- src/components/NoticeComponent.tsx | 15 +++++++++++---- src/components/SponsorTimeEditComponent.tsx | 4 ++-- src/components/SubmissionNoticeComponent.tsx | 5 +++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index 91eedbebe2..cde3db6024 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -8,7 +8,10 @@ export interface NoticeProps { timed?: boolean, idSuffix?: string, - fadeIn?: boolean + fadeIn?: boolean, + + // Callback for when this is closed + closeListener?: () => void } export interface NoticeState { @@ -100,7 +103,7 @@ class NoticeComponent extends React.Component { {/* Close button */} + onClick={() => this.close()}> @@ -181,8 +184,10 @@ class NoticeComponent extends React.Component { }); } - //close this notice - close() { + /** + * @param silent If true, the close listener will not be called + */ + close(silent?: boolean) { //TODO: Change to a listener in the renderer (not component) let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix); if (notice != null) { @@ -191,6 +196,8 @@ class NoticeComponent extends React.Component { //remove setInterval if (this.countdownInterval !== null) clearInterval(this.countdownInterval); + + if (this.props.closeListener && !silent) this.props.closeListener(); } changeNoticeTitle(title) { diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 128516018a..a3ad3c3b93 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -64,7 +64,7 @@ class SponsorTimeEditComponent extends React.Component this.setTimeToNow.bind(this)(0)).bind(this)}> + onClick={() => this.setTimeToNow(0)}> {chrome.i18n.getMessage("bracketNow")}
@@ -122,7 +122,7 @@ class SponsorTimeEditComponent extends React.Component this.setTimeToNow.bind(this)(1)).bind(this)}> + onClick={() => this.setTimeToNow(1)}> {chrome.i18n.getMessage("bracketNow")} diff --git a/src/components/SubmissionNoticeComponent.tsx b/src/components/SubmissionNoticeComponent.tsx index b85efce8c8..edb04b1cd5 100644 --- a/src/components/SubmissionNoticeComponent.tsx +++ b/src/components/SubmissionNoticeComponent.tsx @@ -54,7 +54,8 @@ class SubmissionNoticeComponent extends React.Component + ref={this.noticeRef} + closeListener={this.cancel.bind(this)}> {/* Text Boxes */} {this.getMessageBoxes()} @@ -127,7 +128,7 @@ class SubmissionNoticeComponent extends React.Component Date: Thu, 2 Apr 2020 00:59:11 -0400 Subject: [PATCH 20/64] Submission notice now updates when sponsors are added --- src/components/SponsorTimeEditComponent.tsx | 6 +++--- src/content.ts | 4 ++++ src/render/SubmissionNotice.tsx | 11 ++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index a3ad3c3b93..2ca8b020f9 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -133,7 +133,7 @@ class SponsorTimeEditComponent extends React.Component {utils.getFormattedTime(sponsorTime[0], true) + - ((sponsorTime.length >= 1) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(sponsorTime[1], true) : "")} + ((!isNaN(sponsorTime[1])) ? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(sponsorTime[1], true) : "")} ); } @@ -149,7 +149,7 @@ class SponsorTimeEditComponent extends React.Component - {(sponsorTime.length >= 1) ? ( + {(!isNaN(sponsorTime[1])) ? ( @@ -157,7 +157,7 @@ class SponsorTimeEditComponent extends React.Component ): ""} - {(sponsorTime.length >= 1) ? ( + {(!isNaN(sponsorTime[1])) ? ( diff --git a/src/content.ts b/src/content.ts index c90e6ea388..187bb264e7 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1105,6 +1105,10 @@ function updateSponsorTimesSubmitting() { // Restart skipping schedule startSponsorSchedule(); + + if (submissionNotice !== null) { + submissionNotice.update(); + } } } }); diff --git a/src/render/SubmissionNotice.tsx b/src/render/SubmissionNotice.tsx index 0c961fcd86..bebed3e20a 100644 --- a/src/render/SubmissionNotice.tsx +++ b/src/render/SubmissionNotice.tsx @@ -9,7 +9,11 @@ class SubmissionNotice { callback: () => any; + noticeRef: React.MutableRefObject; + constructor(contentContainer: () => any, callback: () => any) { + this.noticeRef = React.createRef(); + this.contentContainer = contentContainer; this.callback = callback; @@ -38,10 +42,15 @@ class SubmissionNotice { ReactDOM.render( , + callback={callback} + ref={this.noticeRef} />, noticeElement ); } + + update() { + this.noticeRef.current.forceUpdate(); + } } export default SubmissionNotice; \ No newline at end of file From e17eb60b4d9dbeb580f1938154f1a13e543056a8 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 01:25:06 -0400 Subject: [PATCH 21/64] Added basic category selector to the UI --- public/_locales/en/messages.json | 16 ++++++++++-- public/content.css | 11 ++++++++ src/components/SponsorTimeEditComponent.tsx | 28 ++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 69ef638669..6890095997 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -484,7 +484,19 @@ "message": "to", "description": "Used between sponsor times. Example: 1:20 to 1:30" }, - "bracketNow": { - "message": "(Now)" + "category_sponsor": { + "message": "Sponsor" + }, + "category_intro": { + "message": "Intro" + }, + "category_outro": { + "message": "Outro" + }, + "category_interaction": { + "message": "Interaction (Redundant Like, Subscribe, Follow, etc.)" + }, + "category_merchandise": { + "message": "Merchandise and self-promotion" } } diff --git a/public/content.css b/public/content.css index 11d20ff919..5d65f788f9 100644 --- a/public/content.css +++ b/public/content.css @@ -357,4 +357,15 @@ input::-webkit-inner-spin-button { cursor: pointer; text-decoration: underline; +} + +.sponsorTimeCategories { + margin-top: 5px; + margin-bottom: 5px; + + background-color: rgba(28, 28, 28, 0.9); + border-color: rgb(130,0,0,0.9); + color: white; + border-width: 3px; + padding: 3px; } \ No newline at end of file diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 2ca8b020f9..fd9bc7c412 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -1,6 +1,7 @@ import * as React from "react"; -import Config from "../config" +import Config from "../config"; +import * as CompileConfig from "../../config.json"; import Utils from "../utils"; import { ContentContainer } from "../types"; @@ -143,6 +144,17 @@ class SponsorTimeEditComponent extends React.Component + {this.getCategoryOptions()} + + +
+ + {/* Editing Tools */} + @@ -168,6 +180,20 @@ class SponsorTimeEditComponent extends React.Component + {chrome.i18n.getMessage("category_" + category)} + + ); + } + + return elements; + } + setTimeToNow(index: number) { let sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; From 5575eda7b1ef109536aa2db49eddff7cbc2e8a73 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 01:29:12 -0400 Subject: [PATCH 22/64] Changed UI data to be store in strings for better UX --- src/components/SponsorTimeEditComponent.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index fd9bc7c412..ba24089016 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -20,7 +20,7 @@ export interface SponsorTimeEditProps { export interface SponsorTimeEditState { editing: boolean; - sponsorTimeEdits: number[][]; + sponsorTimeEdits: string[][]; } class SponsorTimeEditComponent extends React.Component { @@ -75,7 +75,7 @@ class SponsorTimeEditComponent extends React.Component { let sponsorTimeEdits = this.state.sponsorTimeEdits; - sponsorTimeEdits[0][0] = parseFloat(e.target.value); + sponsorTimeEdits[0][0] = e.target.value; this.setState({sponsorTimeEdits}); }}> @@ -87,7 +87,7 @@ class SponsorTimeEditComponent extends React.Component { let sponsorTimeEdits = this.state.sponsorTimeEdits; - sponsorTimeEdits[0][1] = parseFloat(e.target.value); + sponsorTimeEdits[0][1] = e.target.value; this.setState({sponsorTimeEdits}); }}> @@ -103,7 +103,7 @@ class SponsorTimeEditComponent extends React.Component { let sponsorTimeEdits = this.state.sponsorTimeEdits; - sponsorTimeEdits[1][0] = parseFloat(e.target.value); + sponsorTimeEdits[1][0] = e.target.value; this.setState({sponsorTimeEdits}); }}> @@ -115,7 +115,7 @@ class SponsorTimeEditComponent extends React.Component { let sponsorTimeEdits = this.state.sponsorTimeEdits; - sponsorTimeEdits[1][1] = parseFloat(e.target.value); + sponsorTimeEdits[1][1] = e.target.value; this.setState({sponsorTimeEdits}); }}> @@ -224,16 +224,16 @@ class SponsorTimeEditComponent extends React.Component Date: Thu, 2 Apr 2020 01:33:28 -0400 Subject: [PATCH 23/64] Added category list to example config --- config.json.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index 2f7f052042..e2a2f44b43 100644 --- a/config.json.example +++ b/config.json.example @@ -1,4 +1,5 @@ { "serverAddress": "https://sponsor.ajay.app", - "serverAddressComment": "This specifies the default SponsorBlock server to conect to" + "serverAddressComment": "This specifies the default SponsorBlock server to conect to", + "categoryList": ["sponsor", "intro", "outro", "interaction", "merchandise"] } \ No newline at end of file From 6fa67088bcd350d749e735483dbb65a4cbf4681b Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 13:22:08 -0400 Subject: [PATCH 24/64] Removed old edit pane from popup and made it call the new one --- public/popup.html | 18 ++--------- src/content.ts | 9 +++--- src/popup.ts | 80 ++--------------------------------------------- 3 files changed, 8 insertions(+), 99 deletions(-) diff --git a/public/popup.html b/public/popup.html index 9132ec32de..aa8060a842 100644 --- a/public/popup.html +++ b/public/popup.html @@ -39,29 +39,15 @@

diff --git a/src/content.ts b/src/content.ts index 187bb264e7..51e4ea8e00 100644 --- a/src/content.ts +++ b/src/content.ts @@ -210,6 +210,10 @@ function messageListener(request: any, sender: any, sendResponse: (response: any case "changeStartSponsorButton": changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible); + break; + case "submitTimes": + submitSponsorTimes(); + break; } } @@ -1327,11 +1331,6 @@ function resetSponsorSubmissionNotice() { } function submitSponsorTimes() { - if (document.getElementById("submitButton").style.display == "none") { - //don't submit, not ready - return; - } - if (submissionNotice !== null) return; //it can't update to this info yet diff --git a/src/popup.ts b/src/popup.ts index 3503167e48..0bcbab0572 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -56,7 +56,6 @@ async function runThePopup(messageListener?: MessageListener) { "showNoticeAgain", "optionsButton", // More controls - "clearTimes", "submitTimes", "reportAnIssue", // sponsorTimesContributions @@ -82,9 +81,6 @@ async function runThePopup(messageListener?: MessageListener) { // discordButtons "discordButtonContainer", "hideDiscordButton", - // submitTimesInfoMessage - "submitTimesInfoMessageContainer", - "submitTimesInfoMessage", // Username "setUsernameContainer", "setUsernameButton", @@ -108,7 +104,6 @@ async function runThePopup(messageListener?: MessageListener) { PageElements.unwhitelistChannel.addEventListener("click", unwhitelistChannel); PageElements.disableSkipping.addEventListener("click", () => toggleSkipping(true)); PageElements.enableSkipping.addEventListener("click", () => toggleSkipping(false)); - PageElements.clearTimes.addEventListener("click", clearTimes); PageElements.submitTimes.addEventListener("click", submitTimes); PageElements.showNoticeAgain.addEventListener("click", showNoticeAgain); PageElements.setUsernameButton.addEventListener("click", setUsernameButton); @@ -263,8 +258,6 @@ async function runThePopup(messageListener?: MessageListener) { sponsorTimes = sponsorTimesStorage; - displaySponsorTimes(); - //show submission section PageElements.submissionSection.style.display = "unset"; @@ -363,26 +356,12 @@ async function runThePopup(messageListener?: MessageListener) { updateStartTimeChosen(); - //display video times on screen - displaySponsorTimes(); - //show submission section PageElements.submissionSection.style.display = "unset"; showSubmitTimesIfNecessary(); } - //display the video times from the array - function displaySponsorTimes() { - //remove all children - while (PageElements.sponsorMessageTimes.firstChild) { - PageElements.sponsorMessageTimes.removeChild(PageElements.sponsorMessageTimes.firstChild); - } - - //add sponsor times - PageElements.sponsorMessageTimes.appendChild(getSponsorTimesMessageDiv(sponsorTimes)); - } - //display the video times from the array at the top, in a different section function displayDownloadedSponsorTimes(request) { if (request.sponsorTimes != undefined) { @@ -692,8 +671,6 @@ async function runThePopup(messageListener?: MessageListener) { }); if (closeEditMode) { - displaySponsorTimes(); - showSubmitTimesIfNecessary(); } } @@ -721,9 +698,6 @@ async function runThePopup(messageListener?: MessageListener) { //save this Config.config.sponsorTimes.set(currentVideoID, sponsorTimes); - //update display - displaySponsorTimes(); - //if they are all removed if (sponsorTimes.length == 0) { //update chrome tab @@ -753,67 +727,17 @@ async function runThePopup(messageListener?: MessageListener) { }); } - function clearTimes() { - //send new sponsor time state to tab + function submitTimes() { if (sponsorTimes.length > 0) { - messageHandler.query({ - active: true, - currentWindow: true - }, function(tabs) { - messageHandler.sendMessage(tabs[0].id, { - message: "changeStartSponsorButton", - showStartSponsor: true, - uploadButtonVisible: false - }); - }); - } - - //reset sponsorTimes - sponsorTimes = []; - - Config.config.sponsorTimes.set(currentVideoID, sponsorTimes); messageHandler.query({ active: true, currentWindow: true }, tabs => { messageHandler.sendMessage( tabs[0].id, - {message: "sponsorDataChanged"} + {message: 'submitTimes'}, ); }); - - displaySponsorTimes(); - - //hide submission section - document.getElementById("submissionSection").style.display = "none"; - - resetStartTimeChosen(); - } - - function submitTimes() { - //make info message say loading - PageElements.submitTimesInfoMessage.innerText = chrome.i18n.getMessage("Loading"); - PageElements.submitTimesInfoMessageContainer.style.display = "unset"; - - if (sponsorTimes.length > 0) { - chrome.runtime.sendMessage({ - message: "submitTimes", - videoID: currentVideoID - }, function(response) { - if (response != undefined) { - if (response.statusCode == 200) { - //hide loading message - PageElements.submitTimesInfoMessageContainer.style.display = "none"; - - clearTimes(); - } else { - document.getElementById("submitTimesInfoMessage").innerText = utils.getErrorMessage(response.statusCode); - document.getElementById("submitTimesInfoMessageContainer").style.display = "unset"; - - PageElements.submitTimesInfoMessageContainer.style.display = "unset"; - } - } - }); } } From b6c243236bd8224b1828310eee7bec9136629970 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 14:38:33 -0400 Subject: [PATCH 25/64] Submission notice now saves on submission --- src/components/SubmissionNoticeComponent.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/SubmissionNoticeComponent.tsx b/src/components/SubmissionNoticeComponent.tsx index edb04b1cd5..791092f197 100644 --- a/src/components/SubmissionNoticeComponent.tsx +++ b/src/components/SubmissionNoticeComponent.tsx @@ -26,6 +26,7 @@ class SubmissionNoticeComponent extends React.Component any; noticeRef: React.MutableRefObject; + timeEditRefs: React.RefObject[]; constructor(props: SubmissionNoticeProps) { super(props); @@ -95,18 +96,24 @@ class SubmissionNoticeComponent extends React.Component(); + elements.push( + submissionNotice={this} + ref={timeRef}> - ) + ); + + this.timeEditRefs.push(timeRef); } return elements; @@ -134,6 +141,11 @@ class SubmissionNoticeComponent extends React.Component Date: Thu, 2 Apr 2020 21:26:13 -0400 Subject: [PATCH 26/64] Added basic category chooser UI --- public/_locales/en/messages.json | 9 +++ public/options/options.css | 23 +++++++ public/options/options.html | 7 +++ src/components/CategoryChooserComponent.tsx | 50 +++++++++++++++ .../CategorySkipOptionsComponent.tsx | 63 +++++++++++++++++++ src/options.ts | 4 ++ src/render/CategoryChooser.tsx | 15 +++++ 7 files changed, 171 insertions(+) create mode 100644 src/components/CategoryChooserComponent.tsx create mode 100644 src/components/CategorySkipOptionsComponent.tsx create mode 100644 src/render/CategoryChooser.tsx diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 6890095997..8beb64f16e 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -498,5 +498,14 @@ }, "category_merchandise": { "message": "Merchandise and self-promotion" + }, + "disable": { + "message": "Disable" + }, + "manualSkip": { + "message": "Manual Skip" + }, + "autoSkip": { + "message": "Auto Skip" } } diff --git a/public/options/options.css b/public/options/options.css index b80bf1169e..36db654e1e 100644 --- a/public/options/options.css +++ b/public/options/options.css @@ -323,4 +323,27 @@ svg { font-size: 14px; color: white; +} + +/* React styles */ + +.categoryTableElement { + font-size: 16px; + + color: white; +} + +.categoryTableElement > * { + padding-right: 15px; + padding-bottom: 15px; +} + +.categoryOptionsSelector { + background-color: #c00000; + color: white; + + border: none; + font-size: 14px; + padding: 5px; + border-radius: 5px; } \ No newline at end of file diff --git a/public/options/options.html b/public/options/options.html index 0dc3e4d8d5..658c370446 100644 --- a/public/options/options.html +++ b/public/options/options.html @@ -24,6 +24,13 @@

__MSG_Options__

+ {this.getSponsorTimeMessages()} +
+ + {/* Cancel Button */} + + + {/* Submit Button */} + +
+ {this.getCategorySkipOptions()} +
+ ); + } + + getCategorySkipOptions(): JSX.Element[] { + let elements: JSX.Element[] = []; + + for (const category of CompileConfig.categoryList) { + elements.push( + + + ); + } + + return elements; + } +} + +export default CategoryChooserComponent; \ No newline at end of file diff --git a/src/components/CategorySkipOptionsComponent.tsx b/src/components/CategorySkipOptionsComponent.tsx new file mode 100644 index 0000000000..74ad99db6f --- /dev/null +++ b/src/components/CategorySkipOptionsComponent.tsx @@ -0,0 +1,63 @@ +import * as React from "react"; +import Config from "../config" + +export interface CategorySkipOptionsProps { + category: string; + defaultColor: string; +} + +export interface CategorySkipOptionsState { + color: string; +} + +class CategorySkipOptionsComponent extends React.Component { + + constructor(props: CategorySkipOptionsProps) { + super(props); + + // Setup state + this.state = { + color: props.defaultColor + } + } + + render() { + return ( + + + {chrome.i18n.getMessage("category_" + this.props.category)} + + + + + + + {/* TODO: Add colour chooser */} + + ); + } + + /** + * @param optionNames List of option names as codes that will be sent to i18n + */ + getOptions(optionNames: string[]): JSX.Element[] { + let elements: JSX.Element[] = []; + + for (const optionName of optionNames) { + elements.push( + + ); + } + + return elements; + } +} + +export default CategorySkipOptionsComponent; \ No newline at end of file diff --git a/src/options.ts b/src/options.ts index 27d2a1f640..3fd1307417 100644 --- a/src/options.ts +++ b/src/options.ts @@ -5,6 +5,7 @@ import * as CompileConfig from "../config.json"; ( window).SB = Config; import Utils from "./utils"; +import CategoryChooser from "./render/CategoryChooser"; var utils = new Utils(); window.addEventListener('DOMContentLoaded', init); @@ -164,6 +165,9 @@ async function init() { }); break; + case "react-CategoryChooserComponent": + new CategoryChooser(optionsElements[i]); + break; } } diff --git a/src/render/CategoryChooser.tsx b/src/render/CategoryChooser.tsx new file mode 100644 index 0000000000..eab9edf6f3 --- /dev/null +++ b/src/render/CategoryChooser.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import CategoryChooserComponent from "../components/CategoryChooserComponent"; + +class CategoryChooser { + + constructor(element: Element) { + ReactDOM.render( + , + element + ); + } +} + +export default CategoryChooser; \ No newline at end of file From 3afde08a6e0fdbe55d6bc1216a3581d3c413e966 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 22:13:36 -0400 Subject: [PATCH 27/64] Category selections now save --- src/components/CategoryChooserComponent.tsx | 11 ++-- .../CategorySkipOptionsComponent.tsx | 58 ++++++++++++++++--- src/config.ts | 12 +++- src/types.ts | 7 ++- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/src/components/CategoryChooserComponent.tsx b/src/components/CategoryChooserComponent.tsx index 106ff271bf..3ec272fae8 100644 --- a/src/components/CategoryChooserComponent.tsx +++ b/src/components/CategoryChooserComponent.tsx @@ -26,9 +26,11 @@ class CategoryChooserComponent extends React.Component - {this.getCategorySkipOptions()} - + className="categoryChooserTable"> + + {this.getCategorySkipOptions()} + + ); } @@ -38,7 +40,8 @@ class CategoryChooserComponent extends React.Component + defaultColor={"00d400"} + key={category}> ); } diff --git a/src/components/CategorySkipOptionsComponent.tsx b/src/components/CategorySkipOptionsComponent.tsx index 74ad99db6f..e0604418b9 100644 --- a/src/components/CategorySkipOptionsComponent.tsx +++ b/src/components/CategorySkipOptionsComponent.tsx @@ -1,4 +1,5 @@ import * as React from "react"; + import Config from "../config" export interface CategorySkipOptionsProps { @@ -22,6 +23,14 @@ class CategorySkipOptionsComponent extends React.Component @@ -32,8 +41,10 @@ class CategorySkipOptionsComponent extends React.Component @@ -42,15 +53,48 @@ class CategorySkipOptionsComponent extends React.Component): void { + switch (event.target.value) { + case "disable": + this.removeCurrentCategorySelection(); + + break; + default: + this.removeCurrentCategorySelection(); + + Config.config.categorySelections.push({ + name: this.props.category, + autoSkip: event.target.value === "autoSkip" + }); + + // Forces the Proxy to send this to the chrome storage API + Config.config.categorySelections = Config.config.categorySelections; + } + } + + /** Removes this category from the config list of category selections */ + removeCurrentCategorySelection(): void { + // Remove it if it exists + for (let i = 0; i < Config.config.categorySelections.length; i++) { + if (Config.config.categorySelections[i].name === this.props.category) { + Config.config.categorySelections.splice(i, 1); + + // Forces the Proxy to send this to the chrome storage API + Config.config.categorySelections = Config.config.categorySelections; + + break; + } + } + } + + getCategorySkipOptions(): JSX.Element[] { let elements: JSX.Element[] = []; + let optionNames = ["disable", "manualSkip", "autoSkip"]; + for (const optionName of optionNames) { elements.push( - ); diff --git a/src/config.ts b/src/config.ts index 2a007dce4c..f11b735e22 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,5 @@ import * as CompileConfig from "../config.json"; +import { CategorySelection } from "./types"; interface SBConfig { userID: string, @@ -25,7 +26,10 @@ interface SBConfig { serverAddress: string, minDuration: number, checkForUnlistedVideos: boolean, - mobileUpdateShowCount: number + mobileUpdateShowCount: number, + + // What categories should be skipped + categorySelections: CategorySelection[] } interface SBObject { @@ -120,7 +124,11 @@ var Config: SBObject = { serverAddress: CompileConfig.serverAddress, minDuration: 0, checkForUnlistedVideos: false, - mobileUpdateShowCount: 0 + mobileUpdateShowCount: 0, + categorySelections: [{ + name: "sponsor", + autoSkip: true + }] }, localConfig: null, config: null, diff --git a/src/types.ts b/src/types.ts index 7008f2e18b..9f6649963e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,8 +26,13 @@ interface VideoDurationResponse { duration: number; } +interface CategorySelection { + name: string; + autoSkip: boolean; +} export { VideoDurationResponse, - ContentContainer + ContentContainer, + CategorySelection }; \ No newline at end of file From d4d5e4743e5d6f984f89c21a5d7f8899f93b6d3e Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 2 Apr 2020 22:14:52 -0400 Subject: [PATCH 28/64] Added key to sponsorTimeEditComponent --- src/components/SponsorTimeEditComponent.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index ba24089016..8000c6d16b 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -185,7 +185,8 @@ class SponsorTimeEditComponent extends React.Component + ); From 36981af95ad902bf61737775a50b6f9a1aadec51 Mon Sep 17 00:00:00 2001 From: Joe-Dowd Date: Sat, 4 Apr 2020 13:59:04 +0100 Subject: [PATCH 29/64] Added audio notification on skip to options menu --- manifest/manifest.json | 1 + public/_locales/en/messages.json | 6 ++++++ public/icons/beep.ogg | Bin 0 -> 4706 bytes public/options/options.html | 19 +++++++++++++++++++ src/components/SkipNoticeComponent.tsx | 12 ++++++++++++ src/config.ts | 2 ++ src/options.ts | 4 ++++ 7 files changed, 44 insertions(+) create mode 100644 public/icons/beep.ogg diff --git a/manifest/manifest.json b/manifest/manifest.json index fcfd4bc0c2..b02fe4ca90 100644 --- a/manifest/manifest.json +++ b/manifest/manifest.json @@ -32,6 +32,7 @@ "icons/downvote.png", "icons/report.png", "icons/close.png", + "icons/beep.ogg", "icons/PlayerInfoIconSponsorBlocker256px.png", "icons/PlayerDeleteIconSponsorBlocker256px.png", "popup.html", diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 8beb64f16e..86f2688fcb 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -291,6 +291,12 @@ "autoSkipDescription": { "message": "Auto skip will skip sponsors for you. If disabled, a notice will appear asking if you'd like to skip." }, + "audioNotification": { + "message": "Audio Notification On Skip" + }, + "audioNotificationDescription": { + "message": "Audio notification on skip will play a sound whenever a sponsor is skipped. If disabled (or auto skip is disabled), no sound will be played." + }, "youHaveSkipped": { "message": "You have skipped " }, diff --git a/public/icons/beep.ogg b/public/icons/beep.ogg new file mode 100644 index 0000000000000000000000000000000000000000..37f92fe44f43dcbeb650a545a7f733dd530eb612 GIT binary patch literal 4706 zcmc&XYgm(4nkRtraWz2DfWamhB;n$dAXA zn8pwhFi)ek@_)O*s~qOlCvEP?Jy}rn7n07vSRz?J7zkZ7#|dv zcpN&yHm#TTU{c_eVqT*Lid}&UfTm`K{9A@2(Y@ami~vC77LcOOkaqV`#&6Lb5Qnri z&=>%Lbo>e(U#?G89+Wh0InlzXZ}GX%FB$9i8}DDfwiRdR0}!7;8q6nI<9uQOko^pK zYmoA3s#>4cXf3PgvH&FjSV21bs6JBcEBf^7km;3w?B;E$0DzMWG1>B+3lN&STUZ0? zoMF43M{x@C;7x@Y^kt8juH{L}F1*i9qR5h4d&jeN^oiT^%z1Io4zEgvYujf0dj!|6|_of6V*ltE_K+ z%)0+oR%T7sgMqxvxy;P@qkrFV)k~~EiSjA5I_!LtQ)X>7-w-PtK`Gjw(ys&AA0-`%2_b^!nz z06c~ZC{YEJ;Q~x6+`?2#Km{Nyff7;ZH>?ia4RxFipMH~(u;Xar-n@5CfFxKOmWIGS z3QYll>X7K!z}Ww1#|&!$VDQymyd!)Wac+vk@SocsFjQMzb83{#8;hRsN*p1t@o!hq z!t7fYc*80-UnpRT5n4{)U`p^XbuK+O#-JfX=Q)9J0w9ytsamaP73)SCN<7 z=v^P5+2M0|<0Xexi7>aVB)Rt3&X>R7)$E#1Oz!Z>*wAmEw)P#q#QOw>y}+xXjW?PM zTaz|)+TE@2vwVj)xpM2s|E?S4rw+(W(9&s5o(wX0w-5O_K*&wK{1WqFly?1{bJ!2cZq=h z!$iVpYU}Lu2^?PuPawr6CMUZ>%9b1$Vx2v9kTM}KHaR(Yz8tb+l-GLvEHUP!tWW) zJlA=mQPSDDJQgtT`j1xO0`SpEOAue`aAC8Sbb8Ht_kL$AsZ)_qKC@hf+S2qSo`4B` z1?;g9u8m)dJ5L8AVTiS;l{yQmh(dcF({M3~c9Sea(L>!51sl=p?xfF>MMP9$7-&OH zIyhBK4orpe4Flx!)omIzn#+!4#xlM1b3z4ruO3c^-1Tob`Wj)^b^%kbfVR%npaQpj zr~2kB0MVTSjE;v>Js#_F{Ca0pX90H;%+?BM=pnK!9u87RUI$5}fc6w)uUHuoUSH`{ zDB>oX;Fzc~NLMQ*@`ki<3bX1IdyxW@wh3cHXpqetfDSx9BhO6QM4mJUD7-C0j6t$! zDwLr|$2dqsS-e2t%2S3ur(lXUV$6EoZFEHoMKho(^|>^7W#PC`IP)8Y z3L0>A@u^M|Y(_N8P(d{FD9#ZNEe{X-9nJyw6+r)xFi|)HYR1$=;GY7U2l!|@L8^IBW;NXQVt|IV_G^o$&6sJzYI3OK9zLRHWUX_P! z1i@800G{LitQ6Sw%_@99F*=poyTmusd@KPNH~*^&9D2fiZn|!@3JcQ zpGX4s7gbp9e^o$Z`#?~LtPqJ)(tnc5)<>bM+&gG zAfj@^khToF6~VUMHV+qbLc6?wq!G9q&qt00y?Zv}cz!EyK5=eBsdK_O}mVb<}Yuy?emaSd7I| zQjS+!M)A6Thj)({d^sie<*v7zu)y25&%nI=NV@I=EIB9@qJ&Ch0l>O}Ju$Y& zvT9QDNbet2Z}puKKOZZjGrk0{e?E{Fi2wC+qT`NT z0Rf!9{9+NbEpSW9*H+EDW`6&QBKwj1Z-d+FDVgFTyR#LC@Dhd#z-V~zv!Yr>OAvF- zvHpVh{ie3c9pp`c;2z^z@5@iW`+m#h&by~u?3Vv(czERY^=g0lu96x0YBfap`w{UPw?N+!E%E2&J#3itv%BnMx7`QCxzk?|Me_bVK`|0il;)9ZkpcV7g6W}5lH zaAY*TywpQ2S?T%ox<}(roa-;&d-X21^7swZr%0upas(q_wBIyyQS;m>IVRwnQvi4-{s_Ei=6I9E(Ag?F{N zT$nu|4XRG@Y=~(~46Rk_jO?NPEtV`5?VLe(Dt`*Q-3^P?pl$%T3C9=l;Nl?s9 z`pNJnR{XtDqEmZxL@lGa2$750E%H5WQ5wVTV@YXZsETE^#EM(Xi1QVYqnN{^M)|DV zxtZcsSzTHtR)>3PTx`^%#?XLhPbZ%kI)BSEs@u*ph-;gtUc})K#YLpl$~DRem9jzJ z#d2M$^i%Z}>cy;lfd+jpAHyXRw zZ?uiFa^m zK|f8+vp!vjoj&X8?y+sI__MSG_Options__

+ + +
+ + +
+
+ +
__MSG_audioNotificationDescription__
+
+ +
+
+
diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index a366af7a02..fd2e562381 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -32,6 +32,7 @@ class SkipNoticeComponent extends React.Component + + {(Config.config.audioNotificationOnSkip) && } {/* Text Boxes */} {this.getMessageBoxes()} diff --git a/src/config.ts b/src/config.ts index f11b735e22..3387f4a10d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -25,6 +25,7 @@ interface SBConfig { supportInvidious: boolean, serverAddress: string, minDuration: number, + audioNotificationOnSkip, checkForUnlistedVideos: boolean, mobileUpdateShowCount: number, @@ -123,6 +124,7 @@ var Config: SBObject = { supportInvidious: false, serverAddress: CompileConfig.serverAddress, minDuration: 0, + audioNotificationOnSkip: false, checkForUnlistedVideos: false, mobileUpdateShowCount: 0, categorySelections: [{ diff --git a/src/options.ts b/src/options.ts index 3fd1307417..24fd833da4 100644 --- a/src/options.ts +++ b/src/options.ts @@ -65,6 +65,10 @@ async function init() { showNoticeSwitch.checked = true; } + break; + case "audioNotificationOnSkip": + let audioNotificationOnSkip = document.querySelector("[sync-option='audioNotificationOnSkip'] > label > label > input"); + audioNotificationOnSkip.checked = Config.config[option]; break; } }); From d7a7476cd14b574c0c9de21a00b25b3540eb4b5c Mon Sep 17 00:00:00 2001 From: Joe-Dowd Date: Sat, 4 Apr 2020 14:01:31 +0100 Subject: [PATCH 30/64] fixed tabbing --- src/components/SkipNoticeComponent.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index fd2e562381..bf8db067dc 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -104,10 +104,10 @@ class SkipNoticeComponent extends React.Component - + {(Config.config.audioNotificationOnSkip) && } + + } {/* Text Boxes */} {this.getMessageBoxes()} From 59c64552982be21ccf9aed5c4b05910b3c397ec2 Mon Sep 17 00:00:00 2001 From: Joe-Dowd Date: Sat, 4 Apr 2020 14:13:27 +0100 Subject: [PATCH 31/64] removed duplicate locale message --- public/_locales/en/messages.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 86f2688fcb..4aba475596 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -510,8 +510,5 @@ }, "manualSkip": { "message": "Manual Skip" - }, - "autoSkip": { - "message": "Auto Skip" } } From ec9f1efd55f262629fea222354c01e92cd6ac09a Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 12:58:02 -0400 Subject: [PATCH 32/64] Added category skip option to just show an overlay without skipping --- public/_locales/en/messages.json | 4 +- .../CategorySkipOptionsComponent.tsx | 47 ++++++++++++++----- src/config.ts | 4 +- src/types.ts | 9 +++- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 8beb64f16e..cc008f023a 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -505,7 +505,7 @@ "manualSkip": { "message": "Manual Skip" }, - "autoSkip": { - "message": "Auto Skip" + "showOverlay": { + "message": "Show Overlay On Player" } } diff --git a/src/components/CategorySkipOptionsComponent.tsx b/src/components/CategorySkipOptionsComponent.tsx index e0604418b9..58301d7b95 100644 --- a/src/components/CategorySkipOptionsComponent.tsx +++ b/src/components/CategorySkipOptionsComponent.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import Config from "../config" +import { CategorySkipOption } from "../types"; export interface CategorySkipOptionsProps { category: string; @@ -27,7 +28,17 @@ class CategorySkipOptionsComponent extends React.Component): void { + let option: CategorySkipOption; + + this.removeCurrentCategorySelection(); + switch (event.target.value) { case "disable": - this.removeCurrentCategorySelection(); + return; + case "showOverlay": + option = CategorySkipOption.ShowOverlay; break; - default: - this.removeCurrentCategorySelection(); + case "manualSkip": + option = CategorySkipOption.ManualSkip; - Config.config.categorySelections.push({ - name: this.props.category, - autoSkip: event.target.value === "autoSkip" - }); + break; + case "autoSkip": + option = CategorySkipOption.AutoSkip; - // Forces the Proxy to send this to the chrome storage API - Config.config.categorySelections = Config.config.categorySelections; + break; } + + Config.config.categorySelections.push({ + name: this.props.category, + option: option + }); + + // Forces the Proxy to send this to the chrome storage API + Config.config.categorySelections = Config.config.categorySelections; } /** Removes this category from the config list of category selections */ @@ -89,8 +112,8 @@ class CategorySkipOptionsComponent extends React.Component Date: Sat, 4 Apr 2020 21:04:17 -0400 Subject: [PATCH 33/64] Switched skipping to use category settings. Submission editing is now broken as well as clicking submit. Skipping through multiple submissions just treats it as skipping from one (no multiple vote options). --- src/components/SkipNoticeComponent.tsx | 14 +- src/components/SponsorTimeEditComponent.tsx | 17 +- src/config.ts | 2 - src/content.ts | 271 ++++++++++++-------- src/js-components/previewBar.ts | 2 +- src/popup.ts | 15 +- src/render/SkipNotice.tsx | 8 +- src/types.ts | 17 +- src/utils.ts | 23 ++ 9 files changed, 226 insertions(+), 143 deletions(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index a366af7a02..0b06858dd2 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -7,7 +7,7 @@ import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; export interface SkipNoticeProps { UUID: string; - manualSkip: boolean; + autoSkip: boolean; // Contains functions and variables from the content script needed by the skip notice contentContainer: ContentContainer; } @@ -27,7 +27,7 @@ export interface SkipNoticeState { class SkipNoticeComponent extends React.Component { UUID: string; - manualSkip: boolean; + autoSkip: boolean; // Contains functions and variables from the content script needed by the skip notice contentContainer: ContentContainer; @@ -42,12 +42,12 @@ class SkipNoticeComponent extends React.Component {/* Never show button if manualSkip is disabled */} - {this.manualSkip ? "" : + {!this.autoSkip ? "" :
); } @@ -147,7 +151,10 @@ class SponsorTimeEditComponent extends React.Component + className="sponsorTimeCategories" + defaultValue={sponsorTime.category} + ref={this.categoryOptionRef} + onChange={this.saveEditTimes.bind(this)}> {this.getCategoryOptions()} @@ -161,7 +168,7 @@ class SponsorTimeEditComponent extends React.Component - {(!isNaN(sponsorTime[1])) ? ( + {(!isNaN(segment[1])) ? ( @@ -169,7 +176,7 @@ class SponsorTimeEditComponent extends React.Component ): ""} - {(!isNaN(sponsorTime[1])) ? ( + {(!isNaN(segment[1])) ? ( @@ -198,7 +205,7 @@ class SponsorTimeEditComponent extends React.Component previewBar !== null).then((result) => previewBar.set(allSegments, types, video.duration)); + utils.wait(() => previewBar !== null).then((result) => previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)); //update last video id lastPreviewBarUpdate = sponsorVideoID; @@ -1287,7 +1281,7 @@ function clearSponsorTimes() { let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID); if (sponsorTimes != undefined && sponsorTimes.length > 0) { - let confirmMessage = chrome.i18n.getMessage("clearThis") + getSponsorTimesMessage(sponsorTimes) + let confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes) + "\n" + chrome.i18n.getMessage("confirmMSG") if(!confirm(confirmMessage)) return; @@ -1395,26 +1389,23 @@ function submitSponsorTimes() { let currentVideoID = sponsorVideoID; - let sponsorTimes = Config.config.sponsorTimes.get(currentVideoID); - - if (sponsorTimes != undefined && sponsorTimes.length > 0) { + if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) { //check if a sponsor exceeds the duration of the video - for (let i = 0; i < sponsorTimes.length; i++) { - if (sponsorTimes[i][1] > video.duration) { - sponsorTimes[i][1] = video.duration; + for (let i = 0; i < sponsorTimesSubmitting.length; i++) { + if (sponsorTimesSubmitting[i].segment[1] > video.duration) { + sponsorTimesSubmitting[i].segment[1] = video.duration; } } - //update sponsorTimes - Config.config.sponsorTimes.set(currentVideoID, sponsorTimes); - //update sponsorTimesSubmitting - sponsorTimesSubmitting = sponsorTimes; + //update sponsorTimes + Config.config.sponsorTimes.set(currentVideoID, utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting)); // Check to see if any of the submissions are below the minimum duration set if (Config.config.minDuration > 0) { - for (let i = 0; i < sponsorTimes.length; i++) { - if (sponsorTimes[i][1] - sponsorTimes[i][0] < Config.config.minDuration) { - let confirmShort = chrome.i18n.getMessage("shortCheck") + "\n\n" + getSponsorTimesMessage(sponsorTimes); + for (let i = 0; i < sponsorTimesSubmitting.length; i++) { + if (sponsorTimesSubmitting[i].segment[1] - sponsorTimesSubmitting[i].segment[0] < Config.config.minDuration) { + let confirmShort = chrome.i18n.getMessage("shortCheck") + "\n\n" + + getSegmentsMessage(utils.getSegmentsFromSponsorTimes(sponsorTimesSubmitting)); if(!confirm(confirmShort)) return; } @@ -1480,12 +1471,12 @@ function sendSubmitMessage(){ } //get the message that visually displays the video times -function getSponsorTimesMessage(sponsorTimes) { +function getSegmentsMessage(segments: number[][]): string { let sponsorTimesMessage = ""; - for (let i = 0; i < sponsorTimes.length; i++) { - for (let s = 0; s < sponsorTimes[i].length; s++) { - let timeMessage = utils.getFormattedTime(sponsorTimes[i][s]); + for (let i = 0; i < segments.length; i++) { + for (let s = 0; s < segments[i].length; s++) { + let timeMessage = utils.getFormattedTime(segments[i][s]); //if this is an end time if (s == 1) { timeMessage = " to " + timeMessage; diff --git a/src/utils.ts b/src/utils.ts index 3053ce70c9..974b62b6c1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -155,6 +155,20 @@ class Utils { }); } + /** + * Gets just the timestamps from a sponsorTimes array + * + * @param sponsorTimes + */ + getSegmentsFromSponsorTimes(sponsorTimes: SponsorTime[]): number[][] { + let segments: number[][] = []; + for (const sponsorTime of sponsorTimes) { + segments.push(sponsorTime.segment); + } + + return segments; + } + getSponsorIndexFromUUID(sponsorTimes: SponsorTime[], UUID: string): number { for (let i = 0; i < sponsorTimes.length; i++) { if (sponsorTimes[i].UUID === UUID) { From 37e2fb0972377731a30d594bad262cc17079340b Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 22:11:39 -0400 Subject: [PATCH 36/64] Fixed react whitespace error --- src/components/NoticeComponent.tsx | 80 +++++++++++++++--------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index cde3db6024..7e8bbf6126 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -67,50 +67,52 @@ class NoticeComponent extends React.Component { className={"sponsorSkipObject sponsorSkipNotice" + (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")} style={noticeStyle} onMouseEnter={this.pauseCountdown.bind(this)} - onMouseLeave={this.startCountdown.bind(this)}> - - {/* First row */} - - {/* Left column */} - - {/* Logo */} - - - - - - {this.state.noticeTitle} - - + onMouseLeave={this.startCountdown.bind(this)}> + + + {/* First row */} + + {/* Left column */} + + {/* Logo */} + + + + + + {this.state.noticeTitle} + + - {/* Right column */} - + {/* Right column */} + + + {/* Time left */} + {this.props.timed ? ( + + + {this.state.countdownText || (this.state.countdownTime + "s")} + + ) : ""} - {/* Time left */} - {this.props.timed ? ( - - - {this.state.countdownText || (this.state.countdownTime + "s")} - - ) : ""} - - {/* Close button */} - this.close()}> - - - + {/* Close button */} + this.close()}> + + + - {this.props.children} + {this.props.children} - + + ); } From ebd6c9c95219cb980b3d440844da72a1a9c90a4c Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 22:12:54 -0400 Subject: [PATCH 37/64] Fixed error when preview bar updates --- src/content.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content.ts b/src/content.ts index ade2655892..606d68af08 100644 --- a/src/content.ts +++ b/src/content.ts @@ -824,7 +824,8 @@ function updatePreviewBar() { types.push("preview-" + sponsorTimesSubmitting[i].category); } - utils.wait(() => previewBar !== null).then((result) => previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)); + utils.wait(() => previewBar !== null && video !== null) + .then((result) => previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)); //update last video id lastPreviewBarUpdate = sponsorVideoID; From 8134b5a67e96bbc4168043adaa8f645e3043bdb6 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 22:17:11 -0400 Subject: [PATCH 38/64] Added missing category to example config --- config.json.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json.example b/config.json.example index e2a2f44b43..90698dd91b 100644 --- a/config.json.example +++ b/config.json.example @@ -1,5 +1,5 @@ { "serverAddress": "https://sponsor.ajay.app", "serverAddressComment": "This specifies the default SponsorBlock server to conect to", - "categoryList": ["sponsor", "intro", "outro", "interaction", "merchandise"] -} \ No newline at end of file + "categoryList": ["sponsor", "intro", "outro", "interaction", "merchandise", "offtopic"] +} From 09f53c80f066ad94525a94a6616046f687d54cb3 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 22:22:37 -0400 Subject: [PATCH 39/64] Sync volume with video volume --- src/components/SkipNoticeComponent.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index bf8db067dc..278d619463 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -32,7 +32,7 @@ class SkipNoticeComponent extends React.Component Date: Sat, 4 Apr 2020 22:25:10 -0400 Subject: [PATCH 40/64] Removed custom options code for audio --- src/options.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/options.ts b/src/options.ts index 24fd833da4..3fd1307417 100644 --- a/src/options.ts +++ b/src/options.ts @@ -65,10 +65,6 @@ async function init() { showNoticeSwitch.checked = true; } - break; - case "audioNotificationOnSkip": - let audioNotificationOnSkip = document.querySelector("[sync-option='audioNotificationOnSkip'] > label > label > input"); - audioNotificationOnSkip.checked = Config.config[option]; break; } }); From 2a432490bcedc20de0809e58d8ff3975bb9c2b71 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 23:26:09 -0400 Subject: [PATCH 41/64] Moved audio setting --- public/options/options.html | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/public/options/options.html b/public/options/options.html index 1b423d2637..92cba82062 100644 --- a/public/options/options.html +++ b/public/options/options.html @@ -100,26 +100,6 @@

__MSG_Options__



- - -
- - -
-
- -
__MSG_audioNotificationDescription__
-
- -
-
- -
@@ -254,6 +234,23 @@

__MSG_Options__

__MSG_whatUploadButton__
+
+
+ +
+ + +
+
+ +
__MSG_audioNotificationDescription__
+
+

From 55e17ceb608cc04f91a420cbb94c8df80a1bdd0f Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 4 Apr 2020 23:26:34 -0400 Subject: [PATCH 42/64] Fixed issues with manual skipping --- src/components/NoticeComponent.tsx | 5 +++- src/components/SkipNoticeComponent.tsx | 36 ++++++++++++++++---------- src/content.ts | 7 +++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/components/NoticeComponent.tsx b/src/components/NoticeComponent.tsx index 7e8bbf6126..97b1040dde 100644 --- a/src/components/NoticeComponent.tsx +++ b/src/components/NoticeComponent.tsx @@ -32,7 +32,10 @@ class NoticeComponent extends React.Component { constructor(props: NoticeProps) { super(props); - let maxCountdownTime = props.maxCountdownTime || (() => 4); + let maxCountdownTime = () => { + if (this.props.maxCountdownTime) return this.props.maxCountdownTime(); + else return 4; + }; //the id for the setInterval running the countdown this.countdownInterval = null; diff --git a/src/components/SkipNoticeComponent.tsx b/src/components/SkipNoticeComponent.tsx index 3cf3831f67..07572de64b 100644 --- a/src/components/SkipNoticeComponent.tsx +++ b/src/components/SkipNoticeComponent.tsx @@ -2,9 +2,13 @@ import * as React from "react"; import Config from "../config" import { ContentContainer } from "../types"; +import Utils from "../utils"; +var utils = new Utils(); + import NoticeComponent from "./NoticeComponent"; import NoticeTextSelectionComponent from "./NoticeTextSectionComponent"; + export interface SkipNoticeProps { UUID: string; autoSkip: boolean; @@ -79,6 +83,10 @@ class SkipNoticeComponent extends React.Component - {/* Never show button if manualSkip is disabled */} + {/* Never show button if autoSkip is enabled */} {!this.autoSkip ? "" :
-
-
- -
- - -
-
- -
__MSG_autoSkipDescription__
-
-

diff --git a/src/config.ts b/src/config.ts index cc403e1344..a28d834fa9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -233,11 +233,14 @@ function fetchConfig() { }); } -function migrateOldFormats() { // Convert sponsorTimes format - for (const key in Config.localConfig) { - if (key.startsWith("sponsorTimes") && key !== "sponsorTimes" && key !== "sponsorTimesContributed") { - Config.config.sponsorTimes.set(key.substr(12), Config.config[key]); - delete Config.config[key]; +function migrateOldFormats() { + if (Config.config["disableAutoSkip"]) { + for (const selection of Config.config.categorySelections) { + if (selection.name === "sponsor") { + selection.option = CategorySkipOption.ManualSkip; + + chrome.storage.sync.remove("disableAutoSkip"); + } } } } diff --git a/src/content.ts b/src/content.ts index a8c0ad4cba..e40bd40fef 100644 --- a/src/content.ts +++ b/src/content.ts @@ -34,7 +34,7 @@ var seekListenerSetUp = false var hiddenSponsorTimes: number[] = []; /** @type {Array[boolean]} Has the sponsor been skipped */ -var sponsorSkipped = []; +var sponsorSkipped: boolean[] = []; //the video var video: HTMLVideoElement; From 963fb5832134fc0ca564199b5afc7ce2e2758bcc Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 6 Apr 2020 00:45:28 -0400 Subject: [PATCH 49/64] Fixed endIndex not being used while skipping and made end index finding function recursive --- src/content.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/content.ts b/src/content.ts index e40bd40fef..5aa62c6d4e 100644 --- a/src/content.ts +++ b/src/content.ts @@ -485,7 +485,7 @@ function startSponsorSchedule(currentTime?: number): void { // TODO: Remove this bug catching if statement when the bug is found let currentVideoID = getYouTubeVideoID(document.URL); if (currentVideoID == sponsorVideoID) { - skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice); + skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice); // TODO: Know the autoSkip settings for ALL items being skipped if (utils.getCategorySelection(currentSkip.category)) { @@ -911,6 +911,11 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH } } + // Keep going if required + if (latestEndTimeIndex !== index) { + latestEndTimeIndex = getLatestEndTimeIndex(sponsorTimes, latestEndTimeIndex, hideHiddenSponsors); + } + return latestEndTimeIndex; } From 85c1a45c8b5273ec0f5773c102fa89781ae49aef Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 6 Apr 2020 01:19:17 -0400 Subject: [PATCH 50/64] Improved skipping over multiple segments --- src/content.ts | 52 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/content.ts b/src/content.ts index 5aa62c6d4e..8bad7bd2bf 100644 --- a/src/content.ts +++ b/src/content.ts @@ -456,7 +456,7 @@ function cancelSponsorSchedule(): void { * * @param currentTime Optional if you don't want to use the actual current time */ -function startSponsorSchedule(currentTime?: number): void { +function startSponsorSchedule(includeIntersectingSegments: boolean = false, currentTime?: number): void { cancelSponsorSchedule(); if (video.paused) return; @@ -466,12 +466,12 @@ function startSponsorSchedule(currentTime?: number): void { if (currentTime === undefined || currentTime === null) currentTime = video.currentTime; - let skipInfo = getNextSkipIndex(currentTime); + let skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments); if (skipInfo.index === -1) return; let currentSkip = skipInfo.array[skipInfo.index]; - let skipTime = currentSkip.segment; + let skipTime: number[] = [currentSkip.segment[0], skipInfo.array[skipInfo.endIndex].segment[1]]; let timeUntilSponsor = skipTime[0] - currentTime; // Don't skip if this category should not be skipped @@ -479,6 +479,7 @@ function startSponsorSchedule(currentTime?: number): void { let skippingFunction = () => { let forcedSkipTime: number = null; + let forcedIncludeIntersectingSegments = false; if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) { // Double check that the videoID is correct @@ -488,10 +489,11 @@ function startSponsorSchedule(currentTime?: number): void { skipToTime(video, skipInfo.endIndex, skipInfo.array, skipInfo.openNotice); // TODO: Know the autoSkip settings for ALL items being skipped - if (utils.getCategorySelection(currentSkip.category)) { + if (utils.getCategorySelection(currentSkip.category).option === CategorySkipOption.ManualSkip) { forcedSkipTime = skipTime[0] + 0.001; } else { forcedSkipTime = skipTime[1]; + forcedIncludeIntersectingSegments = true; } } else { // Something has really gone wrong @@ -503,7 +505,7 @@ function startSponsorSchedule(currentTime?: number): void { } } - startSponsorSchedule(forcedSkipTime); + startSponsorSchedule(forcedIncludeIntersectingSegments, forcedSkipTime); }; if (timeUntilSponsor <= 0) { @@ -652,7 +654,7 @@ function sponsorsLookup(id: string, channelIDPromise?) { } if (startingSponsor !== -1) { - startSponsorSchedule(startingSponsor); + startSponsorSchedule(false, startingSponsor); } else { startSponsorSchedule(); } @@ -847,15 +849,17 @@ function whitelistCheck() { /** * Returns info about the next upcoming sponsor skip */ -function getNextSkipIndex(currentTime: number): {array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} { - let sponsorStartTimes = getStartTimes(sponsorTimes); - let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true); +function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean): + {array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} { + + let sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments); + let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, currentTime, true); let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime)); let endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex); - let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting); - let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false); + let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments); + let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, currentTime, false); let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime)); let previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minPreviewSponsorTimeIndex); @@ -905,7 +909,7 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i)) - && utils.getCategorySelection(sponsorTimes[index].category).option === CategorySkipOption.AutoSkip) { + && utils.getCategorySelection(sponsorTimes[i].category).option === CategorySkipOption.AutoSkip) { // Overlapping segment latestEndTimeIndex = i; } @@ -926,14 +930,18 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH * @param sponsorTimes * @param minimum * @param hideHiddenSponsors + * @param includeIntersectingSegments If true, it will include segments that start before + * the current time, but end after */ -function getStartTimes(sponsorTimes: SponsorTime[], minimum?: number, hideHiddenSponsors: boolean = false): number[] { +function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, minimum?: number, + hideHiddenSponsors: boolean = false): number[] { if (sponsorTimes === null) return []; let startTimes: number[] = []; for (let i = 0; i < sponsorTimes.length; i++) { - if ((minimum === undefined || sponsorTimes[i].segment[0] >= minimum) && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) { + if ((minimum === undefined || (sponsorTimes[i].segment[0] >= minimum || (includeIntersectingSegments && sponsorTimes[i].segment[1] > minimum))) + && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) { startTimes.push(sponsorTimes[i].segment[0]); } } @@ -1003,16 +1011,30 @@ function unskipSponsorTime(UUID) { if (sponsorTimes != null) { //add a tiny bit of time to make sure it is not skipped again video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[0] + 0.001; + + checkIfInsideSegment(); } } function reskipSponsorTime(UUID) { if (sponsorTimes != null) { - //add a tiny bit of time to make sure it is not skipped again video.currentTime = utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1]; + + // See if any skips need to be done if this is inside of another segment + startSponsorSchedule(true, utils.getSponsorTimeFromUUID(sponsorTimes, UUID).segment[1]); } } +/** + * Checks if currently inside a segment and will trigger + * a skip schedule if true. + * + * This is used for when a manual skip is finished or a reskip is complete + */ +function checkIfInsideSegment() { + // for +} + function createButton(baseID, title, callback, imageName, isDraggable=false): boolean { if (document.getElementById(baseID + "Button") != null) return false; From 9f87c839b5435e8b060c6154913db46411926f0d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 6 Apr 2020 21:58:42 -0400 Subject: [PATCH 51/64] Fixed preview bar sometimes not appearing --- src/content.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/content.ts b/src/content.ts index 8bad7bd2bf..237e0aa564 100644 --- a/src/content.ts +++ b/src/content.ts @@ -810,6 +810,8 @@ function updatePreviewBarPositionMobile(parent: Element) { } function updatePreviewBar() { + if (previewBar === null || video === null) return; + let localSponsorTimes = sponsorTimes; if (localSponsorTimes == null) localSponsorTimes = []; @@ -829,8 +831,7 @@ function updatePreviewBar() { types.push("preview-" + sponsorTimesSubmitting[i].category); } - utils.wait(() => previewBar !== null && video !== null) - .then((result) => previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration)); + previewBar.set(utils.getSegmentsFromSponsorTimes(allSponsorTimes), types, video.duration) //update last video id lastPreviewBarUpdate = sponsorVideoID; From 6abf6a0044a3c7e9c4ccd7e94dc34ef7eb3f8d5d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Thu, 9 Apr 2020 00:40:11 -0400 Subject: [PATCH 52/64] Added testing server option. --- public/_locales/en/messages.json | 9 +++++++++ public/options/options.html | 16 ++++++++++++++++ src/config.ts | 3 +++ src/options.ts | 8 ++++++++ 4 files changed, 36 insertions(+) diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 5809054f7e..d05dcfc62c 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -516,5 +516,14 @@ }, "showOverlay": { "message": "Show Overlay On Player" + }, + "enableTestingServer": { + "message": "Enable Beta Testing Server" + }, + "whatEnableTestingServer": { + "message": "Your submissions and votes WILL NOT COUNT towards the main server. Only use this for testing." + }, + "testingServerWarning": { + "message": "All submissions and votes WILL NOT COUNT towards the main server while connecting to the test server. Make sure to disable this when you want to make real submissions." } } diff --git a/public/options/options.html b/public/options/options.html index a4530a027a..0a93ad224a 100644 --- a/public/options/options.html +++ b/public/options/options.html @@ -352,7 +352,23 @@

__MSG_Options__



+ +
+ + +
+
+ +
__MSG_whatEnableTestingServer__
+
+
+