FIX: Prevent `LockOn` conflicts (#10422)

If there's already a `LockOn` instance, clear its lock before creating creating a new one. Fixes a shaky viewport effect after certain transitions.

Includes:
* Slight refactor (elementId wasn't an id, but a selector - it included the "#" prefix)
* Add support for a[name=X] anchors in `jumpToPost`
* Scope down anchors to the #main element (Embeded fontawesome sprites are causing conflicts, e.g. when given `bed` anchor, `<a name="bed">` was at odds with `<symbol id="bed" viewBox="0 0 640 512">(…)</symbol>`)
This commit is contained in:
Jarek Radosz 2020-08-13 19:39:40 +02:00 committed by GitHub
parent ba3ee3444e
commit d0d651d8bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 23 deletions

View File

@ -66,25 +66,32 @@ export function groupPath(subPath) {
}
let _jumpScheduled = false;
let _transitioning = false;
let lockon = null;
export function jumpToElement(elementId) {
if (_jumpScheduled || isEmpty(elementId)) {
return;
}
const selector = `#${elementId}, a[name=${elementId}]`;
const selector = `#main #${elementId}, a[name=${elementId}]`;
_jumpScheduled = true;
schedule("afterRender", function() {
const lockon = new LockOn(selector, {
if (lockon) {
lockon.clearLock();
}
lockon = new LockOn(selector, {
finished() {
_jumpScheduled = false;
lockon = null;
}
});
lockon.lock();
});
}
let _transitioning = false;
const DiscourseURL = EmberObject.extend({
isJumpScheduled() {
return _transitioning || _jumpScheduled;
@ -98,9 +105,6 @@ const DiscourseURL = EmberObject.extend({
_transitioning = postNumber > 1;
schedule("afterRender", () => {
let elementId;
let holder;
if (opts.jumpEnd) {
let $holder = $(holderId);
let holderHeight = $holder.height();
@ -125,27 +129,35 @@ const DiscourseURL = EmberObject.extend({
return;
}
let selector;
let holder;
if (opts.anchor) {
elementId = opts.anchor;
holder = $(elementId);
selector = `#main #${opts.anchor}, a[name=${opts.anchor}]`;
holder = document.querySelector(selector);
}
if (!holder || holder.length === 0) {
elementId = holderId;
holder = $(elementId);
if (!holder) {
selector = holderId;
holder = document.querySelector(selector);
}
const lockon = new LockOn(elementId, {
if (lockon) {
lockon.clearLock();
}
lockon = new LockOn(selector, {
finished() {
_transitioning = false;
lockon = null;
}
});
if (holder.length > 0 && opts && opts.skipIfOnScreen) {
if (holder && opts.skipIfOnScreen) {
const elementTop = lockon.elementTop();
const scrollTop = $(window).scrollTop();
const windowHeight = $(window).height() - offsetCalculator();
const height = holder.height();
const height = $(holder).height();
if (
elementTop > scrollTop &&
@ -377,9 +389,9 @@ const DiscourseURL = EmberObject.extend({
jumpEnd: routeOpts.jumpEnd
};
const m = /#.+$/.exec(path);
if (m) {
jumpOpts.anchor = m[0];
const anchorMatch = /#(.+)$/.exec(path);
if (anchorMatch) {
jumpOpts.anchor = anchorMatch[1];
}
this.jumpToPost(closest, jumpOpts);

View File

@ -2,14 +2,16 @@ import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax";
export default DiscourseRoute.extend({
beforeModel({ params }) {
beforeModel({ params, _discourse_anchor }) {
return ajax(`/p/${params.post.id}`).then(t => {
this.transitionTo(
const transition = this.transitionTo(
"topic.fromParamsNear",
t.slug,
t.id,
t.current_post_number
);
transition._discourse_anchor = _discourse_anchor;
});
}
});

View File

@ -17,7 +17,7 @@ export default DiscourseRoute.extend({
this.controllerFor("topic").unsubscribe();
},
setupController(controller, params) {
setupController(controller, params, { _discourse_anchor }) {
params = params || {};
params.track_visit = true;
@ -65,8 +65,10 @@ export default DiscourseRoute.extend({
);
const opts = {};
if (document.location.hash && document.location.hash.length) {
opts.anchor = document.location.hash;
if (document.location.hash) {
opts.anchor = document.location.hash.substr(1);
} else if (_discourse_anchor) {
opts.anchor = _discourse_anchor;
}
DiscourseURL.jumpToPost(closest, opts);