From 13b4b0d3c4a8517142f6ad54b50d98dfa6ea6e01 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 18 Mar 2022 11:47:23 +0000 Subject: [PATCH] DEV: Refactor d-section to function correctly with loading-slider (#16216) When using the loading-slider, the component instance is re-used across different pages and so the didInsertElement/willDestroyElement hooks are not fired during page transitions. Instead, we can lean on `didReceiveAttrs`. Similar fix to 87b98e2862 Note that the `scrollTop` feature is still problematic under the loading slider. That will need to be addressed in a future commit. --- .../discourse/app/components/d-section.js | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/d-section.js b/app/assets/javascripts/discourse/app/components/d-section.js index 3b5433b3ea3..91bc8bfaadf 100644 --- a/app/assets/javascripts/discourse/app/components/d-section.js +++ b/app/assets/javascripts/discourse/app/components/d-section.js @@ -1,25 +1,19 @@ import deprecated from "discourse-common/lib/deprecated"; import Component from "@ember/component"; import { scrollTop } from "discourse/mixins/scroll-top"; +import { scheduleOnce } from "@ember/runloop"; // Can add a body class from within a component, also will scroll to the top automatically. -export default Component.extend({ - tagName: null, - pageClass: null, - bodyClass: null, - scrollTop: true, +export default class extends Component { + tagName = null; + pageClass = null; + bodyClass = null; + scrollTop = true; + currentClasses = new Set(); didInsertElement() { this._super(...arguments); - if (this.pageClass) { - document.body.classList.add(`${this.pageClass}-page`); - } - - if (this.bodyClass) { - document.body.classList.add(...this.bodyClass.split(" ")); - } - if (this.scrollTop === "false") { deprecated("Uses boolean instead of string for scrollTop.", { since: "2.8.0.beta9", @@ -34,17 +28,42 @@ export default Component.extend({ } scrollTop(); - }, + } + + didReceiveAttrs() { + this._super(...arguments); + scheduleOnce("afterRender", this, this._updateClasses); + } willDestroyElement() { this._super(...arguments); + scheduleOnce("afterRender", this, this._removeClasses); + } + _updateClasses() { + if (this.isDestroying || this.isDestroyed) { + return; + } + + const desiredClasses = new Set(); if (this.pageClass) { - document.body.classList.remove(`${this.pageClass}-page`); + desiredClasses.add(`${this.pageClass}-page`); + } + if (this.bodyClass) { + for (const bodyClass of this.bodyClass.split(" ")) { + desiredClasses.add(bodyClass); + } } - if (this.bodyClass) { - document.body.classList.remove(...this.bodyClass.split(" ")); - } - }, -}); + document.body.classList.add(...desiredClasses); + const removeClasses = [...this.currentClasses].filter( + (c) => !desiredClasses.has(c) + ); + document.body.classList.remove(...removeClasses); + this.currentClasses = desiredClasses; + } + + _removeClasses() { + document.body.classList.remove(...this.currentClasses); + } +}