This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/routes/topic.js.es6
Sam 6ddd8d9166 FIX: when entering topics "tracking" would not be set
There was a timing issue when subscribing to messages for topics.

Old flow:

- We generate JSON for topic
- We subscribe to messages for topic

New flow:

- We keep track of last id in the topic message bus channel
- We generate JSON
- We subscribe to messages for topic starting at saved message id

This ensures that there is complete overlap for message consumption
and that there are no cases where an update may go missing due to timing
2017-05-16 15:04:21 -04:00

227 lines
6.7 KiB
JavaScript

import DiscourseURL from 'discourse/lib/url';
let isTransitioning = false,
scheduledReplace = null,
lastScrollPos = null;
const SCROLL_DELAY = 500;
import showModal from 'discourse/lib/show-modal';
const TopicRoute = Discourse.Route.extend({
redirect() { return this.redirectIfLoginRequired(); },
queryParams: {
filter: { replace: true },
username_filters: { replace: true },
},
titleToken() {
const model = this.modelFor('topic');
if (model) {
const result = model.get('unicode_title') ? model.get('unicode_title') : model.get('title'),
cat = model.get('category');
// Only display uncategorized in the title tag if it was renamed
if (cat && !(cat.get('isUncategorizedCategory') && cat.get('name').toLowerCase() === "uncategorized")) {
let catName = cat.get('name');
const parentCategory = cat.get('parentCategory');
if (parentCategory) {
catName = parentCategory.get('name') + " / " + catName;
}
return [result, catName];
}
return result;
}
},
actions: {
showFlags(model) {
showModal('flag', { model });
this.controllerFor('flag').setProperties({ selected: null, flagTopic: false });
},
showFlagTopic() {
const model = this.modelFor('topic');
showModal('flag', { model });
this.controllerFor('flag').setProperties({ selected: null, flagTopic: true });
},
showTopicStatusUpdate() {
const model = this.modelFor('topic');
model.set('topic_timer', Ember.Object.create(model.get('topic_timer')));
showModal('edit-topic-timer', { model });
this.controllerFor('modal').set('modalClass', 'edit-topic-timer-modal');
},
showChangeTimestamp() {
showModal('change-timestamp', { model: this.modelFor('topic'), title: 'topic.change_timestamp.title' });
},
showFeatureTopic() {
showModal('featureTopic', { model: this.modelFor('topic'), title: 'topic.feature_topic.title' });
this.controllerFor('modal').set('modalClass', 'feature-topic-modal');
this.controllerFor('feature_topic').reset();
},
showInvite() {
showModal('invite', { model: this.modelFor('topic') });
this.controllerFor('invite').reset();
},
showHistory(model) {
showModal('history', { model });
const historyController = this.controllerFor('history');
historyController.refresh(model.get("id"), "latest");
historyController.set('post', model);
historyController.set('topicController', this.controllerFor('topic'));
this.controllerFor('modal').set('modalClass', 'history-modal');
},
showRawEmail(model) {
showModal('raw-email', { model });
this.controllerFor('raw_email').loadRawEmail(model.get("id"));
},
mergeTopic() {
showModal('merge-topic', { model: this.modelFor('topic'), title: 'topic.merge_topic.title' });
},
splitTopic() {
showModal('split-topic', { model: this.modelFor('topic') });
},
changeOwner() {
showModal('change-owner', { model: this.modelFor('topic'), title: 'topic.change_owner.title' });
},
// Use replaceState to update the URL once it changes
postChangedRoute(currentPost) {
// do nothing if we are transitioning to another route
if (isTransitioning || TopicRoute.disableReplaceState) { return; }
const topic = this.modelFor('topic');
if (topic && currentPost) {
let postUrl = topic.get('url');
if (currentPost > 1) { postUrl += "/" + currentPost; }
Em.run.cancel(scheduledReplace);
lastScrollPos = parseInt($(document).scrollTop(), 10);
scheduledReplace = Em.run.later(this, '_replaceUnlessScrolling', postUrl, SCROLL_DELAY);
}
},
didTransition() {
this.controllerFor("topic")._showFooter();
return true;
},
willTransition() {
this._super();
Em.run.cancel(scheduledReplace);
isTransitioning = true;
return true;
}
},
// replaceState can be very slow on Android Chrome. This function debounces replaceState
// within a topic until scrolling stops
_replaceUnlessScrolling(url) {
const currentPos = parseInt($(document).scrollTop(), 10);
if (currentPos === lastScrollPos) {
DiscourseURL.replaceState(url);
return;
}
lastScrollPos = currentPos;
scheduledReplace = Em.run.later(this, '_replaceUnlessScrolling', url, SCROLL_DELAY);
},
setupParams(topic, params) {
const postStream = topic.get('postStream');
postStream.set('summary', Em.get(params, 'filter') === 'summary');
const usernames = Em.get(params, 'username_filters'),
userFilters = postStream.get('userFilters');
userFilters.clear();
if (!Em.isEmpty(usernames) && usernames !== 'undefined') {
userFilters.addObjects(usernames.split(','));
}
return topic;
},
model(params, transition) {
const queryParams = transition.queryParams;
let topic = this.modelFor('topic');
if (topic && (topic.get('id') === parseInt(params.id, 10))) {
this.setupParams(topic, queryParams);
return topic;
} else {
topic = this.store.createRecord('topic', _.omit(params, 'username_filters', 'filter'));
return this.setupParams(topic, queryParams);
}
},
activate() {
this._super();
isTransitioning = false;
const topic = this.modelFor('topic');
this.session.set('lastTopicIdViewed', parseInt(topic.get('id'), 10));
},
deactivate() {
this._super();
this.searchService.set('searchContext', null);
this.controllerFor('user-card').set('visible', false);
const topicController = this.controllerFor('topic');
const postStream = topicController.get('model.postStream');
postStream.cancelFilter();
topicController.set('multiSelect', false);
this.controllerFor('composer').set('topic', null);
this.screenTrack.stop();
this.appEvents.trigger('header:hide-topic');
},
setupController(controller, model) {
// In case we navigate from one topic directly to another
isTransitioning = false;
controller.setProperties({
model,
editingTopic: false,
firstPostExpanded: false
});
TopicRoute.trigger('setupTopicController', this);
this.searchService.set('searchContext', model.get('searchContext'));
// close the multi select when switching topics
controller.set('multiSelect', false);
controller.get('quoteState').clear();
this.controllerFor('composer').set('topic', model);
this.topicTrackingState.trackIncoming('all');
// We reset screen tracking every time a topic is entered
this.screenTrack.start(model.get('id'), controller);
}
});
RSVP.EventTarget.mixin(TopicRoute);
export default TopicRoute;