From e216a98f74350fafe5c6b8cecbb4dcb7a30ae5d6 Mon Sep 17 00:00:00 2001 From: Aleksey Bogdanov Date: Thu, 9 Feb 2023 12:46:10 +0200 Subject: [PATCH] FIX: stop youtube autoplay on scrollups (#19951) When a user pauses a youtube video and scrolls up high enough to load new posts, the video either rewinds or restarts depending on the browser. The problem is solved by patching virtual-dom to handle element prepends without reordering old elements. Long-term, Discourse intends to move away from the vdom/widget implementation, so this is intended as a short-term solution. More context at https://meta.discourse.org/t/57692 Co-authored-by: David Taylor --- .../javascripts/discourse/ember-cli-build.js | 3 + app/assets/javascripts/discourse/package.json | 2 +- .../components/widgets/widget-test.js | 72 +++++++++++++++++++ app/assets/javascripts/yarn.lock | 28 ++++---- 4 files changed, 90 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index 57349327ea0..336efc808ca 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -56,6 +56,9 @@ module.exports = function (defaults) { enabled: true, }, autoImport: { + alias: { + "virtual-dom": "@discourse/virtual-dom", + }, forbidEval: true, insertScriptsAt: "ember-auto-import-scripts", webpack: { diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index 280007c0ccf..452c08a0c41 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -94,7 +94,7 @@ "terser": "^5.16.3", "tippy.js": "^6.3.7", "util": "^0.12.5", - "virtual-dom": "^2.1.1", + "@discourse/virtual-dom": "^2.1.2-0", "webpack": "^5.75.0", "wizard": "1.0.0", "xss": "^1.0.14" diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/widget-test.js b/app/assets/javascripts/discourse/tests/integration/components/widgets/widget-test.js index f5406662703..04cf9f31959 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/widgets/widget-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/widgets/widget-test.js @@ -9,6 +9,7 @@ import { Promise } from "rsvp"; import { createWidget } from "discourse/widgets/widget"; import { next } from "@ember/runloop"; import { withPluginApi } from "discourse/lib/plugin-api"; +import { h } from "virtual-dom"; module("Integration | Component | Widget | base", function (hooks) { setupRenderingTest(hooks); @@ -394,4 +395,75 @@ module("Integration | Component | Widget | base", function (hooks) { "renders container with overridden tagName" ); }); + + test("avoids rerendering on prepend", async function (assert) { + createWidget("prepend-test", { + tagName: "div.test", + html(attrs) { + const result = []; + result.push( + this.attach("button", { + label: "rerender", + className: "rerender", + action: "dummyAction", + }) + ); + result.push( + h( + "div", + attrs.array.map((val) => h(`span.val.${val}`, { key: val }, val)) + ) + ); + return result; + }, + dummyAction() {}, + }); + + const array = ["ElementOne", "ElementTwo"]; + this.set("args", { array }); + + await render( + hbs`` + ); + + const startElements = Array.from(document.querySelectorAll("span.val")); + assert.deepEqual( + startElements.map((e) => e.innerText), + ["ElementOne", "ElementTwo"] + ); + const elementOneBefore = startElements[0]; + + const parent = elementOneBefore.parentNode; + const observer = new MutationObserver(function (mutations) { + assert.notOk( + mutations.some((m) => + Array.from(m.addedNodes).includes(elementOneBefore) + ) + ); + }); + observer.observe(parent, { childList: true }); + + array.unshift( + "PrependedElementOne", + "PrependedElementTwo", + "PrependedElementThree" + ); + + await click(".rerender"); + + const endElements = Array.from(document.querySelectorAll("span.val")); + assert.deepEqual( + endElements.map((e) => e.innerText), + [ + "PrependedElementOne", + "PrependedElementTwo", + "PrependedElementThree", + "ElementOne", + "ElementTwo", + ] + ); + const elementOneAfter = endElements[3]; + + assert.strictEqual(elementOneBefore, elementOneAfter); + }); }); diff --git a/app/assets/javascripts/yarn.lock b/app/assets/javascripts/yarn.lock index aebcc597cbe..c83d31df79b 100644 --- a/app/assets/javascripts/yarn.lock +++ b/app/assets/javascripts/yarn.lock @@ -1013,6 +1013,20 @@ resolved "https://registry.yarnpkg.com/@discourse/itsatrap/-/itsatrap-2.0.10.tgz#c7e750eeb32b54e769e952c4ecc472213eb1385a" integrity sha512-Jn1gdiyHMGUsmUfLFf4Q7VnTAv0l7NePbegU6pKhKHEmbzV3FosGxq30fTOYgVyTS1bxqGjlA6LvQttJpv3ROw== +"@discourse/virtual-dom@^2.1.2-0": + version "2.1.2-0" + resolved "https://registry.yarnpkg.com/@discourse/virtual-dom/-/virtual-dom-2.1.2-0.tgz#74e44261c7b0a99b3bf6db0eac37b86e978906a6" + integrity sha512-5sTfdNxyrFK9yb98YLBAChYiO2K6Go7ptErVUQciT7rgueoGyLyw6Sm0FeVkSK1GLfusYFKZG8ch2vGNzJ0wlQ== + dependencies: + browser-split "0.0.1" + error "^4.3.0" + ev-store "^7.0.0" + global "^4.3.0" + is-object "^1.0.1" + next-tick "^0.2.2" + x-is-array "0.1.0" + x-is-string "0.1.0" + "@ember-compat/tracked-built-ins@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@ember-compat/tracked-built-ins/-/tracked-built-ins-0.9.1.tgz#4cc97c1841425fbf812ef3c63c00ab4790fc32a0" @@ -9315,20 +9329,6 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -virtual-dom@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/virtual-dom/-/virtual-dom-2.1.1.tgz#80eda2d481b9ede0c049118cefcb4a05f21d1375" - integrity sha1-gO2i1IG57eDASRGM78tKBfIdE3U= - dependencies: - browser-split "0.0.1" - error "^4.3.0" - ev-store "^7.0.0" - global "^4.3.0" - is-object "^1.0.1" - next-tick "^0.2.2" - x-is-array "0.1.0" - x-is-string "0.1.0" - w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073"