mirror of
https://github.com/discourse/discourse.git
synced 2025-04-02 08:35:59 +08:00
DEV: Fewer jQuery calls in offset calculation (#15465)
This commit is contained in:
parent
0a0e06fcf8
commit
1ed2520589
app/assets/javascripts/discourse/app
components
lib
plugins/discourse-narrative-bot/assets/javascripts/initializers
@ -8,7 +8,7 @@ import Composer from "discourse/models/composer";
|
|||||||
import KeyEnterEscape from "discourse/mixins/key-enter-escape";
|
import KeyEnterEscape from "discourse/mixins/key-enter-escape";
|
||||||
import afterTransition from "discourse/lib/after-transition";
|
import afterTransition from "discourse/lib/after-transition";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { headerOffset } from "discourse/components/site-header";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import positioningWorkaround from "discourse/lib/safari-hacks";
|
import positioningWorkaround from "discourse/lib/safari-hacks";
|
||||||
|
|
||||||
const START_DRAG_EVENTS = ["touchstart", "mousedown"];
|
const START_DRAG_EVENTS = ["touchstart", "mousedown"];
|
||||||
|
@ -7,6 +7,7 @@ import Docking from "discourse/mixins/docking";
|
|||||||
import MountWidget from "discourse/components/mount-widget";
|
import MountWidget from "discourse/components/mount-widget";
|
||||||
import ItsATrap from "@discourse/itsatrap";
|
import ItsATrap from "@discourse/itsatrap";
|
||||||
import RerenderOnDoNotDisturbChange from "discourse/mixins/rerender-on-do-not-disturb-change";
|
import RerenderOnDoNotDisturbChange from "discourse/mixins/rerender-on-do-not-disturb-change";
|
||||||
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
import { topicTitleDecorators } from "discourse/components/topic-title";
|
import { topicTitleDecorators } from "discourse/components/topic-title";
|
||||||
|
|
||||||
@ -438,15 +439,6 @@ export default SiteHeaderComponent.extend({
|
|||||||
classNames: ["d-header-wrap"],
|
classNames: ["d-header-wrap"],
|
||||||
});
|
});
|
||||||
|
|
||||||
export function headerOffset() {
|
|
||||||
return (
|
|
||||||
parseInt(
|
|
||||||
document.documentElement.style.getPropertyValue("--header-offset"),
|
|
||||||
10
|
|
||||||
) || 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function headerTop() {
|
export function headerTop() {
|
||||||
const header = document.querySelector("header.d-header");
|
const header = document.querySelector("header.d-header");
|
||||||
const headerOffsetTop = header.offsetTop ? header.offsetTop : 0;
|
const headerOffsetTop = header.offsetTop ? header.offsetTop : 0;
|
||||||
|
@ -5,7 +5,7 @@ import PanEvents, {
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { headerOffset } from "discourse/components/site-header";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import { later, next } from "@ember/runloop";
|
import { later, next } from "@ember/runloop";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Docking from "discourse/mixins/docking";
|
import Docking from "discourse/mixins/docking";
|
||||||
import MountWidget from "discourse/components/mount-widget";
|
import MountWidget from "discourse/components/mount-widget";
|
||||||
import { headerOffset } from "discourse/components/site-header";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
import optionalService from "discourse/lib/optional-service";
|
import optionalService from "discourse/lib/optional-service";
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { isAppWebview } from "discourse/lib/utilities";
|
import { isAppWebview } from "discourse/lib/utilities";
|
||||||
import { later, run, schedule, throttle } from "@ember/runloop";
|
import { later, run, schedule, throttle } from "@ember/runloop";
|
||||||
import {
|
import {
|
||||||
@ -6,9 +8,10 @@ import {
|
|||||||
} from "discourse/lib/topic-list-tracker";
|
} from "discourse/lib/topic-list-tracker";
|
||||||
import Composer from "discourse/models/composer";
|
import Composer from "discourse/models/composer";
|
||||||
import DiscourseURL from "discourse/lib/url";
|
import DiscourseURL from "discourse/lib/url";
|
||||||
|
import domUtils from "discourse-common/utils/dom-utils";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { minimumOffset } from "discourse/lib/offset-calculator";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
|
|
||||||
const DEFAULT_BINDINGS = {
|
const DEFAULT_BINDINGS = {
|
||||||
"!": { postAction: "showFlags" },
|
"!": { postAction: "showFlags" },
|
||||||
@ -608,7 +611,7 @@ export default {
|
|||||||
// Discard selection if it is not in viewport, so users can combine
|
// Discard selection if it is not in viewport, so users can combine
|
||||||
// keyboard shortcuts with mouse scrolling.
|
// keyboard shortcuts with mouse scrolling.
|
||||||
if ($selected.length !== 0 && !fast) {
|
if ($selected.length !== 0 && !fast) {
|
||||||
const offset = minimumOffset();
|
const offset = headerOffset();
|
||||||
const beginScreen = $(window).scrollTop() - offset;
|
const beginScreen = $(window).scrollTop() - offset;
|
||||||
const endScreen = beginScreen + window.innerHeight + offset;
|
const endScreen = beginScreen + window.innerHeight + offset;
|
||||||
const beginArticle = $selected.offset().top;
|
const beginArticle = $selected.offset().top;
|
||||||
@ -621,7 +624,7 @@ export default {
|
|||||||
// If still nothing is selected, select the first post that is
|
// If still nothing is selected, select the first post that is
|
||||||
// visible and cancel move operation.
|
// visible and cancel move operation.
|
||||||
if (!$selected || $selected.length === 0) {
|
if (!$selected || $selected.length === 0) {
|
||||||
const offset = minimumOffset();
|
const offset = headerOffset();
|
||||||
$selected = $articles
|
$selected = $articles
|
||||||
.toArray()
|
.toArray()
|
||||||
.find((article) =>
|
.find((article) =>
|
||||||
@ -636,32 +639,32 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const index = $articles.index($selected);
|
const index = $articles.index($selected);
|
||||||
let $article = $articles.eq(index);
|
let article = $articles.eq(index)[0];
|
||||||
|
|
||||||
// Try doing a page scroll in the context of current post.
|
// Try doing a page scroll in the context of current post.
|
||||||
if (!fast && direction !== 0 && $article.length > 0) {
|
if (!fast && direction !== 0 && article) {
|
||||||
// The beginning of first article is the beginning of the page.
|
// The beginning of first article is the beginning of the page.
|
||||||
const beginArticle =
|
const beginArticle =
|
||||||
$article.is(".topic-post") && $article.find("#post_1").length
|
article.classList.contains("topic-post") &&
|
||||||
|
article.querySelector("#post_1")
|
||||||
? 0
|
? 0
|
||||||
: $article.offset().top;
|
: domUtils.offset(article).top;
|
||||||
const endArticle =
|
const endArticle = domUtils.offset(article).top + article.offsetHeight;
|
||||||
$article.offset().top + $article[0].getBoundingClientRect().height;
|
|
||||||
|
|
||||||
const beginScreen = $(window).scrollTop();
|
const beginScreen = window.scrollY;
|
||||||
const endScreen = beginScreen + window.innerHeight;
|
const endScreen = beginScreen + window.innerHeight;
|
||||||
|
|
||||||
if (direction < 0 && beginScreen > beginArticle) {
|
if (direction < 0 && beginScreen > beginArticle) {
|
||||||
return this._scrollTo(
|
return this._scrollTo(
|
||||||
Math.max(
|
Math.max(
|
||||||
beginScreen - window.innerHeight + 3 * minimumOffset(), // page up
|
beginScreen - window.innerHeight + 3 * headerOffset(), // page up
|
||||||
beginArticle - minimumOffset() // beginning of article
|
beginArticle - headerOffset() // beginning of article
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else if (direction > 0 && endScreen < endArticle - minimumOffset()) {
|
} else if (direction > 0 && endScreen < endArticle - headerOffset()) {
|
||||||
return this._scrollTo(
|
return this._scrollTo(
|
||||||
Math.min(
|
Math.min(
|
||||||
endScreen - 3 * minimumOffset(), // page down
|
endScreen - 3 * headerOffset(), // page down
|
||||||
endArticle - window.innerHeight // end of article
|
endArticle - window.innerHeight // end of article
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -678,68 +681,59 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$article = $articles.eq(index + direction);
|
article = $articles.eq(index + direction)[0];
|
||||||
if ($article.length > 0) {
|
if (!article) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$articles.removeClass("selected");
|
$articles.removeClass("selected");
|
||||||
$article.addClass("selected");
|
article.classList.add("selected");
|
||||||
|
|
||||||
this.appEvents.trigger("keyboard:move-selection", {
|
this.appEvents.trigger("keyboard:move-selection", {
|
||||||
articles: $articles.get(),
|
articles: $articles.get(),
|
||||||
selectedArticle: $article.get(0),
|
selectedArticle: article,
|
||||||
});
|
});
|
||||||
|
|
||||||
const articleRect = $article[0].getBoundingClientRect();
|
const articleTop = domUtils.offset(article).top;
|
||||||
if (!fast && direction < 0 && articleRect.height > window.innerHeight) {
|
if (!fast && direction < 0 && article.offsetHeight > window.innerHeight) {
|
||||||
// Scrolling to the last "page" of the previous post if post has multiple
|
// Scrolling to the last "page" of the previous post if post has multiple
|
||||||
// "pages" (if its height does not fit in the screen).
|
// "pages" (if its height does not fit in the screen).
|
||||||
return this._scrollTo(
|
return this._scrollTo(
|
||||||
$article.offset().top + articleRect.height - window.innerHeight
|
articleTop + article.offsetHeight - window.innerHeight
|
||||||
);
|
);
|
||||||
} else if ($article.is(".topic-post")) {
|
} else if (article.classList.contains("topic-post")) {
|
||||||
return this._scrollTo(
|
return this._scrollTo(
|
||||||
$article.find("#post_1").length > 0
|
article.querySelector("#post_1") ? 0 : articleTop - headerOffset(),
|
||||||
? 0
|
{ focusTabLoc: true }
|
||||||
: $article.offset().top - minimumOffset(),
|
|
||||||
() => $("a.tabLoc", $article).focus()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise scroll through the suggested topic list.
|
// Otherwise scroll through the suggested topic list.
|
||||||
this._scrollList($article, direction);
|
article.scrollIntoView({
|
||||||
}
|
behavior: "smooth",
|
||||||
|
block: "center",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrollTo(scrollTop) {
|
_scrollTo(scrollTop, opts = {}) {
|
||||||
window.scrollTo({
|
window.scrollTo({
|
||||||
top: scrollTop,
|
top: scrollTop,
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (opts.focusTabLoc) {
|
||||||
|
window.addEventListener("scroll", this._onScrollEnds, { passive: true });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrollList($article) {
|
@bind
|
||||||
// Try to keep the article on screen
|
_onScrollEnds() {
|
||||||
const pos = $article.offset();
|
window.removeEventListener("scroll", this._onScrollEnds, { passive: true });
|
||||||
const height = $article.height();
|
discourseDebounce(this, this._onScrollEndsCallback, animationDuration);
|
||||||
const headerHeight = $("header.d-header").height();
|
},
|
||||||
const scrollTop = $(window).scrollTop();
|
|
||||||
const windowHeight = $(window).height();
|
|
||||||
|
|
||||||
// skip if completely on screen
|
_onScrollEndsCallback() {
|
||||||
if (
|
document.querySelector(".topic-post.selected a.tabLoc")?.focus();
|
||||||
pos.top - headerHeight > scrollTop &&
|
|
||||||
pos.top + height < scrollTop + windowHeight
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let scrollPos = pos.top + height / 2 - windowHeight * 0.5;
|
|
||||||
if (height > windowHeight - headerHeight) {
|
|
||||||
scrollPos = pos.top - headerHeight;
|
|
||||||
}
|
|
||||||
if (scrollPos < 0) {
|
|
||||||
scrollPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._scrollTo(scrollPos);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
categoriesTopicsList() {
|
categoriesTopicsList() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import { minimumOffset } from "discourse/lib/offset-calculator";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
|
|
||||||
// Dear traveller, you are entering a zone where we are at war with the browser.
|
// Dear traveller, you are entering a zone where we are at war with the browser.
|
||||||
// The browser is insisting on positioning scrollTop per the location it was in
|
// The browser is insisting on positioning scrollTop per the location it was in
|
||||||
@ -50,7 +50,7 @@ export default class LockOn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset - minimumOffset();
|
return offset - headerOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
clearLock() {
|
clearLock() {
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
|
import deprecated from "discourse-common/lib/deprecated";
|
||||||
|
|
||||||
export function scrollTopFor(y) {
|
export function scrollTopFor(y) {
|
||||||
return y - offsetCalculator();
|
return y - offsetCalculator();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function minimumOffset() {
|
export function minimumOffset() {
|
||||||
|
deprecated(
|
||||||
|
"The minimumOffset() helper is deprecated, please use headerOffset() instead.",
|
||||||
|
{
|
||||||
|
since: "2.8.0.beta10",
|
||||||
|
dropFrom: "2.9.0.beta2",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const header = document.querySelector("header.d-header"),
|
const header = document.querySelector("header.d-header"),
|
||||||
iPadNav = document.querySelector(".footer-nav-ipad .footer-nav"),
|
iPadNav = document.querySelector(".footer-nav-ipad .footer-nav"),
|
||||||
iPadNavHeight = iPadNav ? iPadNav.offsetHeight : 0;
|
iPadNavHeight = iPadNav ? iPadNav.offsetHeight : 0;
|
||||||
@ -17,8 +27,17 @@ export function minimumOffset() {
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function headerOffset() {
|
||||||
|
return (
|
||||||
|
parseInt(
|
||||||
|
document.documentElement.style.getPropertyValue("--header-offset"),
|
||||||
|
10
|
||||||
|
) || 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function offsetCalculator() {
|
export default function offsetCalculator() {
|
||||||
const min = minimumOffset();
|
const min = headerOffset();
|
||||||
|
|
||||||
// on mobile, just use the header
|
// on mobile, just use the header
|
||||||
if (document.querySelector("html").classList.contains("mobile-view")) {
|
if (document.querySelector("html").classList.contains("mobile-view")) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { addWidgetCleanCallback } from "discourse/components/mount-widget";
|
import { addWidgetCleanCallback } from "discourse/components/mount-widget";
|
||||||
import Site from "discourse/models/site";
|
import Site from "discourse/models/site";
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import { headerOffset } from "discourse/components/site-header";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
|
|
||||||
export default class StickyAvatars {
|
export default class StickyAvatars {
|
||||||
@ -79,6 +79,9 @@ export default class StickyAvatars {
|
|||||||
@bind
|
@bind
|
||||||
_initIntersectionObserver() {
|
_initIntersectionObserver() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
|
const headerOffsetInPx =
|
||||||
|
headerOffset() <= 0 ? "0px" : `-${headerOffset()}px`;
|
||||||
|
|
||||||
this.intersectionObserver = new IntersectionObserver(
|
this.intersectionObserver = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
@ -99,7 +102,7 @@ export default class StickyAvatars {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
threshold: [0.0, 1.0],
|
threshold: [0.0, 1.0],
|
||||||
rootMargin: `-${headerOffset()}px 0px 0px 0px`,
|
rootMargin: `${headerOffsetInPx} 0px 0px 0px`,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { headerOffset } from "discourse/components/site-header";
|
import { headerOffset } from "discourse/lib/offset-calculator";
|
||||||
import isElementInViewport from "discourse/lib/is-element-in-viewport";
|
import isElementInViewport from "discourse/lib/is-element-in-viewport";
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user