283 lines · 8.4 KB · Text
RawDownload
@app =  _$: $  _$$: $$  _page: page  collections: {}  models:      {}  templates:   {}  views:       {}   init: ->    try @initErrorTracking() catch    return unless @browserCheck()     @el = $('._app')    @localStorage = new LocalStorageStore    @serviceWorker = new app.ServiceWorker if app.ServiceWorker.isEnabled()    @settings = new app.Settings    @db = new app.DB()     @settings.initLayout()     @docs = new app.collections.Docs    @disabledDocs = new app.collections.Docs    @entries = new app.collections.Entries     @router = new app.Router    @shortcuts = new app.Shortcuts    @document = new app.views.Document    @mobile = new app.views.Mobile if @isMobile()     if document.body.hasAttribute('data-doc')      @DOC = JSON.parse(document.body.getAttribute('data-doc'))      @bootOne()    else if @DOCS      @bootAll()    else      @onBootError()    return   browserCheck: ->    return true if @isSupportedBrowser()    document.body.innerHTML = app.templates.unsupportedBrowser    @hideLoadingScreen()    false   initErrorTracking: ->    # Show a warning message and don't track errors when the app is loaded    # from a domain other than our own, because things are likely to break.    # (e.g. cross-domain requests)    if @isInvalidLocation()      new app.views.Notif 'InvalidLocation'    else      if @config.sentry_dsn        Raven.config @config.sentry_dsn,          release: @config.release          whitelistUrls: [/devdocs/]          includePaths: [/devdocs/]          ignoreErrors: [/NPObject/, /NS_ERROR/, /^null$/, /EvalError/]          tags:            mode: if @isSingleDoc() then 'single' else 'full'            iframe: (window.top isnt window).toString()            electron: (!!window.process?.versions?.electron).toString()          shouldSendCallback: =>            try              if @isInjectionError()                @onInjectionError()                return false              if @isAndroidWebview()                return false            true          dataCallback: (data) ->            try              $.extend(data.user ||= {}, app.settings.dump())              data.user.docs = data.user.docs.split('/') if data.user.docs              data.user.lastIDBTransaction = app.lastIDBTransaction if app.lastIDBTransaction              data.tags.scriptCount = document.scripts.length            data        .install()      @previousErrorHandler = onerror      window.onerror = @onWindowError.bind(@)      CookiesStore.onBlocked = @onCookieBlocked    return   bootOne: ->    @doc = new app.models.Doc @DOC    @docs.reset [@doc]    @doc.load @start.bind(@), @onBootError.bind(@), readCache: true    new app.views.Notice 'singleDoc', @doc    delete @DOC    return   bootAll: ->    docs = @settings.getDocs()    for doc in @DOCS      (if docs.indexOf(doc.slug) >= 0 then @docs else @disabledDocs).add(doc)    @migrateDocs()    @docs.load @start.bind(@), @onBootError.bind(@), readCache: true, writeCache: true    delete @DOCS    return   start: ->    @entries.add doc.toEntry() for doc in @docs.all()    @entries.add doc.toEntry() for doc in @disabledDocs.all()    @initDoc(doc) for doc in @docs.all()    @trigger 'ready'    @router.start()    @hideLoadingScreen()    setTimeout =>      @welcomeBack() unless @doc      @removeEvent 'ready bootError'    , 50    return   initDoc: (doc) ->    doc.entries.add type.toEntry() for type in doc.types.all()    @entries.add doc.entries.all()    return   migrateDocs: ->    for slug in @settings.getDocs() when not @docs.findBy('slug', slug)      needsSaving = true      doc = @disabledDocs.findBy('slug', 'webpack') if slug == 'webpack~2'      doc = @disabledDocs.findBy('slug', 'angular') if slug == 'angular~4_typescript'      doc = @disabledDocs.findBy('slug', 'angular~2') if slug == 'angular~2_typescript'      doc ||= @disabledDocs.findBy('slug_without_version', slug)      if doc        @disabledDocs.remove(doc)        @docs.add(doc)     @saveDocs() if needsSaving    return   enableDoc: (doc, _onSuccess, onError) ->    return if @docs.contains(doc)     onSuccess = =>      return if @docs.contains(doc)      @disabledDocs.remove(doc)      @docs.add(doc)      @docs.sort()      @initDoc(doc)      @saveDocs()      if app.settings.get('autoInstall')        doc.install(_onSuccess, onError)      else        _onSuccess()      return     doc.load onSuccess, onError, writeCache: true    return   saveDocs: ->    @settings.setDocs(doc.slug for doc in @docs.all())    @db.migrate()    @serviceWorker?.updateInBackground()   welcomeBack: ->    visitCount = @settings.get('count')    @settings.set 'count', ++visitCount    new app.views.Notif 'Share', autoHide: null if visitCount is 5    new app.views.News()    new app.views.Updates()    @updateChecker = new app.UpdateChecker()   reboot: ->    if location.pathname isnt '/' and location.pathname isnt '/settings'      window.location = "/##{location.pathname}"    else      window.location = '/'    return   reload: ->    @docs.clearCache()    @disabledDocs.clearCache()    if @serviceWorker then @serviceWorker.reload() else @reboot()    return   reset: ->    @localStorage.reset()    @settings.reset()    @db?.reset()    @serviceWorker?.update()    window.location = '/'    return   showTip: (tip) ->    return if @isSingleDoc()    tips = @settings.getTips()    if tips.indexOf(tip) is -1      tips.push(tip)      @settings.setTips(tips)      new app.views.Tip(tip)    return   hideLoadingScreen: ->    document.body.classList.add '_overlay-scrollbars' if $.overlayScrollbarsEnabled()    document.documentElement.classList.remove '_booting'    return   indexHost: ->    # Can't load the index files from the host/CDN when service worker is    # enabled because it doesn't support caching URLs that use CORS.    @config[if @serviceWorker and @settings.hasDocs() then 'index_path' else 'docs_origin']   onBootError: (args...) ->    @trigger 'bootError'    @hideLoadingScreen()    return   onQuotaExceeded: ->    return if @quotaExceeded    @quotaExceeded = true    new app.views.Notif 'QuotaExceeded', autoHide: null    return   onCookieBlocked: (key, value, actual) ->    return if @cookieBlocked    @cookieBlocked = true    new app.views.Notif 'CookieBlocked', autoHide: null    Raven.captureMessage "CookieBlocked/#{key}", level: 'warning', extra: {value, actual}    return   onWindowError: (args...) ->    return if @cookieBlocked    if @isInjectionError args...      @onInjectionError()    else if @isAppError args...      @previousErrorHandler? args...      @hideLoadingScreen()      @errorNotif or= new app.views.Notif 'Error'      @errorNotif.show()    return   onInjectionError: ->    unless @injectionError      @injectionError = true      alert """        JavaScript code has been injected in the page which prevents DevDocs from running correctly.        Please check your browser extensions/addons. """      Raven.captureMessage 'injection error', level: 'info'    return   isInjectionError: ->    # Some browser extensions expect the entire web to use jQuery.    # I gave up trying to fight back.    window.$ isnt app._$ or window.$$ isnt app._$$ or window.page isnt app._page or typeof $.empty isnt 'function' or typeof page.show isnt 'function'   isAppError: (error, file) ->    # Ignore errors from external scripts.    file and file.indexOf('devdocs') isnt -1 and file.indexOf('.js') is file.length - 3   isSupportedBrowser: ->    try      features =        bind:               !!Function::bind        pushState:          !!history.pushState        matchMedia:         !!window.matchMedia        insertAdjacentHTML: !!document.body.insertAdjacentHTML        defaultPrevented:     document.createEvent('CustomEvent').defaultPrevented is false        cssVariables:       !!CSS?.supports?('(--t: 0)')       for key, value of features when not value        Raven.captureMessage "unsupported/#{key}", level: 'info'        return false       true    catch error      Raven.captureMessage 'unsupported/exception', level: 'info', extra: { error: error }      false   isSingleDoc: ->    document.body.hasAttribute('data-doc')   isMobile: ->    @_isMobile ?= app.views.Mobile.detect()   isAndroidWebview: ->    @_isAndroidWebview ?= app.views.Mobile.detectAndroidWebview()   isInvalidLocation: ->    @config.env is 'production' and location.host.indexOf(app.config.production_host) isnt 0 $.extend app, Events