SuperModel = require 'models/SuperModel' utils = require 'lib/utils' CocoClass = require 'lib/CocoClass' loadingScreenTemplate = require 'templates/loading' visibleModal = null waitingModal = null classCount = 0 makeScopeName = -> "view-scope-#{classCount++}" module.exports = class CocoView extends Backbone.View startsLoading: false cache: true # signals to the router to keep this view around template: => '' events: 'click a': 'toggleModal' 'click button': 'toggleModal' subscriptions: {} shortcuts: {} # Setup, Teardown constructor: (options) -> @supermodel ?= options?.supermodel or new SuperModel() @options = options @subscriptions = utils.combineAncestralObject(@, 'subscriptions') @events = utils.combineAncestralObject(@, 'events') @scope = makeScopeName() @shortcuts = utils.combineAncestralObject(@, 'shortcuts') @subviews = {} @listenToShortcuts() # Backbone.Mediator handles subscription setup/teardown automatically super options destroy: -> @destroyed = true @stopListening() @stopListeningToShortcuts() @undelegateEvents() # removes both events and subs view.destroy() for id, view of @subviews afterInsert: -> willDisappear: -> # the router removes this view but this view will be cached @undelegateEvents() @hidden = true @stopListeningToShortcuts() view.willDisappear() for id, view of @subviews didReappear: -> # the router brings back this view from the cache @delegateEvents() @hidden = false @listenToShortcuts() view.didReappear() for id, view of @subviews # View Rendering render: => return @ unless me super() return @template if _.isString(@template) @$el.html @template(@getRenderData()) @afterRender() @showLoading() if @startsLoading @$el.i18n() @ getRenderData: (context) => context ?= {} context.isProduction = document.location.href.search(/codecombat.com/) isnt -1 context.me = me context.pathname = document.location.pathname # like "/play/level" context.fbRef = context.pathname.replace(/[^a-zA-Z0-9+/=\-.:_]/g, '').slice(0, 40) or 'home' context.isMobile = @isMobile() context.isIE = @isIE() context afterRender: -> @registerModalsWithin() # Modals toggleModal: (e) -> if $(e.currentTarget).prop('target') is '_blank' return true # special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value. elem = $(e.target) return unless elem.data('toggle') is 'coco-modal' target = elem.data('target') view = application.router.getView(target, '_modal') # could set up a system for loading cached modals, if told to @openModalView(view) registerModalsWithin: (e...) -> # TODO: Get rid of this part for modal in $('.modal', @$el) # console.warn 'Registered modal to get rid of...', modal $(modal).on('show', @clearModals) openModalView: (modalView) -> return if @waitingModal # can only have one waiting at once if visibleModal waitingModal = modalView visibleModal.hide() return modalView.render() $('#modal-wrapper').empty().append modalView.el modalView.afterInsert() visibleModal = modalView modalOptions = {show: true, backdrop: if modalView.closesOnClickOutside then true else 'static'} $('#modal-wrapper .modal').modal(modalOptions).on('hidden', => @modalClosed()) window.currentModal = modalView @getRootView().stopListeningToShortcuts(true) modalClosed: => visibleModal.willDisappear() if visibleModal visibleModal.destroy() visibleModal = null if waitingModal wm = waitingModal waitingModal = null @openModalView(wm) else @getRootView().listenToShortcuts(true) Backbone.Mediator.publish 'modal-closed' clearModals: => if visibleModal visibleModal.$el.addClass('hide') waitingModal = null @modalClosed() # Loading RootViews showLoading: ($el=@$el) -> $el.find('>').addClass('hide') $el.append($('
') .append('