From disqus.com, 3 Weeks ago, written in JavaScript.
This paste is a reply to main.js from disqus.com
- view diff
Embed
  1. define('Router',[  // eslint-disable-line requirejs/amd-function-arity
  2.     'underscore',
  3.     'jquery',
  4.     'modernizr',
  5.     'backbone',
  6.     'backbone-marionette',
  7.  
  8.     'home/templates/preload',
  9.  
  10.     'home/views/MainLayout',
  11.     'home/views/HomepageView',
  12.     'home/views/ActivityFeedView',
  13.     'home/views/NotificationsView',
  14.     'home/views/NotificationsLoggedOutView',
  15.     'home/views/ForumProfileView',
  16.     'home/views/ProfileView',
  17.     'home/views/DiscussionCreateView',
  18.     'home/views/DiscussionPageView',
  19.     'home/views/WelcomeView',
  20.     'home/views/ChannelProfileView',
  21.     'home/views/SettingsLayout',
  22.     'home/views/ChannelsView',
  23.     'home/views/ExploreView',
  24.     'home/views/OnboardingView',
  25.     'home/viewmodels/DiscussionCreateViewModel',
  26.     'home/viewmodels/ChannelsViewModel',
  27.     'home/viewmodels/DiscussionViewModel',
  28.  
  29.     'home/collections/common/ExtensibleCollection',
  30.     'home/collections/ChannelCollection',
  31.  
  32.     'home/models/Session',
  33.     'core/UniqueModel',
  34.     'home/models/UserProfile',
  35.     'home/models/Thread',
  36.     'home/models/Forum',
  37.     'home/models/Channel',
  38.     'home/models/ChannelProfile',
  39.     'home/models/ForumProfile',
  40.     'home/models/HomepageProfile',
  41.     'home/models/ExploreViewModel',
  42.  
  43.     'home/utils/navigationUtils',
  44.     'home/utils/trackingUtils',
  45.     'core/utils/auth',
  46.     'core/utils/url/parseQueryString',
  47.     'core/api',
  48.     'core/engagement/page',
  49.     'core/strings',
  50.     'core/switches',
  51.     'remote/config',
  52.     'core/config/urls',
  53.  
  54.     // imported for side effects
  55.     'home/backbone.overrides',
  56.     'home/overrides/marionette.overrides',
  57.  
  58.     'disqus.sdk',  // needed to load the embed on Discussion pages
  59. ], function (
  60.     _,
  61.     $,
  62.     Modernizr,
  63.     Backbone,
  64.     Marionette,
  65.  
  66.     preloadTemplate,
  67.  
  68.     MainLayout,
  69.     HomepageView,
  70.     AnonHomepageView,
  71.     NotificationsView,
  72.     NotificationsLoggedOutView,
  73.     ForumProfileView,
  74.     ProfileView,
  75.     DiscussionCreateView,
  76.     DiscussionPageView,
  77.     WelcomeView,
  78.     ChannelProfileView,
  79.     SettingsLayout,
  80.     ChannelsView,
  81.     ExploreView,
  82.     OnboardingView,
  83.     DiscussionCreateViewModel,
  84.     ChannelsViewModel,
  85.     DiscussionViewModel,
  86.  
  87.     ExtensibleCollection,
  88.     ChannelCollection,
  89.  
  90.     Session,
  91.     UniqueModel,
  92.     UserProfile,
  93.     Thread,
  94.     Forum,
  95.     Channel,
  96.     ChannelProfile,
  97.     ForumProfile,
  98.     HomepageProfile,
  99.     ExploreViewModel,
  100.  
  101.     NavigationUtils,
  102.     TrackingUtils,
  103.     auth,
  104.     parseQueryString,
  105.     api,
  106.     pageEngagement,
  107.     strings,
  108.     switches,
  109.     remoteConfig,
  110.     urls
  111. ) {
  112.     'use strict';
  113.  
  114.     var localStorageSupported = Modernizr.localstorage;
  115.  
  116.     /* eslint-disable no-unused-expressions */
  117.     // This line causes the grunt task to add the Modernizr Touch test
  118.     // which in turn causes Modernizr to add a css class touch/no-touch
  119.     // to the <html> tag
  120.     Modernizr.touch;
  121.  
  122.     // Add flexbox/no-flexbox detection for IE9
  123.     Modernizr.flexbox;
  124.     /* eslint-disable no-unused-expressions */
  125.  
  126.     // TODO: move this to jesterUtils
  127.     var logStatsD = function (eventName) {
  128.         new window.Image().src = urls.jester + '/stat.gif?event=' + eventName;
  129.     };
  130.  
  131.     var gettext = strings.get;
  132.  
  133.     var Router = Backbone.Router.extend({
  134.  
  135.         name: 'home',
  136.  
  137.         routes: {
  138.             'home/discuss/:forum(/)': 'startDiscussion',
  139.             'home/edit/:forum/:thread(/)': 'editDiscussion',
  140.             'home/search(/)': 'search',
  141.             'home/user(s)(/:username)(/:feed)(/)': 'profile',
  142.             'home/user(s)/(:username)(/:feed)(/:subfeed)(/)': 'profile',
  143.             'by/:username(/:feed)(/)': 'profile',
  144.             'by/:username(/:feed)(/:subfeed)(/)': 'profile',
  145.             'home/inbox(/:feed)(/)': 'inbox',
  146.             'home/preload(/)': 'preload',
  147.             'home/account(/)': 'account',
  148.             'home/notifications(/)': 'notifications',
  149.             'home/topic(s)/:topicId(/)': 'topics',
  150.             'home/forum(s)/:forumId(/:feed)(/)': 'forums',
  151.             'home/discussion(s)/:forum/:thread(/:activeTab)(/:permalink)(/)': 'discussion',
  152.             'home/ndiscussion(s)/:forum/:thread(/:activeTab)(/:permalink)(/)': 'nativeDiscussion',
  153.             'home/follow/channel(s)/:channelId(/)': 'followChannel',
  154.  
  155.             'home/channel(s)(/)': 'channelsPage',
  156.             'home/channel(s)/:channelId(/:feed)(/)': 'channels',
  157.             'home/channel(s)/:channelId/topics/:topic(/)': 'channelTopics',
  158.             'home/channel(s)/:channelId/discussion(s)/:forumId/:thread(/:activeTab)(/:permalink)(/)': 'channelDiscussion',
  159.             'home/channel(s)/:channelId/ndiscussion(s)/:forumId/:thread(/:activeTab)(/:permalink)(/)': 'nativeChannelDiscussion',
  160.             'home/settings(/:section)/': 'settings',
  161.  
  162.             // TODO: remove this once nowhere in disqus-web is directing users to /home/discover
  163.             // (specifically after email verification, possibly other places)
  164.             // Note: also remove 'discover' route handler in trackingUtils zone names
  165.             'home/discover(/)': 'channelsPage',
  166.  
  167.             'home/explore(/)': 'explore',
  168.             'home/explore/:activeTab(/)': 'explore',
  169.             'home/explore/channels/:channelId(/:activeTab)(/)': 'exploreChannel',
  170.             'home/explore/discussions/:channelId(/)': 'exploreDiscussions',
  171.  
  172.             // This must remain as the last item so that it doesn't match this router when
  173.             // it should match something more specific (ex: home/inbox/)
  174.             'home(/:feed)(/)': 'home',
  175.         },
  176.  
  177.         initialize: function (options) {
  178.             this.CDN_ROOT = options.CDN_ROOT;
  179.             this.feeds = {};
  180.             this.listenTo(this, 'route', this.handleRouteChange);
  181.  
  182.             this.listenTo(this, 'route', this.logRouteChange);
  183.  
  184.             this.messages = [];
  185.  
  186.             this.onboardingWithoutChannels = switches.isFeatureActive('onboarding_without_channels');
  187.         },
  188.  
  189.         /*
  190.          * Start the application by running through a
  191.          * sequence of initialization steps.
  192.          */
  193.         bootstrap: function () {
  194.             this.initSession();
  195.             this.initTracking();
  196.             this.initPageEngagementTracking();
  197.             this.initLinkHandling();
  198.             this.initMainLayout();
  199.         },
  200.  
  201.         initTracking: function () {
  202.             TrackingUtils.init();
  203.             TrackingUtils.trackVisit();
  204.         },
  205.  
  206.         initLinkHandling: function () {
  207.             $('body').on('click', 'a[href]', _.bind(NavigationUtils.handleLinkClicks, NavigationUtils));
  208.         },
  209.  
  210.         initSession: function () {
  211.             var session = this.session = Session.get();
  212.             session.load();
  213.             session.loadPromise().then(_.bind(function () {
  214.                 if (window.Raven) {
  215.                     window.Raven.setUser({
  216.                         id: session.user.get('id'),
  217.                         username: session.user.get('username'),
  218.                     });
  219.                 }
  220.  
  221.                 this.loadModeratedForums();
  222.             }, this));
  223.  
  224.             session.loadPromise().fail(function () {
  225.                 var provider = session.provider();
  226.                 // If we know the session provider and we are rejecting the
  227.                 // session authentication anyway, then there was something wrong
  228.                 // with our disqusauth cookie (or the user is an "SSO" publisher account).
  229.                 if (provider)  // don't log all the random provider domains, just do 'remote' instead
  230.                     logStatsD('home.session.rejected.' + (provider === 'disqus' ? 'disqus' : 'remote'));
  231.             });
  232.  
  233.             this.initUserProfile();
  234.  
  235.             return session;
  236.         },
  237.  
  238.         initMainLayout: function () {
  239.             this.layout = new MainLayout({
  240.                 container: 'body',
  241.                 session: this.session,
  242.                 app: this,
  243.             });
  244.             // We do not render here because rendering kicks off the creation of
  245.             // certain subviews (e.g., NavView) that rely on Backbone.history.start
  246.             // having been called, which does not occur until after app.bootstrap.
  247.             // And we cannot init the MainLayout AFTER History.start because History.start
  248.             // will trigger a route that relies on MainLayout existing. And we cannot
  249.             // hook into the route event because that is fired after the route handler
  250.             // has been executed.
  251.         },
  252.  
  253.         /*
  254.          * Returns the view currently showing in the main content area of the page.
  255.          * Useful for anything external to the content view (ex: NavView) to get
  256.          * the current view/model being shown.
  257.          */
  258.         getCurrentView: function () {
  259.             return this.layout.content.currentView;
  260.         },
  261.  
  262.         initPageEngagementTracking: function () {
  263.             pageEngagement.start();
  264.         },
  265.  
  266.         /*
  267.          * When the asEmbedApp mixin is applied, loadModeratedForums is only called
  268.          * when the 'showPath' message is received via the FrameBus.
  269.          */
  270.         loadModeratedForums: function () {
  271.             this.session.loadModeratedForums();
  272.         },
  273.  
  274.         logRouteChange: function (route) {
  275.             // Log the page view to 'events.*.route.<page path>'
  276.             logStatsD(this.name + '.route.' + route);
  277.         },
  278.  
  279.         /*
  280.          * When the asEmbedApp mixin is applied, initUserProfile is only called when
  281.          * the 'showPath' message is received via the FrameBus.
  282.          */
  283.         initUserProfile: function () {
  284.             var username = Session.fromCookie().username;
  285.  
  286.             if (username) {
  287.                 // It appears the user is logged in. Fetch all the necessary user details
  288.                 // asynchronously using the username from the auth cookie.
  289.                 // (If the user turns out to be not logged in, or session expired, it'll be
  290.                 // handled on api response)
  291.                 this.session.initUserProfile(username);
  292.             } else {
  293.                 // If we can't get the username from the cookie, wait until users/details
  294.                 // returns and then fetch the rest of the user details using the fetched username
  295.                 this.session.once('change:id', function (user) {
  296.                     this.session.initUserProfile(user.get('username'));
  297.                 }, this);
  298.             }
  299.         },
  300.  
  301.         /*
  302.          * Inherits + overrides parent .execute method
  303.          * Handle pre-view setup and post-view cleanup before executing a route handler.
  304.          */
  305.         execute: function () {
  306.             // Before showing a new view remove the logged-in requirement handling that may have been
  307.             // added for the previous view.
  308.             api.off('error', NavigationUtils.navigateToLoginOnAuthFail);
  309.  
  310.             TrackingUtils.pageChanged();
  311.  
  312.             Backbone.Router.prototype.execute.apply(this, arguments);
  313.         },
  314.  
  315.         ensureAuthenticated: function (callback) {
  316.  
  317.             // Reset the api 'error' handler so we don't bind this
  318.             // more than necessary.
  319.             api.off('error', NavigationUtils.navigateToLoginOnAuthFail);
  320.  
  321.             if (Session.isKnownToBeLoggedOut())
  322.                 return NavigationUtils.navigateToLogin();
  323.  
  324.             // If we expect the user to be logged in, but we make
  325.             // an API call that returns an error, we should direct the
  326.             // user to the login page.
  327.             api.on('error', NavigationUtils.navigateToLoginOnAuthFail);
  328.  
  329.             // Ensure the session is fetched. Once it is, call the
  330.             // callback. If fetch fails, prompt user to login
  331.             this.session.loadPromise().then(
  332.                 _.bind(callback, this, _.tail(arguments)),
  333.                 NavigationUtils.navigateToLogin
  334.             );
  335.         },
  336.  
  337.         navigateToLandingPage: function (options) {
  338.             return NavigationUtils.navigate('/home/', options);
  339.         },
  340.  
  341.         /*
  342.          * Ensures that logged in users are redirected to onboarding step 1 if
  343.          * they have not completed it yet. Logged out users are not affected.
  344.          */
  345.         ensureOnboardingComplete: function (callback) {
  346.             // TODO: @taylangocmen once channels is removed kill this onboarding flow
  347.             if (this.onboardingWithoutChannels || Session.isKnownToBeLoggedOut())
  348.                 return callback.apply(this);
  349.  
  350.             this.session.loadPromise().always(_.bind(function () {
  351.                 if (this.session.isLoggedIn() && this.session.user.shouldHomeOnboard())
  352.                     // Defer this so that the current route event is triggered before navigating to the 1st step of
  353.                     // onboarding. Not deferring it will result in route events being triggered in the wrong order.
  354.                     _.defer(this.navigateToOnboarding);
  355.                 else
  356.                     callback.apply(this);
  357.             }, this));
  358.         },
  359.  
  360.         navigateToOnboarding: function () {
  361.             var welcomeRoute = 'home/explore/';
  362.             var params = parseQueryString();
  363.             var toKeep = {};
  364.  
  365.             // Retain certain params for use later.
  366.             // Only retain them if given truthy values, so that checks later
  367.             // for these params can skip value check and only check existence.
  368.             if (params.email_verified)
  369.                 toKeep.email_verified = params.email_verified;
  370.  
  371.             if (params.forum_id)
  372.                 toKeep.forum_id = params.forum_id;
  373.  
  374.             if (_.size(toKeep))
  375.                 welcomeRoute += '?' + $.param(toKeep);
  376.  
  377.             NavigationUtils.navigate(welcomeRoute, { trigger: true, replace: true });
  378.         },
  379.  
  380.         /*
  381.          * Verifies the forum with the given id has a channel and that
  382.          * this user can create on that channel.
  383.          */
  384.         ensureCanCreateOnChannel: function (callback, forumId) {
  385.             var forum = new UniqueModel(Forum, {
  386.                 id: forumId,
  387.             });
  388.  
  389.             // If forum hasn't been fetched yet, wait until fetching is complete
  390.             // and then re-call this function
  391.             if (forum.shouldFetch()) {
  392.                 forum.fetch();
  393.                 this.listenToOnce(forum, 'sync', _.bind.apply(_, [this.ensureCanCreateOnChannel, this].concat(_.toArray(arguments))));
  394.                 return;
  395.             }
  396.  
  397.             // If the forum is not the primary forum for a channel, or if the
  398.             // current user does not have create permissions for the channel,
  399.             // redirect to an error page.
  400.             if ((!forum.channel && forumId !== 'gabalafou-test') ||
  401.                 !forum.channel.userCanCreate(this.session.user))
  402.  
  403.                 // TODO: this should redirect to a page with a message like:
  404.                 // "You do not have permission to view this page"
  405.                 return this.notFound();
  406.  
  407.             // The forum has a channel. Call the callback.
  408.             callback.apply(this, _.tail(arguments));
  409.         },
  410.  
  411.         /**
  412.          * Listens for a tabbed view in case it throws a badTab event. If that occurs,
  413.          * rewrites the url to the given route silently. It's expected that the tabbed
  414.          * view will handle the event gracefully.
  415.          *
  416.          * @param  {tabbedView} tabbedView - A view instance that triggers a badTab event
  417.          *                                   in the case that an invalid tab is navigated
  418.          *                                   to, as TabbedView does.
  419.          * @param  {string} redirectRoute - The route to rewrite if the tab is not supported
  420.          */
  421.         ensureTab: function (tabbedView, redirectRoute) {
  422.             tabbedView.listenTo(tabbedView, 'badTab', function () {
  423.                 NavigationUtils.navigate(redirectRoute, { silent: true, replace: true });
  424.             });
  425.         },
  426.  
  427.         preventBlacklisted: function (options) {
  428.             if (_.contains(remoteConfig.timelines.BLACKLISTED_FORUMS, options.forum))
  429.                 window.top.location = 'https://help.disqus.com/customer/portal/articles/1689402-redirected-from-home';
  430.         },
  431.  
  432.         preload: function () {
  433.             this.preloadView = new (Marionette.ItemView.extend({ template: preloadTemplate }))();
  434.  
  435.             this.layout.showView(this.preloadView);
  436.         },
  437.  
  438.         /*
  439.          * Append a trailing slash to the current route if it
  440.          * doesn't have one.
  441.          *
  442.          * Saves the current and previous route names as properties so it can
  443.          * be used by the NavView.
  444.          */
  445.         handleRouteChange: function (routeName) {
  446.             this.setCurrentRouteName(routeName);
  447.             NavigationUtils.coerceTrailingSlash(window.location);
  448.         },
  449.  
  450.         setCurrentRouteName: function (routeName) {
  451.             this._previousRouteName = this.getCurrentRouteName();
  452.             this._currentRouteName = routeName;
  453.         },
  454.  
  455.         getCurrentRouteName: function () {
  456.             return this._currentRouteName;
  457.         },
  458.  
  459.         getPreviousRouteName: function () {
  460.             return this._previousRouteName;
  461.         },
  462.  
  463.         onboarding: function () {
  464.             return this.ensureAuthenticated(function () {
  465.                 this.layout.showView(new WelcomeView({ session: this.session }), { lightBackground: true });
  466.             });
  467.         },
  468.  
  469.         _explore: function (options) {
  470.             this.session.loadPromise()
  471.                 .always(Function.bind.call(function () {
  472.                     var showOnboarding = this.session.isLoggedIn() && this.session.user.shouldHomeOnboard();
  473.                     if (showOnboarding) {
  474.                         options.collection = new ChannelCollection([], { listName: 'explore' });
  475.                         this.layout.showView(new OnboardingView(options));
  476.                     } else {
  477.                         options.model = new ExploreViewModel();
  478.                         this.layout.showView(new ExploreView(options));
  479.                     }
  480.                 }, this));
  481.         },
  482.  
  483.         explore: function () {
  484.             return this.navigateToLandingPage({ replace: true });
  485.         },
  486.  
  487.         exploreChannel: function () {
  488.             return this.navigateToLandingPage({ replace: true });
  489.         },
  490.  
  491.         exploreDiscussions: function () {
  492.             return this.navigateToLandingPage({ replace: true });
  493.         },
  494.  
  495.         // When user goes to /user, take them to /user/<username>
  496.         renavigateToProfile: function (user) {
  497.             var username = user.get('username');
  498.  
  499.             // Prevent potential infinite loop
  500.             // .profile() -> .renavigateToProfile() -> .profile() -> ...
  501.             // (happens when username never gets set to truthy value)
  502.             if (!username) {
  503.                 this.navigateToLandingPage({ replace: true });
  504.                 return void this.home();
  505.             }
  506.  
  507.             NavigationUtils.navigate('/by/' + username + '/', {
  508.                 replace: true,
  509.             });
  510.             this.profile(username);
  511.         },
  512.  
  513.         settings: function (section) {
  514.             return this.ensureAuthenticated(function () {
  515.                 this.layout.showView(new SettingsLayout({
  516.                     session: this.session,
  517.                     activeTab: section,
  518.                     onboardingWithoutChannels: this.onboardingWithoutChannels,
  519.                 }));
  520.             });
  521.         },
  522.  
  523.         channelsPage: function () {
  524.             // remove everything but discussdisqus
  525.  
  526.             // Channels page shows channels followed/managed by the authenticated user.
  527.             // Don't allow anon users to visit the page.
  528.             if (Session.isKnownToBeLoggedOut()) {
  529.                 NavigationUtils.navigate('/', { replace: true });
  530.                 return this.home();
  531.             }
  532.  
  533.             this.ensureOnboardingComplete(function () {
  534.                 var model = new UniqueModel(ChannelsViewModel, { id: 'discover-view-model' });
  535.                 model.ensureFetched();
  536.  
  537.                 this.layout.showView(new ChannelsView({
  538.                     model: model,
  539.                     onboardingWithoutChannels: this.onboardingWithoutChannels,
  540.                 }));
  541.             });
  542.         },
  543.  
  544.         search: function () {
  545.             return this.navigateToLandingPage({ replace: true });
  546.         },
  547.  
  548.         profile: function (username, feedName, subFeedName) {
  549.             // If we get here and we aren't on the /by/ profile path,
  550.             // then rewrite the URL to be correct. NavigationUtils knows
  551.             // how to rewrite the home/user URL correctly, so just pass the
  552.             // task off to there.
  553.             if (window.location.pathname.indexOf('home/user') !== -1)
  554.                 NavigationUtils.navigate(window.location, { replace: true, silent: true });
  555.  
  556.             if (!username) {
  557.                 return this.ensureAuthenticated(function () {
  558.                     var session = this.session;
  559.                     var sessionUser = session.user;
  560.  
  561.                     if (!sessionUser.get('username'))
  562.                         return void this.listenToOnce(session, 'change:id', this.renavigateToProfile);
  563.  
  564.                     return void this.renavigateToProfile(sessionUser);
  565.                 });
  566.             }
  567.  
  568.             var userProfile = _.find(UniqueModel.pool(UserProfile), function (userProfile) {
  569.                 return userProfile.user.get('username') === username;
  570.             });
  571.  
  572.             if (!userProfile)
  573.                 userProfile = new UniqueModel(UserProfile, { username: username });
  574.  
  575.             userProfile.ensureFetched();
  576.  
  577.             var view = new ProfileView({
  578.                 model: userProfile,
  579.                 activeTab: feedName,
  580.                 subTab: subFeedName,
  581.             });
  582.             this.ensureTab(view, '/by/' + username + '/');
  583.  
  584.             this.layout.showView(view);
  585.         },
  586.  
  587.         home: function (feedName, callback) {
  588.             var isKnownToBeLoggedOut = Session.isKnownToBeLoggedOut();
  589.  
  590.             if (isKnownToBeLoggedOut) {
  591.                 if (parseQueryString().email_verified)
  592.                     // Always try to login in users who have the email_verified param
  593.                     // in their url, so we can send them through onboarding if necessary
  594.                     NavigationUtils.navigateToLogin();
  595.                 else
  596.                     // Logged out users who were not sent to home via an email verification
  597.                     // link should be taken to the main homepage
  598.                     NavigationUtils.navigateToHomepage();
  599.  
  600.                 return;
  601.             }
  602.  
  603.  
  604.             this.ensureOnboardingComplete(function () {
  605.                 // If we get here and we aren't on the / home page path,
  606.                 // then rewrite the URL to be correct. NavigationUtils knows
  607.                 // how to rewrite the /home/ to /.
  608.                 if (window.location.pathname === '/home/')
  609.                     NavigationUtils.navigate(window.location, { replace: true, silent: true });
  610.  
  611.                 var model, contentView;
  612.  
  613.                 if (isKnownToBeLoggedOut) {
  614.                     var exploreChannelCollection = new ChannelCollection([], {
  615.                         listName: 'explore',
  616.                     });
  617.                     exploreChannelCollection.ensureFetched();
  618.                     contentView = new AnonHomepageView({
  619.                         collection: exploreChannelCollection,
  620.                     });
  621.  
  622.                     this.layout.showView(contentView, { lightBackground: true });
  623.                 } else {
  624.                     model = new UniqueModel(HomepageProfile, { id: 'home-view-model' });
  625.                     model.ensureFetched();
  626.                     contentView = new HomepageView({
  627.                         model: model,
  628.                         activeTab: feedName,
  629.                         onboardingWithoutChannels: this.onboardingWithoutChannels,
  630.                     });
  631.                     this.ensureTab(contentView, '/');
  632.  
  633.                     this.layout.showView(contentView);
  634.                 }
  635.  
  636.                 // Check that callback is a function before calling.
  637.                 // This is necessary since `home` is called by the router,
  638.                 // which may pass a query string as an argument.
  639.                 if (_.isFunction(callback))
  640.                     callback();
  641.  
  642.                 this.cleanLocalStorage();
  643.             });
  644.         },
  645.  
  646.         // Previously the Home feed view used local storage to determine whether
  647.         // or not to show a banner message to the user. With the removal of those
  648.         // banner views we can clean up local storage that they were using.
  649.         cleanLocalStorage: function () {
  650.             if (!localStorageSupported)
  651.                 return;
  652.  
  653.             try {
  654.                 window.localStorage.removeItem('dhome_v2oo');
  655.                 window.localStorage.removeItem('whatsNewViewsRemaining');
  656.                 window.localStorage.removeItem('v2SwitchoverViewsRemaining');
  657.             } catch (err) {
  658.                 /* pass */
  659.             }
  660.         },
  661.  
  662.         account: function () {
  663.             return NavigationUtils.navigate('/home/settings/account/', { trigger: true, replace: true });
  664.         },
  665.  
  666.         notifications: function () {
  667.             return NavigationUtils.navigate('/home/settings/email/', { trigger: true, replace: true });
  668.         },
  669.  
  670.         ensureAdmin: function (routeHandler, args) {
  671.             var session = this.session;
  672.  
  673.             // If we got here but the session hasn't been
  674.             // fetched, fetch the session first, and then try again
  675.             if (!session.fetched) {
  676.                 return void session.fetch().then(
  677.                     _.bind(this.ensureAdmin, this, routeHandler, args),
  678.                     _.bind(this.notFound, this));
  679.             }
  680.  
  681.             // Checks if session user is a global admin, and
  682.             // checks Jones config for any additional accounts
  683.             if (!auth.getFromCookie().staff)
  684.                 return this.notFound();
  685.  
  686.             return routeHandler.apply(this, args);
  687.         },
  688.  
  689.         followChannel: function (channelId) {
  690.             if (channelId === 'disqusfun')
  691.                 return this.ensureAdmin(this._followChannel, arguments);
  692.  
  693.             return this._followChannel.apply(this, arguments);
  694.         },
  695.  
  696.         _followChannel: function (channelId) {
  697.             // Follow action will fail and prompt user to log in, so check first, before
  698.             // replacing the url, so that the login page will have the correct return url
  699.             this.ensureAuthenticated(function () {
  700.                 var channel = new UniqueModel(Channel, { slug: channelId });
  701.  
  702.                 if (channel.primaryForum && !channel.primaryForum.get('isFollowing')) {
  703.                     channel.primaryForum.follow();
  704.                 } else {
  705.                     this.listenToOnce(channel, 'changeRelated:primaryForum', function () {
  706.                         if (!channel.primaryForum.get('isFollowing'))
  707.                             channel.primaryForum.follow();
  708.                     });
  709.                 }
  710.  
  711.                 NavigationUtils.navigate('/home/channel/' + channelId + '/', { trigger: true, replace: true });
  712.             });
  713.         },
  714.  
  715.         channels: function (channelId) {
  716.             if (channelId !== 'discussdisqus')
  717.                 return this.navigateToLandingPage({ replace: true });
  718.  
  719.             if (channelId === 'disqusfun' || channelId === 'gabalafou-test')
  720.                 return this.ensureAdmin(this._channels, arguments);
  721.  
  722.             return this._channels.apply(this, arguments);
  723.         },
  724.  
  725.         channelTopics: function (channelId, topicName) {
  726.             if (channelId !== 'discussdisqus')
  727.                 return this.navigateToLandingPage({ replace: true });
  728.  
  729.             return this.channels(channelId, 'topic-' + topicName);
  730.         },
  731.  
  732.         _channels: function (channelId, feedName) {
  733.             var channelProfile = new UniqueModel(
  734.                 ChannelProfile,
  735.                 {
  736.                     id: channelId, // must have id for UniqueModel
  737.                     channel: channelId,
  738.                 }
  739.             );
  740.  
  741.             channelProfile.ensureFetched();
  742.  
  743.             var contentView = new ChannelProfileView({
  744.                 model: channelProfile,
  745.                 activeTab: feedName,
  746.             });
  747.             this.ensureTab(contentView, 'home/channel/' + channelId + '/');
  748.             this.layout.showView(contentView);
  749.         },
  750.  
  751.         _forums: function (forumId, feedName) {
  752.             var forumProfile = new UniqueModel(
  753.                 ForumProfile,
  754.                 {
  755.                     id: forumId,
  756.                 }
  757.             );
  758.  
  759.             var forum = forumProfile.forum;
  760.             var self = this;
  761.  
  762.             // If this is the primary forum for a channel, redirect to the channel page
  763.             if (forum.channel) {
  764.                 NavigationUtils.navigate('/home/channel/' + forum.channel.id + '/', { trigger: true, replace: true });
  765.                 return;
  766.             }
  767.  
  768.             forum.fetch().then(function () {
  769.                 if (forum.channel)
  770.                     self._forums(forumId);
  771.             }, this.notFound);
  772.  
  773.             forumProfile.ensureFetched();
  774.  
  775.             var view = new ForumProfileView({
  776.                 model: forumProfile,
  777.                 activeTab: feedName,
  778.                 onboardingWithoutChannels: this.onboardingWithoutChannels,
  779.             });
  780.             this.ensureTab(view, '/home/forum/' + forumId + '/');
  781.  
  782.             this.layout.showView(view);
  783.         },
  784.  
  785.         forums: function (forumId) {
  786.             this.preventBlacklisted({ forum: forumId });
  787.  
  788.             if (forumId === 'disqus-disqusfun')
  789.                 return this.ensureAdmin(this._forums, arguments);
  790.  
  791.             return this._forums.apply(this, arguments);
  792.         },
  793.  
  794.         topics: function () {
  795.             return this.navigateToLandingPage({ replace: true });
  796.         },
  797.  
  798.         inbox: function (feedName) {
  799.             var view;
  800.             var notifications = this.session.getOrCreateNotifications();
  801.  
  802.             // Kick off fetch(es) for items needed on the notifications view.
  803.             // Notifications and counters will have already been fetched by
  804.             // the Nav bar
  805.             notifications.ensureFetchedRecommendations();
  806.  
  807.             // If the user isn't logged in via Disqus or an SSO account (via embed sidebar), show the logged out
  808.             // notifications inbox.
  809.             if (!this.isSSOAuthenticated && Session.isKnownToBeLoggedOut()) {
  810.                 view = new NotificationsLoggedOutView({
  811.                     model: notifications,
  812.                     onboardingWithoutChannels: this.onboardingWithoutChannels,
  813.                 });
  814.             } else {
  815.  
  816.                 if (window.location.search.indexOf('email_verified') > -1) {
  817.                     var message = strings.interpolate(
  818.                         gettext('Your email\'s verified! Have a look around -- %(Disqus)s is a lot more than comments'),
  819.                         { Disqus: 'Disqus' }
  820.                     );
  821.                     this.messages.push({ message: message });
  822.                 }
  823.  
  824.                 view = new NotificationsView({
  825.                     model: notifications,
  826.                     activeTab: feedName,
  827.                     disableMOTD: this.disableMOTD,
  828.                     onboardingWithoutChannels: this.onboardingWithoutChannels,
  829.                 });
  830.             }
  831.  
  832.             this.ensureTab(view, '/home/inbox/');
  833.             this.layout.showView(view);
  834.         },
  835.  
  836.         _showDiscussionForm: function (forumId, options) {
  837.             var discussionForm = new DiscussionCreateView({
  838.                 session: this.session,
  839.                 model: new DiscussionCreateViewModel({}, _.extend({ forum: forumId }, options)),
  840.             });
  841.  
  842.             this.listenTo(discussionForm, 'createThread', function () {
  843.                 var thread = discussionForm.getThread();
  844.                 // Add the recently created thread to an extensible collection so that embedly
  845.                 // requests (if any) will be made before showing the newly created discussion.
  846.                 new ExtensibleCollection().add(thread);
  847.                 NavigationUtils.navigate(thread.getDiscussionRoute(), {
  848.                     trigger: true,
  849.                 });
  850.             });
  851.             this.listenTo(discussionForm, 'cancelThread', function () {
  852.                 NavigationUtils.navigate('home/' + discussionForm.getForum().getForumRoute(), {
  853.                     trigger: true,
  854.                 });
  855.             });
  856.  
  857.             this.layout.showView(discussionForm);
  858.         },
  859.  
  860.         startDiscussion: function (forumId) {
  861.             // return if a non discussdisqus channel
  862.             if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
  863.                 return this.navigateToLandingPage({ replace: true });
  864.  
  865.             // Must be logged in and on the primary forum for a channel in order to create a discussion
  866.             return this.ensureAuthenticated(function () {
  867.                 this.ensureCanCreateOnChannel(function () {
  868.  
  869.                     this._showDiscussionForm.apply(this, arguments);
  870.                 }, forumId);
  871.             }, arguments);
  872.         },
  873.  
  874.         editDiscussion: function (forumId, threadSlug) {
  875.             // return if a non discussdisqus channel
  876.             if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
  877.                 return this.navigateToLandingPage({ replace: true });
  878.  
  879.             var session = this.session;
  880.             var thread = Thread.getOrCreateThread(forumId, threadSlug);
  881.             var fetchPromises = [thread.getEditPermissions(session)];
  882.  
  883.             // If we got here but the session hasn't been
  884.             // fetched, fetch the session first, and then try again
  885.             if (thread.shouldFetch())
  886.                 fetchPromises.push(thread.fetch());
  887.  
  888.             return $.when.apply($, fetchPromises).then(
  889.                 _.bind(function (canEdit) {
  890.                     if (canEdit)
  891.                         return this._showDiscussionForm(forumId, { thread: thread });
  892.  
  893.                     return void NavigationUtils.navigate(thread.getDiscussionRoute(),
  894.                         { trigger: true, replace: true });
  895.                 }, this),
  896.                 _.bind(this.notFound, this)
  897.             );
  898.         },
  899.  
  900.         discussionPage: function (forumId, threadSlug, activeTab, options) {
  901.             options = options || {};
  902.  
  903.             var thread = Thread.getOrCreateThread(forumId, threadSlug, options.threadFetchOptions);
  904.             var model = DiscussionViewModel.getOrCreate({}, {
  905.                 channel: options.channel,
  906.                 thread: thread,
  907.             });
  908.  
  909.             var discussionPage = new DiscussionPageView(_.extend({
  910.                 model: model,
  911.                 session: this.session,
  912.                 activeTab: activeTab,
  913.                 app: this,
  914.             }, options));
  915.  
  916.             this.layout.showView(discussionPage, { lightBackground: true });
  917.         },
  918.  
  919.         _discussion: function (forumId, threadSlug, activeTab, options) {
  920.             this.preventBlacklisted({ forum: forumId });
  921.  
  922.             if (forumId === 'disqus-disqusfun')
  923.                 return this.ensureAdmin(this.discussionPage, [forumId, threadSlug, activeTab, options]);
  924.  
  925.             return this.discussionPage(forumId, threadSlug, activeTab, options);
  926.         },
  927.  
  928.         discussion: function (forumId, threadSlug, activeTab) {
  929.             if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
  930.                 return this.navigateToLandingPage({ replace: true });
  931.  
  932.             return this._discussion(forumId, threadSlug, activeTab);
  933.         },
  934.  
  935.         channelDiscussion: function (channelId, forumId, threadSlug, activeTab, options) {
  936.             if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
  937.                 return this.navigateToLandingPage({ replace: true });
  938.  
  939.             options = options || {};
  940.  
  941.             var channel = new UniqueModel(Channel, { slug: channelId });
  942.  
  943.             // Must fetch this for network threads linked through a channel.
  944.             // User generated threads will end up fetching this again as
  945.             // part of the forum fetch, but network threads won't, and they
  946.             // need channel details for this view.
  947.             if (channel.shouldFetch())
  948.                 channel.fetch();
  949.  
  950.             return this._discussion(forumId, threadSlug, activeTab, {
  951.                 channel: channel,
  952.                 threadFetchOptions: {
  953.                     data: {
  954.                         related: ['author'],
  955.                     },
  956.                 },
  957.                 noEmbed: options.noEmbed,
  958.             });
  959.         },
  960.  
  961.         // Native = no embed, iframe-less comments section
  962.         nativeDiscussion: function (forumId, threadId, activeTab) {
  963.             if (forumId.indexOf('channel-') !== -1 && forumId !== 'channel-discussdisqus')
  964.                 return this.navigateToLandingPage({ replace: true });
  965.  
  966.             return this._discussion(forumId, threadId, activeTab, {
  967.                 noEmbed: true,
  968.             });
  969.         },
  970.  
  971.         // Native = no embed, iframe-less comments section
  972.         nativeChannelDiscussion: function (channelId, forumId, threadSlug, activeTab) {
  973.             if (channelId !== 'discussdisqus')
  974.                 return this.navigateToLandingPage({ replace: true });
  975.  
  976.             return this.channelDiscussion(channelId, forumId, threadSlug, activeTab, {
  977.                 noEmbed: true,
  978.             });
  979.         },
  980.  
  981.         notFound: NavigationUtils.notFoundRouteHandler,
  982.     });
  983.  
  984.     return Router;
  985. });
  986.  
  987. // https://c.disquscdn.com/next/16dccc7/home/js/Router.js

Replies to Router.js rss

Title Name Language When
completeReportUser.js disqus.com javascript 3 Weeks ago.