codecombat/app/core/Router.coffee

263 lines
10 KiB
CoffeeScript
Raw Normal View History

2016-03-30 16:57:19 -04:00
go = (path, options) -> -> @routeDirectly path, arguments, options
redirect = (path) -> -> @navigate(path, { trigger: true, replace: true })
2016-04-13 12:54:24 -04:00
utils = require './utils'
2014-01-03 13:32:13 -05:00
module.exports = class CocoRouter extends Backbone.Router
initialize: ->
# http://nerds.airbnb.com/how-to-add-google-analytics-page-tracking-to-57536
@bind 'route', @_trackPageView
2014-01-03 13:32:13 -05:00
Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
@initializeSocialMediaServices = _.once @initializeSocialMediaServices
2014-01-03 13:32:13 -05:00
routes:
2016-01-26 19:28:29 -05:00
'': ->
if window.serverConfig.picoCTF
return @routeDirectly 'play/CampaignView', ['picoctf'], {}
2016-04-13 12:54:24 -04:00
if utils.getQueryVariable 'hour_of_code'
return @navigate "/play", {trigger: true, replace: true}
return @routeDirectly('NewHomeView', [])
'about': go('AboutView')
2014-07-29 11:28:13 -04:00
'account': go('account/MainAccountView')
'account/settings': go('account/AccountSettingsRootView')
'account/unsubscribe': go('account/UnsubscribeView')
2014-11-25 14:09:29 -05:00
'account/payments': go('account/PaymentsView')
'account/subscription': go('account/SubscriptionView')
'account/invoices': go('account/InvoicesView')
2015-09-25 13:03:44 -04:00
'account/prepaid': go('account/PrepaidView')
'admin': go('admin/MainAdminView')
'admin/clas': go('admin/CLAsView')
'admin/design-elements': go('admin/DesignElementsView')
'admin/files': go('admin/FilesView')
'admin/analytics': go('admin/AnalyticsView')
'admin/analytics/subscriptions': go('admin/AnalyticsSubscriptionsView')
'admin/level-sessions': go('admin/LevelSessionsView')
'admin/users': go('admin/UsersView')
2014-08-30 23:27:58 -04:00
'admin/base': go('admin/BaseView')
'admin/trial-requests': go('admin/TrialRequestsView')
'admin/user-code-problems': go('admin/UserCodeProblemsView')
'admin/pending-patches': go('admin/PendingPatchesView')
'admin/codelogs': go('admin/CodeLogsView')
'beta': go('HomeView')
2015-09-25 18:49:00 -04:00
'careers': => window.location.href = 'https://jobs.lever.co/codecombat'
2015-10-26 23:39:36 -04:00
'Careers': => window.location.href = 'https://jobs.lever.co/codecombat'
2015-09-14 20:38:18 -04:00
'cla': go('CLAView')
'clans': go('clans/ClansView')
'clans/:clanID': go('clans/ClanDetailsView')
'community': go('CommunityView')
'contribute': go('contribute/MainContributeView')
'contribute/adventurer': go('contribute/AdventurerView')
'contribute/ambassador': go('contribute/AmbassadorView')
'contribute/archmage': go('contribute/ArchmageView')
'contribute/artisan': go('contribute/ArtisanView')
'contribute/diplomat': go('contribute/DiplomatView')
'contribute/scribe': go('contribute/ScribeView')
2016-03-30 16:57:19 -04:00
'courses': go('courses/CoursesView') # , { studentsOnly: true }) # TODO: Enforce after session-less play for teachers
'Courses': go('courses/CoursesView') # , { studentsOnly: true })
'courses/students': redirect('/courses')
'courses/teachers': redirect('/teachers/classes')
'courses/purchase': redirect('/teachers/enrollments')
'courses/enroll(/:courseID)': redirect('/teachers/enrollments')
'courses/:classroomID': go('courses/ClassroomView') #, { studentsOnly: true })
2015-11-30 14:14:27 -05:00
'courses/:courseID/:courseInstanceID': go('courses/CourseDetailsView')
'db/*path': 'routeToServer'
'demo(/*subpath)': go('DemoView')
'docs/components': go('docs/ComponentsDocumentationView')
'docs/systems': go('docs/SystemsDocumentationView')
2014-08-26 20:34:00 -04:00
'editor': go('CommunityView')
'editor/achievement': go('editor/achievement/AchievementSearchView')
'editor/achievement/:articleID': go('editor/achievement/AchievementEditView')
'editor/article': go('editor/article/ArticleSearchView')
'editor/article/preview': go('editor/article/ArticlePreviewView')
'editor/article/:articleID': go('editor/article/ArticleEditView')
'editor/level': go('editor/level/LevelSearchView')
'editor/level/:levelID': go('editor/level/LevelEditView')
'editor/thang': go('editor/thang/ThangTypeSearchView')
'editor/thang/:thangID': go('editor/thang/ThangTypeEditView')
'editor/campaign/:campaignID': go('editor/campaign/CampaignEditorView')
2015-03-07 19:30:25 -05:00
'editor/poll': go('editor/poll/PollSearchView')
'editor/poll/:articleID': go('editor/poll/PollEditView')
2015-12-21 15:44:22 -05:00
'editor/thang-tasks': go('editor/ThangTasksView')
'editor/verifier': go('editor/verifier/VerifierView')
'editor/verifier/:levelID': go('editor/verifier/VerifierView')
'file/*path': 'routeToServer'
2014-08-15 10:20:45 -04:00
'github/*path': 'routeToServer'
2015-11-03 19:41:06 -05:00
'hoc': go('courses/HourOfCodeView')
2016-01-26 19:28:29 -05:00
'home': go('NewHomeView')
'i18n': go('i18n/I18NHomeView')
'i18n/thang/:handle': go('i18n/I18NEditThangTypeView')
'i18n/component/:handle': go('i18n/I18NEditComponentView')
'i18n/level/:handle': go('i18n/I18NEditLevelView')
'i18n/achievement/:handle': go('i18n/I18NEditAchievementView')
'i18n/campaign/:handle': go('i18n/I18NEditCampaignView')
2015-03-07 19:30:25 -05:00
'i18n/poll/:handle': go('i18n/I18NEditPollView')
2015-04-30 16:35:21 -04:00
'identify': go('user/IdentifyView')
'legal': go('LegalView')
'multiplayer': go('MultiplayerView')
'play(/)': go('play/CampaignView') # extra slash is to get Facebook app to work
'play/ladder/:levelID/:leagueType/:leagueID': go('ladder/LadderView')
'play/ladder/:levelID': go('ladder/LadderView')
'play/ladder': go('ladder/MainLadderView')
'play/level/:levelID': go('play/level/PlayLevelView')
'play/spectate/:levelID': go('play/SpectateView')
'play/:map': go('play/CampaignView')
'preview': go('HomeView')
2016-02-01 11:39:00 -05:00
'privacy': go('PrivacyView')
'schools': go('NewHomeView')
2015-12-14 23:43:34 -05:00
2016-04-05 12:34:45 -04:00
'teachers': redirect('/teachers/classes')
2016-03-30 16:57:19 -04:00
'teachers/classes': go('courses/TeacherClassesView') #, { teachersOnly: true })
'teachers/classes/:classroomID': go('courses/TeacherClassView') #, { teachersOnly: true })
'teachers/courses': go('courses/TeacherCoursesView')
2016-03-09 17:40:52 -05:00
'teachers/demo': go('teachers/RequestQuoteView')
2016-03-30 16:57:19 -04:00
'teachers/enrollments': go('courses/EnrollmentsView') #, { teachersOnly: true })
2016-03-09 17:40:52 -05:00
'teachers/freetrial': go('teachers/RequestQuoteView')
'teachers/quote': go('teachers/RequestQuoteView')
'teachers/signup': ->
return @routeDirectly('teachers/CreateTeacherAccountView', []) if me.isAnonymous()
@navigate('/teachers/update-account', {trigger: true, replace: true})
'teachers/update-account': ->
2016-03-09 17:40:52 -05:00
return @navigate('/teachers/signup', {trigger: true, replace: true}) if me.isAnonymous()
@routeDirectly('teachers/ConvertToTeacherAccountView', [])
'test(/*subpath)': go('TestView')
'user/:slugOrID': go('user/MainUserView')
'*name/': 'removeTrailingSlash'
2015-06-24 17:46:59 -04:00
'*name': go('NotFoundView')
routeToServer: (e) ->
window.location.href = window.location.href
removeTrailingSlash: (e) ->
@navigate e, {trigger: true}
2016-03-30 16:57:19 -04:00
routeDirectly: (path, args=[], options={}) ->
if options.teachersOnly and not me.isTeacher()
return @routeDirectly('teachers/RestrictedToTeachersView')
if options.studentsOnly and me.isTeacher()
return @routeDirectly('courses/RestrictedToStudentsView')
leavingMessage = _.result(window.currentView, 'onLeaveMessage')
if leavingMessage
if not confirm(leavingMessage)
return @navigate(this.path, {replace: true})
else
window.currentView.onLeaveMessage = _.noop # to stop repeat confirm calls
path = 'play/CampaignView' if window.serverConfig.picoCTF and not /^(views)?\/?play/.test(path)
path = "views/#{path}" if not _.string.startsWith(path, 'views/')
ViewClass = @tryToLoadModule path
if not ViewClass and application.moduleLoader.load(path)
@listenToOnce application.moduleLoader, 'load-complete', ->
2016-01-26 19:28:29 -05:00
@routeDirectly(path, args, options)
return
return @openView @notFoundView() if not ViewClass
2016-01-26 19:28:29 -05:00
view = new ViewClass(options, args...) # options, then any path fragment args
view.render()
@openView(view)
tryToLoadModule: (path) ->
try
return require(path)
catch error
if error.toString().search('Cannot find module "' + path + '" from') is -1
throw error
2014-01-03 13:32:13 -05:00
openView: (view) ->
@closeCurrentView()
$('#page-container').empty().append view.el
window.currentView = view
@activateTab()
view.afterInsert()
view.didReappear()
@path = document.location.pathname + document.location.search
closeCurrentView: ->
if window.currentView?.reloadOnClose
return document.location.reload()
window.currentModal?.hide?()
return unless window.currentView?
window.currentView.destroy()
$('.popover').popover 'hide'
$('#flying-focus').css({top: 0, left: 0}) # otherwise it might make the page unnecessarily tall
2016-03-30 16:57:19 -04:00
_.delay (->
$('html')[0].scrollTop = 0
$('body')[0].scrollTop = 0
), 10
2014-01-03 13:32:13 -05:00
initializeSocialMediaServices: ->
return if application.testing or application.demoing
application.facebookHandler.loadAPI()
application.gplusHandler.loadAPI()
require('core/services/twitter')()
2014-01-03 13:32:13 -05:00
renderSocialButtons: =>
# TODO: Refactor remaining services to Handlers, use loadAPI success callback
@initializeSocialMediaServices()
$('.share-buttons, .partner-badges').addClass('fade-in').delay(10000).removeClass('fade-in', 5000)
application.facebookHandler.renderButtons()
application.gplusHandler.renderButtons()
twttr?.widgets?.load?()
2014-01-03 13:32:13 -05:00
activateTab: ->
base = _.string.words(document.location.pathname[1..], '/')[0]
$("ul.nav li.#{base}").addClass('active')
_trackPageView: ->
window.tracker?.trackPageView()
2014-01-03 13:32:13 -05:00
onNavigate: (e) ->
if _.isString e.viewClass
ViewClass = @tryToLoadModule e.viewClass
if not ViewClass and application.moduleLoader.load(e.viewClass)
@listenToOnce application.moduleLoader, 'load-complete', ->
@onNavigate(e)
return
e.viewClass = ViewClass
2014-01-03 13:32:13 -05:00
manualView = e.view or e.viewClass
if (e.route is document.location.pathname) and not manualView
return document.location.reload()
@navigate e.route, {trigger: not manualView}
@_trackPageView()
2014-01-03 13:32:13 -05:00
return unless manualView
if e.viewClass
args = e.viewArgs or []
view = new e.viewClass(args...)
view.render()
@openView view
else
@openView e.view
navigate: (fragment, options) ->
super fragment, options
Backbone.Mediator.publish 'router:navigated', route: fragment
2016-03-09 17:40:52 -05:00
reload: ->
document.location.reload()