'home/utils/layoutUtils',
'Router',
'jquery',
'modernizr',
'backbone',
'backbone-marionette',
'home/templates/preload',
'home/views/MainLayout',
'home/views/HomepageView',
'home/views/ActivityFeedView',
'home/views/NotificationsView',
'home/views/NotificationsLoggedOutView',
'home/views/ForumProfileView',
'home/views/ProfileView',
'home/views/DiscussionCreateView',
'home/views/DiscussionPageView',
'home/views/WelcomeView',
'home/views/ChannelProfileView',
'home/views/SettingsLayout',
'home/views/ChannelsView',
'home/views/ExploreView',
'home/views/OnboardingView',
'home/viewmodels/DiscussionCreateViewModel',
'home/viewmodels/ChannelsViewModel',
'home/viewmodels/DiscussionViewModel',
'home/collections/common/ExtensibleCollection',
'home/collections/ChannelCollection',
'home/models/Session',
'core/UniqueModel',
'home/models/UserProfile',
'home/models/Thread',
'home/models/Forum',
'home/models/Channel',
'home/models/ChannelProfile',
'home/models/ForumProfile',
'home/models/HomepageProfile',
'home/models/ExploreViewModel',
'home/utils/navigationUtils',
'home/utils/trackingUtils',
'core/utils/auth',
'core/utils/url/parseQueryString',
'core/api',
'core/engagement/page',
'core/strings',
'core/switches',
'remote/config',
'core/config/urls',
'bootstrap/tooltip',
'bootstrap/modal',
'bootstrap/collapse',
'jquery.trunk8',
'home/overrides/marionette.overrides',
'disqus.sdk', // needed to load the embed on Discussion pages
], function (
layoutUtils,
Router,
$,
Modernizr,
Backbone,
Marionette,
preloadTemplate,
MainLayout,
HomepageView,
AnonHomepageView,
NotificationsView,
NotificationsLoggedOutView,
ForumProfileView,
ProfileView,
DiscussionCreateView,
DiscussionPageView,
WelcomeView,
ChannelProfileView,
SettingsLayout,
ChannelsView,
ExploreView,
OnboardingView,
DiscussionCreateViewModel,
ChannelsViewModel,
DiscussionViewModel,
ExtensibleCollection,
ChannelCollection,
Session,
$,
Backbone,
asEmbedApp,
sidebarUtils,
navigationUtils
UserProfile,
Thread,
Forum,
Channel,
ChannelProfile,
ForumProfile,
HomepageProfile,
ExploreViewModel,
NavigationUtils,
TrackingUtils,
auth,
parseQueryString,
api,
pageEngagement,
strings,
switches,
remoteConfig,
urls
) {
'use strict';
var
/* eslint-disable no-unused-expressions */
// This line causes the grunt task to add the Modernizr Touch test
// which in turn causes Modernizr to add a css class touch/no-touch
// to the <html> tag
Modernizr.touch;
// Add flexbox/no-flexbox detection for IE9
Modernizr.flexbox;
/* eslint-disable no-unused-expressions */
// TODO: move this to jesterUtils
var logStatsD = function
require(['fixtures/fixtures'], callback);
else
callback();
};
* Backwards compatibility layer
var Router = Backbone.Router.extend({
name: 'home',
routes: {
'home/discuss/:forum(/)': 'startDiscussion',
'home/edit/:forum/:thread(/)': 'editDiscussion',
'home/search(/)': 'search',
'home/user(s)(/:username)(/:feed)(/)': 'profile',
'home/user(s)/(:username)(/:feed)(/:subfeed)(/)': 'profile',
'by/:username(/:feed)(/)': 'profile',
'by/:username(/:feed)(/:subfeed)(/)': 'profile',
'home/inbox(/:feed)(/)': 'inbox',
'home/preload(/)': 'preload',
'home/account(/)': 'account',
'home/notifications(/)': 'notifications',
'home/topic(s)/:topicId(/)': 'topics',
'home/forum(s)/:forumId(/:feed)(/)': 'forums',
'home/discussion(s)/:forum/:thread(/:activeTab)(/:permalink)(/)': 'discussion',
'home/ndiscussion(s)/:forum/:thread(/:activeTab)(/:permalink)(/)': 'nativeDiscussion',
'home/follow/channel(s)/:channelId(/)': 'followChannel',
'home/channel(s)(/)': 'channelsPage',
'home/channel(s)/:channelId(/:feed)(/)': 'channels',
'home/channel(s)/:channelId/topics/:topic(/)': 'channelTopics',
'home/channel(s)/:channelId/discussion(s)/:forumId/:thread(/:activeTab)(/:permalink)(/)': 'channelDiscussion',
'home/channel(s)/:channelId/ndiscussion(s)/:forumId/:thread(/:activeTab)(/:permalink)(/)': 'nativeChannelDiscussion',
'home/settings(/:section)/': 'settings',
// TODO: remove this once nowhere in disqus-web is directing users to
// (specifically after email verification, possibly other places)
// Note: also remove 'discover' route handler in trackingUtils zone names
'home/discover(/)': 'channelsPage',
'home/explore(/)': 'explore',
'home/explore/:activeTab(/)': 'explore',
'home/explore/channels/:channelId(/:activeTab)(/)': 'exploreChannel',
'home/explore/discussions/:channelId(/)': 'exploreDiscussions',
// This must remain as the last item so that it doesn't match this router when
// it should match something more specific (ex: home/inbox/)
'home(/:feed)(/)': 'home',
},
initialize: function (options) {
this.CDN_ROOT = options.CDN_ROOT;
this.feeds = {};
this.listenTo(this, 'route', this.handleRouteChange);
this.listenTo(this, 'route', this.logRouteChange);
this.messages = [];
this.onboardingWithoutChannels = switches.isFeatureActive('onboarding_without_channels');
},
/*
*
* sequence of initialization steps.
*/
bootstrap: function () {
this.initSession();
this.initTracking();
this.initPageEngagementTracking();
this.initLinkHandling();
this.initMainLayout();
},
initTracking: function () {
TrackingUtils.init();
TrackingUtils.trackVisit();
},
initLinkHandling: function () {
$('body').on('click', 'a[href]', _.bind(NavigationUtils.handleLinkClicks, NavigationUtils));
},
initSession: function () {
var session = this.session = Session.get();
session.load();
session.loadPromise().then(_.bind(function () {
if (window.Raven) {
window.Raven.setUser({
id: session.user.get('id'),
username: session.user.get('username'),
});
}
this.loadModeratedForums();
}, this));
session.loadPromise().fail(function () {
var provider = session.provider();
// If we know the session provider and we are rejecting the
// session authentication anyway, then there was something wrong
// with our disqusauth cookie (or the user is an "SSO" publisher account).
if (provider) // don't log all the random provider domains, just do 'remote' instead
logStatsD('home.session.rejected.' + (provider === 'disqus' ? 'disqus' : 'remote'));
});
this.initUserProfile();
return session;
},
initMainLayout: function () {
this.layout = new MainLayout({
container: 'body',
session: this.session,
app: this,
});
// We do not render here because rendering kicks off the creation of
// certain subviews (e.g.,
*/
function transitionUrl() {
var location = window.location;
// If we are at the /home/ prefix and we happen to also have a
// hash
// direct the user to that route instead of just going to /home/.
// NOTE: this hash routing feature is only to support a few legacy
// urls like disqus.com/home/#account.
if (location.hash.length > 1 && (location.pathname === '/home' || location.pathname === '/home/')) {
// Construct a new location object that contains the hash's route
// as well as search params, etc.
var loc = {
pathname: '/home/' + location.hash.slice(1).replace(/^\//, ''),
search: location.search,
hash: '',
host: location.host,
};
if (navigationUtils.matchesRoute(loc))
return navigationUtils.navigate(loc, true);
}
return
}
// having been called, which does not occur until after app.bootstrap.
// And we cannot init the MainLayout AFTER History.start because History.start
// will trigger a route that relies on MainLayout existing. And we cannot
// hook into the route event because that is fired after the route handler
// has been executed.
},
/*
* Returns the view currently showing in the main content area of the page.
* Useful for anything external to the content view (ex: NavView) to get
* the current view/model being shown.
*/
getCurrentView: function () {
return
_init:
},
initPageEngagementTracking: function () {
pageEngagement.start();
},
/*
* When the asEmbedApp mixin is applied, loadModeratedForums is only called
* when the 'showPath' message is received via the FrameBus.
*/
loadModeratedForums: function () {
this.session.loadModeratedForums();
},
logRouteChange: function (route) {
// Log the page view to 'events.*.route.<page path>'
logStatsD(this.name + '.route.' + route);
},
/*
* When the asEmbedApp mixin is applied, initUserProfile is only called when
* the 'showPath' message is received via the FrameBus.
*/
initUserProfile: function () {
var username = Session.fromCookie().username;
if (username) {
// It appears the user is logged in. Fetch all the necessary user details
// asynchronously using the username from the auth cookie.
// (If the user turns out to be not logged in, or session expired, it'll be
// handled on api response)
this.session.initUserProfile(username);
} else {
// If we can't get the username from the cookie, wait until users/details
// returns and then fetch the rest of the user details using the fetched username
this.session.once('change:id', function (user) {
this.session.initUserProfile(user.get('username'));
}, this);
}
},
/*
* Inherits + overrides parent .execute method
* Handle pre-view setup and post-view cleanup before executing a route handler.
*/
execute: function () {
// Before showing a new view remove the logged-in requirement handling that may have been
// added for the previous view.
api.off('error', NavigationUtils.navigateToLoginOnAuthFail);
TrackingUtils.pageChanged();
Backbone.Router.prototype.execute.apply(this, arguments);
},
ensureAuthenticated: function (callback) {
// Reset the api 'error' handler so we don't bind this
// more than necessary.
api.off('error', NavigationUtils.navigateToLoginOnAuthFail);
if (Session.isKnownToBeLoggedOut())
return NavigationUtils.navigateToLogin();
// If we expect the user to be logged in, but we make
// an API call that returns an error, we should direct the
// user to the login page.
api.on('error', NavigationUtils.navigateToLoginOnAuthFail);
// Ensure the session is fetched. Once it is, call the
// callback. If fetch fails, prompt user to login
this.session.loadPromise().then(
_.bind(callback, this, _.tail(arguments)),
NavigationUtils.navigateToLogin
);
},
navigateToLandingPage: function (options) {
// Start
app.bootstrap();
// overwrite tooltip support so
},
/*
* Ensures that logged in users are redirected to onboarding step 1 if
* they
*/
ensureOnboardingComplete: function (callback) {
// TODO: @taylangocmen once channels is removed kill this onboarding flow
if
$.fn.tooltip = $.noop;
window.DISQUS = window.DISQUS
window.DISQUS.home = {
app: app,
};
// Wait for fixtures to initialize (for dev) before beginning navigation
initFixtures(function
return callback.apply(this);
this.session.loadPromise().always(_.bind(function () {
pushState: true,
hashChange: false,
root: config.appRoot,
// Defer this so that the current route event is triggered before navigating to the 1st step of
// onboarding. Not deferring it will result in route events being triggered in the wrong order.
_.defer(this.navigateToOnboarding);
else
callback.apply(this);
}, this));
},
navigateToOnboarding: function () {
var welcomeRoute = 'home/explore/';
var params = parseQueryString();
var toKeep = {};
// Retain certain params for use later.
// Only retain them if given truthy values, so that checks later
// for these params can skip value check and only check existence.
if (params.email_verified)
toKeep.email_verified = params.email_verified;
if (params.forum_id)
toKeep.forum_id = params.forum_id;
if (_.size(toKeep))
welcomeRoute += '?' + $.param(toKeep);
NavigationUtils.navigate(welcomeRoute, { trigger: true, replace: true });
},
/*
* Verifies the forum with the given id has a channel and that
* this user can create on that channel.
*/
ensureCanCreateOnChannel: function (callback, forumId) {
var forum = new UniqueModel(Forum, {
id: forumId,
});
// If forum hasn't been fetched yet, wait until fetching is complete
// and then re-call this function
if (forum.shouldFetch()) {
forum.fetch();
this.listenToOnce(forum, 'sync', _.bind.apply(_, [this.ensureCanCreateOnChannel, this].concat(_.toArray(arguments))));
return;
}
// If the forum is not the primary forum for a channel, or if the
// current user does not have create permissions for the channel,
// redirect to an error page.
if ((!forum.channel && forumId !== 'gabalafou-test') ||
!forum.channel.userCanCreate(this.session.user))
// TODO: this should redirect to a page with a message like:
// "You do not have permission to view this page"
return this.notFound();
// The forum has a channel. Call the callback.
callback.apply(this, _.tail(arguments));
},
/**
* Listens for a tabbed view in case it throws a badTab event. If that occurs,
* rewrites the url to the given route silently. It's expected that the tabbed
* view will handle the event gracefully.
*
* @param {tabbedView} tabbedView - A view instance that triggers a badTab event
* in the case that an invalid tab is navigated
* to, as TabbedView does.
* @param {string} redirectRoute - The route to rewrite if the tab is not supported
*/
ensureTab: function (tabbedView, redirectRoute) {
tabbedView.listenTo(tabbedView, 'badTab', function () {
NavigationUtils.navigate(redirectRoute, { silent:
});
// If we don't have a matching route, call notFound
if (!transitionUrl())
app.notFound();
});
},
window.top.location = 'https://help.disqus.com/customer/portal/articles/1689402-redirected-from-home';
},
preload: function () {
this.preloadView = new (Marionette.ItemView.extend({ template: preloadTemplate }))();
this.layout.showView(this.preloadView);
},
/*
* Append a trailing slash to the current route if it
* doesn't have one.
*
* Saves the current and previous route names as properties so it can
* be used by the NavView.
*/
handleRouteChange: function (routeName) {
this.setCurrentRouteName(routeName);
NavigationUtils.coerceTrailingSlash(window.location);
},
setCurrentRouteName: function (routeName) {
this._previousRouteName = this.getCurrentRouteName();
this._currentRouteName = routeName;
},
getCurrentRouteName: function () {
return this._currentRouteName;
},
getPreviousRouteName: function () {
return this._previousRouteName;
},
onboarding: function () {
return this.ensureAuthenticated(function () {
this.layout.showView(new WelcomeView({ session: this.session }), { lightBackground: true });
});
},
_explore: function (options) {
this.session.loadPromise()
.always(Function.bind.call(function () {
var showOnboarding = this.session.isLoggedIn() && this.session.user.shouldHomeOnboard();
if (showOnboarding) {
options.collection = new ChannelCollection([], { listName: 'explore' });
this.layout.showView(new OnboardingView(options));
} else {
options.model = new ExploreViewModel();
this.layout.showView(new ExploreView(options));
}
}, this));
},
explore: function () {
return this.navigateToLandingPage({ replace: true });
},
exploreChannel: function () {
return this.navigateToLandingPage({ replace: true });
},
exploreDiscussions: function () {
return this.navigateToLandingPage({ replace: true });
},
// When user goes to /user, take them to /user/<username>
renavigateToProfile: function (user) {
var username = user.get('username');
// Prevent potential infinite loop
// .profile() -> .renavigateToProfile() -> .profile() -> ...
// (happens when username never gets set to truthy value)
if (!username) {
this.navigateToLandingPage({ replace: true });
return void this.home();
}
NavigationUtils.navigate('/by/' + username + '/', {
replace: true,
});
this.profile(username);
},
settings: function (section) {
return this.ensureAuthenticated(function () {
this.layout.showView(new SettingsLayout({
session: this.session,
activeTab: section,
onboardingWithoutChannels: this.onboardingWithoutChannels,
}));
});
},
channelsPage: function () {
// remove everything but discussdisqus
// Channels page shows channels followed/managed by the authenticated user.
// Don't allow anon users to visit the page.
if (Session.isKnownToBeLoggedOut()) {
NavigationUtils.navigate('/', { replace: true });
return this.home();
}
this.ensureOnboardingComplete(function () {
var model = new UniqueModel(ChannelsViewModel, { id: 'discover-view-model' });
model.ensureFetched();
this.layout.showView(new ChannelsView({
model: model,
onboardingWithoutChannels: this.onboardingWithoutChannels,
}));
});
},
search: function () {
return this.navigateToLandingPage({ replace: true });
},
profile: function (username, feedName, subFeedName) {
// If we get here and we aren't on the /by/ profile path,
// then rewrite the URL to be correct. NavigationUtils knows
// how to rewrite the home/user URL correctly, so just pass the
// task off to there.
if (window.location.pathname.indexOf('home/user') !== -1)
NavigationUtils.navigate(window.location, { replace: true, silent: true });
if (!username) {
return this.ensureAuthenticated(function () {
var session = this.session;
var sessionUser = session.user;
if (!sessionUser.get('username'))
return void this.listenToOnce(session, 'change:id', this.renavigateToProfile);
return void this.renavigateToProfile(sessionUser);
});
}
var userProfile = _.find(UniqueModel.pool(UserProfile), function (userProfile) {
return userProfile.user.get('username') === username;
});
if (!userProfile)
userProfile = new UniqueModel(UserProfile, { username: username });
userProfile.ensureFetched();
var view = new ProfileView({
model: userProfile,
activeTab: feedName,
subTab: subFeedName,
});
this.ensureTab(view, '/by/' + username + '/');
this.layout.showView(view);
},
home: function (feedName, callback) {
var isKnownToBeLoggedOut = Session.isKnownToBeLoggedOut();
if (isKnownToBeLoggedOut) {
if (parseQueryString().email_verified)
// Always try to login in users who have the email_verified param
// in their url, so we can send them through onboarding if necessary
NavigationUtils.navigateToLogin();
else
// Logged out users who were not sent to home via an email verification
// link should be taken to the main homepage
NavigationUtils.navigateToHomepage();
return;
}
this.ensureOnboardingComplete(function () {
// If we get here and we aren't on the / home page path,
// then rewrite the URL to be correct. NavigationUtils knows
// how to rewrite the /home/ to /.
if (window.location.pathname === '/home/')
NavigationUtils.navigate(window.location, { replace: true, silent: true });
var model, contentView;
if (isKnownToBeLoggedOut) {
var exploreChannelCollection = new ChannelCollection([], {
listName: 'explore',
});
exploreChannelCollection.ensureFetched();
contentView = new AnonHomepageView({
collection: exploreChannelCollection,
});
this.layout.showView(contentView, { lightBackground: true });
} else {
model = new UniqueModel(HomepageProfile, { id: 'home-view-model' });
model.ensureFetched();
contentView = new HomepageView({
model: model,
activeTab: feedName,
onboardingWithoutChannels: this.onboardingWithoutChannels,
});
this.ensureTab(contentView, '/');
this.layout.showView(contentView);
}
// Check that callback is a function before calling.
// This is necessary since `home` is called by the router,
// which may pass a query string as an argument.
if (_.isFunction(callback))
callback();
this.cleanLocalStorage();
});
},
// Previously the Home feed view used local storage to determine whether
// or not to show a banner message to the user. With the removal of those
// banner views we can clean up local storage that they were using.
cleanLocalStorage: function () {
if (!localStorageSupported)
return;
try {
window.localStorage.removeItem('dhome_v2oo');
window.localStorage.removeItem('whatsNewViewsRemaining');
window.localStorage.removeItem('v2SwitchoverViewsRemaining');
} catch (err) {
/* pass */
}
},
account: function () {
return NavigationUtils.navigate('/home/settings/account/', { trigger: true, replace: true });
},
notifications: function () {
return NavigationUtils.navigate('/home/settings/email/', { trigger: true, replace: true });
},
ensureAdmin: function (routeHandler, args) {
var session = this.session;
// If we got here but the session hasn't been
// fetched, fetch the session first, and then try again
if (!session.fetched) {
return void session.fetch().then(
_.bind(this.ensureAdmin, this, routeHandler, args),
_.bind(this.notFound, this));
}
// Checks if session user is a global admin, and
// checks Jones config for any additional accounts
if (!auth.getFromCookie().staff)
return this.notFound();
return routeHandler.apply(this, args);
},
followChannel: function (channelId) {
if (channelId === 'disqusfun')
return this.ensureAdmin(this._followChannel, arguments);
return this._followChannel.apply(this, arguments);
},
_followChannel: function (channelId) {
// Follow action will fail and prompt user to log in, so check first, before
// replacing the url, so that the login page will have the correct return url
this.ensureAuthenticated(function () {
var channel = new UniqueModel(Channel, { slug: channelId });
if (channel.primaryForum && !channel.primaryForum.get('isFollowing')) {
channel.primaryForum.follow();
} else {
this.listenToOnce(channel, 'changeRelated:primaryForum', function () {
if (!channel.primaryForum.get('isFollowing'))
channel.primaryForum.follow();
});
}
NavigationUtils.navigate('/home/channel/' + channelId + '/', { trigger: true, replace: true });
});
},
channels: function (channelId) {
if (channelId !== 'discussdisqus')
return this.navigateToLandingPage({ replace: true });
if (channelId === 'disqusfun' || channelId === 'gabalafou-test')
return this.ensureAdmin(this._channels, arguments);
return this._channels.apply(this, arguments);
},
channelTopics: function (channelId, topicName) {
if (channelId !== 'discussdisqus')
return this.navigateToLandingPage({ replace: true });
return this.channels(channelId, 'topic-' + topicName);
},
_channels: function (channelId, feedName) {
var channelProfile = new UniqueModel(
ChannelProfile,
{
id: channelId, // must have id for UniqueModel
channel: channelId,
}
);
channelProfile.ensureFetched();
var contentView = new ChannelProfileView({
model: channelProfile,
activeTab: feedName,
});
this.ensureTab(contentView, 'home/channel/' + channelId + '/');
this.layout.showView(contentView);
},
_forums: function (forumId, feedName) {
var forumProfile = new UniqueModel(
ForumProfile,
{
id: forumId,
}
);
var forum = forumProfile.forum;
var self = this;
// If this is the primary forum for a channel, redirect to the channel page
if
asEmbedApp(Router.prototype, Session.prototype);
$(function
NavigationUtils.navigate('/home/channel/' + forum.channel.id + '/', { trigger: true, replace: true });
return;
}
forum.fetch().then(function () {
if (forum.channel)
self.
}, this.notFound);
forumProfile.ensureFetched();
var view = new ForumProfileView({
model: forumProfile,
activeTab: feedName,
onboardingWithoutChannels: this.onboardingWithoutChannels,
});
this.layout.showView(view);
},
forums: function (forumId) {
this.preventBlacklisted({ forum: forumId });
if (forumId === 'disqus-disqusfun')
return this.ensureAdmin(this._forums, arguments);
return this._forums.apply(this, arguments);
},
topics: function () {
return this.navigateToLandingPage({ replace: true });
},
inbox: function (feedName) {
var view;
var notifications = this.session.getOrCreateNotifications();
// Kick off fetch(es) for items needed on the notifications view.
// Notifications and counters will have already been fetched by
// the Nav bar
notifications.ensureFetchedRecommendations();
// If the user isn't logged in via Disqus or an SSO account (via embed sidebar), show the logged out
// notifications inbox.
if (!this.isSSOAuthenticated && Session.isKnownToBeLoggedOut()) {
view = new NotificationsLoggedOutView({
model: notifications,
onboardingWithoutChannels: this.onboardingWithoutChannels,
});
} else {
if (window.location.search.indexOf('email_verified') > -1) {
var message = strings.interpolate(
gettext('Your email\'s verified! Have a look around -- %(Disqus)s is a lot more than comments'),
{ Disqus: 'Disqus' }
);
this.messages.push({ message: message });
}
view = new NotificationsView({
model: notifications,
activeTab: feedName,
disableMOTD: this.disableMOTD,
onboardingWithoutChannels: this.onboardingWithoutChannels,
});
}
this.ensureTab(view, '/home/inbox/');
this.layout.showView(view);
},
_showDiscussionForm: function (forumId, options) {
var discussionForm = new DiscussionCreateView({
session: this.session,
model: new DiscussionCreateViewModel({}, _.extend({ forum: forumId }, options)),
});
this.listenTo(discussionForm, 'createThread', function () {
var thread = discussionForm.getThread();
// Add the recently created thread to an extensible collection so that embedly
// requests (if any) will be made before showing the newly created discussion.
new ExtensibleCollection().add(thread);
NavigationUtils.navigate(thread.getDiscussionRoute(), {
trigger: true,
});
});
this.listenTo(discussionForm, 'cancelThread', function () {
NavigationUtils.navigate('home/' + discussionForm.getForum().getForumRoute(), {
trigger: true,
});
});
this.layout.showView(discussionForm);
},
startDiscussion: function (forumId) {
// return if a non discussdisqus channel
if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
return this.navigateToLandingPage({ replace: true });
// Must be logged in and on the primary forum for a channel in order to create a discussion
return this.ensureAuthenticated(function () {
this.ensureCanCreateOnChannel(function () {
this._showDiscussionForm.apply(this, arguments);
}, forumId);
}, arguments);
},
editDiscussion: function (forumId, threadSlug) {
// return if a non discussdisqus channel
if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
return this.navigateToLandingPage({ replace: true });
var session = this.session;
var thread = Thread.getOrCreateThread(forumId, threadSlug);
var fetchPromises = [thread.getEditPermissions(session)];
// If we got here but the session hasn't been
// fetched, fetch the session first, and then try again
if (thread.shouldFetch())
fetchPromises.push(thread.fetch());
return $.when.apply($, fetchPromises).then(
_.bind(function (canEdit) {
if (canEdit)
return this._showDiscussionForm(forumId, { thread: thread });
return void NavigationUtils.navigate(thread.getDiscussionRoute(),
{ trigger: true, replace: true });
}, this),
_.bind(this.notFound, this)
);
},
discussionPage: function (forumId, threadSlug, activeTab, options) {
options = options || {};
var thread = Thread.getOrCreateThread(forumId, threadSlug, options.threadFetchOptions);
var model = DiscussionViewModel.getOrCreate({}, {
channel: options.channel,
thread: thread,
});
var discussionPage = new DiscussionPageView(_.extend({
model: model,
session: this.session,
activeTab: activeTab,
app: this,
}, options));
this.layout.showView(discussionPage, { lightBackground: true });
},
_discussion: function (forumId, threadSlug, activeTab, options) {
this.preventBlacklisted({ forum: forumId });
if (forumId === 'disqus-disqusfun')
return this.ensureAdmin(this.discussionPage, [forumId, threadSlug, activeTab, options]);
return this.discussionPage(forumId, threadSlug, activeTab, options);
},
discussion: function (forumId, threadSlug, activeTab) {
if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
return this.navigateToLandingPage({ replace: true });
return this._discussion(forumId, threadSlug, activeTab);
},
channelDiscussion: function (channelId, forumId, threadSlug, activeTab, options) {
if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
return this.navigateToLandingPage({ replace: true });
options = options || {};
var channel = new UniqueModel(Channel, { slug: channelId });
// Must fetch this for network threads linked through a channel.
// User generated threads will end up fetching this again as
// part of the forum fetch, but network threads won't, and they
// need channel details for this view.
if (channel.shouldFetch())
channel.fetch();
return this._discussion(forumId, threadSlug, activeTab, {
channel: channel,
threadFetchOptions: {
data: {
related: ['author'],
},
},
noEmbed: options.noEmbed,
});
},
// Native = no embed, iframe-less comments section
nativeDiscussion: function (forumId, threadId, activeTab) {
if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
return this.navigateToLandingPage({ replace: true });
return this._discussion(forumId, threadId, activeTab, {
noEmbed: true,
});
},
// Native = no embed, iframe-less comments section
nativeChannelDiscussion: function (channelId, forumId, threadSlug, activeTab) {
if (channelId !== 'discussdisqus')
return this.navigateToLandingPage({ replace: true });
return this.channelDiscussion(channelId, forumId, threadSlug, activeTab, {
noEmbed: true,
});
},
notFound: NavigationUtils.notFoundRouteHandler,
});
return Router;
});
// https://c.disquscdn.