mirror of
https://github.com/discourse/discourse.git
synced 2025-02-07 20:08:26 +00:00
FIX: Correctly debounce various functions (#18673)
Debouncing inline anonymous functions does not work. This fixes all instances of that error by extracting the function or using the new `@debounce(delay)` decorator
This commit is contained in:
parent
ce53152e53
commit
8304f40f84
@ -2,9 +2,8 @@ import Controller from "@ember/controller";
|
|||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { debounce, observes } from "discourse-common/utils/decorators";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
@ -113,18 +112,13 @@ export default Controller.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
@observes("filter", "onlyOverridden", "model")
|
@observes("filter", "onlyOverridden", "model")
|
||||||
|
@debounce(INPUT_DELAY)
|
||||||
filterContent() {
|
filterContent() {
|
||||||
discourseDebounce(
|
if (this._skipBounce) {
|
||||||
this,
|
this.set("_skipBounce", false);
|
||||||
() => {
|
} else {
|
||||||
if (this._skipBounce) {
|
this.filterContentNow(this.categoryNameKey);
|
||||||
this.set("_skipBounce", false);
|
}
|
||||||
} else {
|
|
||||||
this.filterContentNow(this.categoryNameKey);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
INPUT_DELAY
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { action, get } from "@ember/object";
|
import { action, get } from "@ember/object";
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { debounce, observes } from "discourse-common/utils/decorators";
|
||||||
import { searchForTerm } from "discourse/lib/search";
|
import { searchForTerm } from "discourse/lib/search";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
@ -30,37 +29,29 @@ export default Component.extend({
|
|||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@debounce(300)
|
||||||
search(title) {
|
search(title) {
|
||||||
discourseDebounce(
|
if (isEmpty(title)) {
|
||||||
this,
|
this.setProperties({ messages: null, loading: false });
|
||||||
function () {
|
return;
|
||||||
const currentTopicId = this.currentTopicId;
|
}
|
||||||
|
|
||||||
if (isEmpty(title)) {
|
searchForTerm(title, {
|
||||||
this.setProperties({ messages: null, loading: false });
|
typeFilter: "private_messages",
|
||||||
return;
|
searchForId: true,
|
||||||
}
|
restrictToArchetype: "private_message",
|
||||||
|
}).then((results) => {
|
||||||
searchForTerm(title, {
|
if (results?.posts?.length) {
|
||||||
typeFilter: "private_messages",
|
this.set(
|
||||||
searchForId: true,
|
"messages",
|
||||||
restrictToArchetype: "private_message",
|
results.posts
|
||||||
}).then((results) => {
|
.mapBy("topic")
|
||||||
if (results && results.posts && results.posts.length > 0) {
|
.filter((t) => t.get("id") !== this.currentTopicId)
|
||||||
this.set(
|
);
|
||||||
"messages",
|
} else {
|
||||||
results.posts
|
this.setProperties({ messages: null, loading: false });
|
||||||
.mapBy("topic")
|
}
|
||||||
.filter((t) => t.get("id") !== currentTopicId)
|
});
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.setProperties({ messages: null, loading: false });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
title,
|
|
||||||
300
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -1,19 +1,32 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
tagName: "",
|
tagName: "",
|
||||||
copyIcon: "copy",
|
copyIcon: "copy",
|
||||||
copyClass: "btn-primary",
|
copyClass: "btn-primary",
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_restoreButton() {
|
||||||
|
if (this.isDestroying || this.isDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set("copyIcon", "copy");
|
||||||
|
this.set("copyClass", "btn-primary");
|
||||||
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
copy() {
|
copy() {
|
||||||
const target = document.querySelector(this.selector);
|
const target = document.querySelector(this.selector);
|
||||||
target.select();
|
target.select();
|
||||||
target.setSelectionRange(0, target.value.length);
|
target.setSelectionRange(0, target.value.length);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
|
|
||||||
if (this.copied) {
|
if (this.copied) {
|
||||||
this.copied();
|
this.copied();
|
||||||
}
|
}
|
||||||
@ -21,13 +34,7 @@ export default Component.extend({
|
|||||||
this.set("copyIcon", "check");
|
this.set("copyIcon", "check");
|
||||||
this.set("copyClass", "btn-primary ok");
|
this.set("copyClass", "btn-primary ok");
|
||||||
|
|
||||||
discourseDebounce(() => {
|
discourseDebounce(this._restoreButton, 3000);
|
||||||
if (this.isDestroying || this.isDestroyed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.set("copyIcon", "copy");
|
|
||||||
this.set("copyClass", "btn-primary");
|
|
||||||
}, 3000);
|
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, {
|
||||||
|
debounce,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { gt } from "@ember/object/computed";
|
import { gt } from "@ember/object/computed";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
@ -23,14 +25,9 @@ export default Controller.extend({
|
|||||||
bulkSelection: null,
|
bulkSelection: null,
|
||||||
|
|
||||||
@observes("filterInput")
|
@observes("filterInput")
|
||||||
|
@debounce(500)
|
||||||
_setFilter() {
|
_setFilter() {
|
||||||
discourseDebounce(
|
this.set("filter", this.filterInput);
|
||||||
this,
|
|
||||||
function () {
|
|
||||||
this.set("filter", this.filterInput);
|
|
||||||
},
|
|
||||||
500
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("order", "asc", "filter")
|
@observes("order", "asc", "filter")
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, {
|
||||||
|
debounce,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
@ -17,14 +19,9 @@ export default Controller.extend({
|
|||||||
loading: false,
|
loading: false,
|
||||||
|
|
||||||
@observes("filterInput")
|
@observes("filterInput")
|
||||||
|
@debounce(500)
|
||||||
_setFilter() {
|
_setFilter() {
|
||||||
discourseDebounce(
|
this.set("filter", this.filterInput);
|
||||||
this,
|
|
||||||
function () {
|
|
||||||
this.set("filter", this.filterInput);
|
|
||||||
},
|
|
||||||
500
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("order", "asc", "filter")
|
@observes("order", "asc", "filter")
|
||||||
|
@ -2,8 +2,10 @@ import Controller from "@ember/controller";
|
|||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { equal, reads } from "@ember/object/computed";
|
import { equal, reads } from "@ember/object/computed";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseComputed, {
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
debounce,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
import Invite from "discourse/models/invite";
|
import Invite from "discourse/models/invite";
|
||||||
@ -28,15 +30,10 @@ export default Controller.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
@observes("searchTerm")
|
@observes("searchTerm")
|
||||||
|
@debounce(INPUT_DELAY)
|
||||||
_searchTermChanged() {
|
_searchTermChanged() {
|
||||||
discourseDebounce(
|
Invite.findInvitedBy(this.user, this.filter, this.searchTerm).then(
|
||||||
this,
|
(invites) => this.set("model", invites)
|
||||||
function () {
|
|
||||||
Invite.findInvitedBy(this.user, this.filter, this.searchTerm).then(
|
|
||||||
(invites) => this.set("model", invites)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
INPUT_DELAY
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -19,6 +19,32 @@ function updateCache(term, results) {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function searchFunc(q, limit, cats, resultFunc) {
|
||||||
|
oldSearch = ajax("/tags/filter/search", {
|
||||||
|
data: { limit, q },
|
||||||
|
});
|
||||||
|
|
||||||
|
let returnVal = CANCELLED_STATUS;
|
||||||
|
|
||||||
|
oldSearch
|
||||||
|
.then((r) => {
|
||||||
|
const categoryNames = cats.map((c) => c.model.get("name"));
|
||||||
|
|
||||||
|
const tags = r.results.map((tag) => {
|
||||||
|
tag.text = categoryNames.includes(tag.text)
|
||||||
|
? `${tag.text}${TAG_HASHTAG_POSTFIX}`
|
||||||
|
: tag.text;
|
||||||
|
return tag;
|
||||||
|
});
|
||||||
|
|
||||||
|
returnVal = cats.concat(tags);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
oldSearch = null;
|
||||||
|
resultFunc(returnVal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function searchTags(term, categories, limit) {
|
function searchTags(term, categories, limit) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let clearPromise = isTesting()
|
let clearPromise = isTesting()
|
||||||
@ -27,45 +53,18 @@ function searchTags(term, categories, limit) {
|
|||||||
resolve(CANCELLED_STATUS);
|
resolve(CANCELLED_STATUS);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
const debouncedSearch = (q, cats, resultFunc) => {
|
discourseDebounce(
|
||||||
discourseDebounce(
|
this,
|
||||||
this,
|
searchFunc,
|
||||||
function () {
|
term,
|
||||||
oldSearch = ajax("/tags/filter/search", {
|
limit,
|
||||||
data: { limit, q },
|
categories,
|
||||||
});
|
(result) => {
|
||||||
|
cancel(clearPromise);
|
||||||
let returnVal = CANCELLED_STATUS;
|
resolve(updateCache(term, result));
|
||||||
|
},
|
||||||
oldSearch
|
300
|
||||||
.then((r) => {
|
);
|
||||||
const categoryNames = cats.map((c) => c.model.get("name"));
|
|
||||||
|
|
||||||
const tags = r.results.map((tag) => {
|
|
||||||
tag.text = categoryNames.includes(tag.text)
|
|
||||||
? `${tag.text}${TAG_HASHTAG_POSTFIX}`
|
|
||||||
: tag.text;
|
|
||||||
return tag;
|
|
||||||
});
|
|
||||||
|
|
||||||
returnVal = cats.concat(tags);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
oldSearch = null;
|
|
||||||
resultFunc(returnVal);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
q,
|
|
||||||
cats,
|
|
||||||
resultFunc,
|
|
||||||
300
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
debouncedSearch(term, categories, (result) => {
|
|
||||||
cancel(clearPromise);
|
|
||||||
resolve(updateCache(term, result));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,28 +131,26 @@ function positioningWorkaround(fixedElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkForInputs = function () {
|
function checkForInputs() {
|
||||||
discourseDebounce(
|
attachTouchStart(fixedElement, lastTouched);
|
||||||
this,
|
|
||||||
function () {
|
|
||||||
attachTouchStart(fixedElement, lastTouched);
|
|
||||||
|
|
||||||
fixedElement
|
fixedElement
|
||||||
.querySelectorAll("input[type=text], textarea")
|
.querySelectorAll("input[type=text], textarea")
|
||||||
.forEach((el) => {
|
.forEach((el) => {
|
||||||
attachTouchStart(el, positioningHack);
|
attachTouchStart(el, positioningHack);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
100
|
|
||||||
);
|
function debouncedCheckForInputs() {
|
||||||
};
|
discourseDebounce(checkForInputs, 100);
|
||||||
|
}
|
||||||
|
|
||||||
positioningWorkaround.touchstartEvent = function (element) {
|
positioningWorkaround.touchstartEvent = function (element) {
|
||||||
let triggerHack = positioningHack.bind(element);
|
let triggerHack = positioningHack.bind(element);
|
||||||
triggerHack();
|
triggerHack();
|
||||||
};
|
};
|
||||||
|
|
||||||
const observer = new MutationObserver(checkForInputs);
|
const observer = new MutationObserver(debouncedCheckForInputs);
|
||||||
observer.observe(fixedElement, {
|
observer.observe(fixedElement, {
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true,
|
subtree: true,
|
||||||
|
@ -2,34 +2,15 @@ import Mixin from "@ember/object/mixin";
|
|||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { cancel } from "@ember/runloop";
|
import { cancel } from "@ember/runloop";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
const INITIAL_DELAY_MS = isTesting() ? 0 : 50;
|
const INITIAL_DELAY_MS = 50;
|
||||||
const DEBOUNCE_MS = isTesting() ? 0 : 5;
|
const DEBOUNCE_MS = 5;
|
||||||
|
|
||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
queueDockCheck: null,
|
|
||||||
_initialTimer: null,
|
_initialTimer: null,
|
||||||
_queuedTimer: null,
|
_queuedTimer: null,
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.queueDockCheck = () => {
|
|
||||||
this._queuedTimer = discourseDebounce(
|
|
||||||
this,
|
|
||||||
this.safeDockCheck,
|
|
||||||
DEBOUNCE_MS
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
safeDockCheck() {
|
|
||||||
if (this.isDestroyed || this.isDestroying) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.dockCheck();
|
|
||||||
},
|
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
@ -57,4 +38,21 @@ export default Mixin.create({
|
|||||||
window.removeEventListener("scroll", this.queueDockCheck);
|
window.removeEventListener("scroll", this.queueDockCheck);
|
||||||
document.removeEventListener("touchmove", this.queueDockCheck);
|
document.removeEventListener("touchmove", this.queueDockCheck);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
queueDockCheck() {
|
||||||
|
this._queuedTimer = discourseDebounce(
|
||||||
|
this,
|
||||||
|
this.safeDockCheck,
|
||||||
|
DEBOUNCE_MS
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
safeDockCheck() {
|
||||||
|
if (this.isDestroyed || this.isDestroying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.dockCheck();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -48,16 +48,14 @@ export default Mixin.create({
|
|||||||
// If the user reaches the very bottom of the topic, we only want to reset
|
// If the user reaches the very bottom of the topic, we only want to reset
|
||||||
// this scroll direction after a second scroll down. This is a nicer event
|
// this scroll direction after a second scroll down. This is a nicer event
|
||||||
// similar to what Safari and Chrome do.
|
// similar to what Safari and Chrome do.
|
||||||
discourseDebounce(
|
discourseDebounce(this, this._setBottomHit, 1000);
|
||||||
this,
|
|
||||||
function () {
|
|
||||||
this._bottomHit = 1;
|
|
||||||
},
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this._bottomHit === 1) {
|
if (this._bottomHit === 1) {
|
||||||
this.set("mobileScrollDirection", null);
|
this.set("mobileScrollDirection", null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_setBottomHit() {
|
||||||
|
this._bottomHit = 1;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
/* global Pikaday:true */
|
/* global Pikaday:true */
|
||||||
import computed, { observes } from "discourse-common/utils/decorators";
|
import computed, {
|
||||||
|
debounce,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import EmberObject, { action } from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
import { cookAsync } from "discourse/lib/text";
|
import { cookAsync } from "discourse/lib/text";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import loadScript from "discourse/lib/load-script";
|
import loadScript from "discourse/lib/load-script";
|
||||||
import { notEmpty } from "@ember/object/computed";
|
import { notEmpty } from "@ember/object/computed";
|
||||||
@ -59,25 +61,19 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
@observes("computedConfig.{from,to,options}", "options", "isValid", "isRange")
|
@observes("computedConfig.{from,to,options}", "options", "isValid", "isRange")
|
||||||
_renderPreview() {
|
@debounce(INPUT_DELAY)
|
||||||
discourseDebounce(
|
async _renderPreview() {
|
||||||
this,
|
if (this.markup) {
|
||||||
function () {
|
const result = await cookAsync(this.markup);
|
||||||
const markup = this.markup;
|
this.set("currentPreview", result);
|
||||||
if (markup) {
|
|
||||||
cookAsync(markup).then((result) => {
|
schedule("afterRender", () => {
|
||||||
this.set("currentPreview", result);
|
applyLocalDates(
|
||||||
schedule("afterRender", () => {
|
document.querySelectorAll(".preview .discourse-local-date"),
|
||||||
applyLocalDates(
|
this.siteSettings
|
||||||
document.querySelectorAll(".preview .discourse-local-date"),
|
);
|
||||||
this.siteSettings
|
});
|
||||||
);
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
INPUT_DELAY
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("date", "toDate", "toTime")
|
@computed("date", "toDate", "toTime")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { debounce } from "discourse-common/utils/decorators";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { headerOffset } from "discourse/lib/offset-calculator";
|
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";
|
||||||
@ -74,28 +74,22 @@ function initialize(api) {
|
|||||||
// No need to unsubscribe, core unsubscribes /topic/* routes
|
// No need to unsubscribe, core unsubscribes /topic/* routes
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@debounce(500)
|
||||||
_scrollToDiscobotPost(postNumber) {
|
_scrollToDiscobotPost(postNumber) {
|
||||||
discourseDebounce(
|
const post = document.querySelector(
|
||||||
this,
|
`.topic-post article#post_${postNumber}`
|
||||||
function () {
|
|
||||||
const post = document.querySelector(
|
|
||||||
`.topic-post article#post_${postNumber}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!post || isElementInViewport(post)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewportOffset = post.getBoundingClientRect();
|
|
||||||
|
|
||||||
window.scrollTo({
|
|
||||||
top: window.scrollY + viewportOffset.top - headerOffset(),
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
postNumber,
|
|
||||||
500
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!post || isElementInViewport(post)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewportOffset = post.getBoundingClientRect();
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: window.scrollY + viewportOffset.top - headerOffset(),
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user