Files
discourse/app/assets/javascripts/discourse/components/discourse-topic.js.es6
Roman Rizzi 77931b70c3 Revert "DEV: Upgrade to Ember 3.7.0 (#6977)" (#7165)
This reverts commit 3eebf8be733065996ff172adbcad85c254048274.
2019-03-13 15:49:47 -03:00

218 lines
6.5 KiB
JavaScript

import DiscourseURL from "discourse/lib/url";
import AddArchetypeClass from "discourse/mixins/add-archetype-class";
import ClickTrack from "discourse/lib/click-track";
import Scrolling from "discourse/mixins/scrolling";
import { selectedText } from "discourse/lib/utilities";
import { observes } from "ember-addons/ember-computed-decorators";
function highlight(postNumber) {
const $contents = $(`#post_${postNumber} .topic-body`);
$contents.addClass("highlighted");
$contents.on("animationend", () => $contents.removeClass("highlighted"));
}
// used to determine scroll direction on mobile
let lastScroll, scrollDirection, delta;
export default Ember.Component.extend(AddArchetypeClass, Scrolling, {
userFilters: Ember.computed.alias("topic.userFilters"),
classNameBindings: [
"multiSelect",
"topic.archetype",
"topic.is_warning",
"topic.category.read_restricted:read_restricted",
"topic.deleted:deleted-topic",
"topic.categoryClass"
],
menuVisible: true,
SHORT_POST: 1200,
postStream: Ember.computed.alias("topic.postStream"),
archetype: Ember.computed.alias("topic.archetype"),
dockAt: 0,
_lastShowTopic: null,
@observes("enteredAt")
_enteredTopic() {
// Ember is supposed to only call observers when values change but something
// in our view set up is firing this observer with the same value. This check
// prevents scrolled from being called twice.
const enteredAt = this.get("enteredAt");
if (enteredAt && this.get("lastEnteredAt") !== enteredAt) {
this._lastShowTopic = null;
Ember.run.schedule("afterRender", () => this.scrolled());
this.set("lastEnteredAt", enteredAt);
}
},
didInsertElement() {
this._super(...arguments);
this.bindScrolling({ name: "topic-view" });
$(window).on("resize.discourse-on-scroll", () => this.scrolled());
this.$().on(
"mouseup.discourse-redirect",
".cooked a, a.track-link",
function(e) {
// bypass if we are selecting stuff
const selection = window.getSelection && window.getSelection();
if (selection.type === "Range" || selection.rangeCount > 0) {
if (selectedText() !== "") {
return true;
}
}
const $target = $(e.target);
if (
$target.hasClass("mention") ||
$target.parents(".expanded-embed").length
) {
return false;
}
return ClickTrack.trackClick(e);
}
);
this.appEvents.on("post:highlight", postNumber => {
Ember.run.scheduleOnce("afterRender", null, highlight, postNumber);
});
this.appEvents.on("header:update-topic", topic => {
if (topic === null) {
this._lastShowTopic = false;
this.appEvents.trigger("header:hide-topic");
return;
}
const offset = window.pageYOffset || $("html").scrollTop();
this._lastShowTopic = this.showTopicInHeader(topic, offset);
if (this._lastShowTopic) {
this.appEvents.trigger("header:show-topic", topic);
} else {
this.appEvents.trigger("header:hide-topic");
}
});
// setup mobile scroll logo
if (this.site.mobileView) {
this.appEvents.on("topic:scrolled", offset =>
this.mobileScrollGaurd(offset)
);
// used to animate header contents on scroll
this.appEvents.on("header:show-topic", () => {
$("header.d-header")
.removeClass("scroll-up")
.addClass("scroll-down");
});
this.appEvents.on("header:hide-topic", () => {
$("header.d-header")
.removeClass("scroll-down")
.addClass("scroll-up");
});
}
},
willDestroyElement() {
this._super(...arguments);
this.unbindScrolling("topic-view");
$(window).unbind("resize.discourse-on-scroll");
// Unbind link tracking
this.$().off("mouseup.discourse-redirect", ".cooked a, a.track-link");
this.resetExamineDockCache();
// this happens after route exit, stuff could have trickled in
this.appEvents.trigger("header:hide-topic");
this.appEvents.off("post:highlight");
// mobile scroll logo clean up.
if (this.site.mobileView) {
this.appEvents.off("topic:scrolled");
$("header.d-header").removeClass("scroll-down scroll-up");
}
},
@observes("Discourse.hasFocus")
gotFocus() {
if (Discourse.get("hasFocus")) {
this.scrolled();
}
},
resetExamineDockCache() {
this.set("dockAt", 0);
},
showTopicInHeader(topic, offset) {
// conditions for showing topic title in the header for mobile
if (
this.site.mobileView &&
scrollDirection !== "up" &&
offset > this.dockAt
) {
return true;
// condition for desktops
} else {
return offset > this.dockAt;
}
},
// The user has scrolled the window, or it is finished rendering and ready for processing.
scrolled() {
if (this.isDestroyed || this.isDestroying || this._state !== "inDOM") {
return;
}
const offset = window.pageYOffset || $("html").scrollTop();
if (this.get("dockAt") === 0) {
const title = $("#topic-title");
if (title && title.length === 1) {
this.set("dockAt", title.offset().top);
}
}
this.set("hasScrolled", offset > 0);
const topic = this.get("topic");
const showTopic = this.showTopicInHeader(topic, offset);
if (showTopic !== this._lastShowTopic) {
if (showTopic) {
this.appEvents.trigger("header:show-topic", topic);
this._lastShowTopic = true;
} else {
if (!DiscourseURL.isJumpScheduled()) {
const loadingNear = topic.get("postStream.loadingNearPost") || 1;
if (loadingNear === 1) {
this.appEvents.trigger("header:hide-topic");
this._lastShowTopic = false;
}
}
}
}
// Trigger a scrolled event
this.appEvents.trigger("topic:scrolled", offset);
},
// determines scroll direction, triggers header topic info on mobile
// and ensures that the switch happens only once per scroll direction change
mobileScrollGaurd(offset) {
// user hasn't scrolled past topic title.
if (offset < this.dockAt) return;
delta = offset - lastScroll;
// 3px buffer so that the switch doesn't happen with tiny scrolls
if (delta > 3 && scrollDirection !== "down") {
scrollDirection = "down";
this.appEvents.trigger("header:show-topic", this.topic);
} else if (delta < -3 && scrollDirection !== "up") {
scrollDirection = "up";
this.appEvents.trigger("header:hide-topic");
}
lastScroll = offset;
}
});