mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-11 00:02:19 -05:00
663c220eaf
This heavily refactors SpellView and adds infrastructure for receiving and reporting Errors raised by the web-dev iFrame. The web-dev error system, the Aether error system, and the Ace html-worker avoid disturbing each others' errors/annotations (though currently Aether+web-dev errors won't coexist), and they clear/update their own asynchronously. Show web-dev iFrame errors as Ace annotations Add functional error banners (with poor messages) Improve error banners, don't allow duplicate Problems Refactor setAnnotations override Convert all constructor calls for Problems Add comments, clean up Clean up Don't clear things unnecessarily Clean up error message sending from iFrame Add web-dev:error schema Clarify error message attributes Refactor displaying AetherProblems Refactor displaying user problem banners Refactor onWebDevError Set ace styles on updating @problems Clean up, fix off-by-1 error Add comment Show stale web-dev errors differently Some web-dev errors are generated by "stale" code — code that's still running in the iFrame but doesn't have the player's recent changes. This shows those errors differently than if they weren't "stale", and suggests they re-run their code. Hook up web-dev event schema Destroy ignored duplicate problems Functionalize a bit of stuff Fix ProblemAlertView never loading
169 lines
6 KiB
CoffeeScript
169 lines
6 KiB
CoffeeScript
Backbone.Mediator.setValidationEnabled false
|
|
app = null
|
|
|
|
channelSchemas =
|
|
'auth': require 'schemas/subscriptions/auth'
|
|
'bus': require 'schemas/subscriptions/bus'
|
|
'editor': require 'schemas/subscriptions/editor'
|
|
'errors': require 'schemas/subscriptions/errors'
|
|
'ipad': require 'schemas/subscriptions/ipad'
|
|
'misc': require 'schemas/subscriptions/misc'
|
|
'play': require 'schemas/subscriptions/play'
|
|
'surface': require 'schemas/subscriptions/surface'
|
|
'tome': require 'schemas/subscriptions/tome'
|
|
'god': require 'schemas/subscriptions/god'
|
|
'scripts': require 'schemas/subscriptions/scripts'
|
|
'web-dev': require 'schemas/subscriptions/web-dev'
|
|
'world': require 'schemas/subscriptions/world'
|
|
|
|
definitionSchemas =
|
|
'bus': require 'schemas/definitions/bus'
|
|
'misc': require 'schemas/definitions/misc'
|
|
|
|
init = ->
|
|
return if app
|
|
if not window.userObject._id
|
|
$.ajax '/auth/whoami', cache: false, success: (res) ->
|
|
window.userObject = res
|
|
init()
|
|
return
|
|
|
|
app = require 'core/application'
|
|
setupConsoleLogging()
|
|
watchForErrors()
|
|
setUpIOSLogging()
|
|
path = document.location.pathname
|
|
app.testing = _.string.startsWith path, '/test'
|
|
app.demoing = _.string.startsWith path, '/demo'
|
|
setUpBackboneMediator()
|
|
app.initialize()
|
|
loadOfflineFonts() unless app.isProduction()
|
|
Backbone.history.start({ pushState: true })
|
|
handleNormalUrls()
|
|
setUpMoment() # Set up i18n for moment
|
|
|
|
module.exports.init = init
|
|
|
|
handleNormalUrls = ->
|
|
# http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/
|
|
$(document).on 'click', "a[href^='/']", (event) ->
|
|
|
|
href = $(event.currentTarget).attr('href')
|
|
|
|
# chain 'or's for other black list routes
|
|
passThrough = href.indexOf('sign_out') >= 0
|
|
|
|
# Allow shift+click for new tabs, etc.
|
|
if !passThrough && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey
|
|
event.preventDefault()
|
|
|
|
# Remove leading slashes and hash bangs (backward compatablility)
|
|
url = href.replace(/^\//,'').replace('\#\!\/','')
|
|
|
|
# Instruct Backbone to trigger routing events
|
|
app.router.navigate url, { trigger: true }
|
|
|
|
return false
|
|
|
|
setUpBackboneMediator = ->
|
|
Backbone.Mediator.addDefSchemas schemas for definition, schemas of definitionSchemas
|
|
Backbone.Mediator.addChannelSchemas schemas for channel, schemas of channelSchemas
|
|
Backbone.Mediator.setValidationEnabled document.location.href.search(/codecombat.com/) is -1
|
|
if false # Debug which events are being fired
|
|
originalPublish = Backbone.Mediator.publish
|
|
Backbone.Mediator.publish = ->
|
|
console.log 'Publishing event:', arguments... unless /(tick|frame-changed)/.test(arguments[0])
|
|
originalPublish.apply Backbone.Mediator, arguments
|
|
|
|
setUpMoment = ->
|
|
{me} = require 'core/auth'
|
|
moment.lang me.get('preferredLanguage', true), {}
|
|
me.on 'change:preferredLanguage', (me) ->
|
|
moment.lang me.get('preferredLanguage', true), {}
|
|
|
|
setupConsoleLogging = ->
|
|
# IE9 doesn't expose console object unless debugger tools are loaded
|
|
unless console?
|
|
window.console =
|
|
info: ->
|
|
log: ->
|
|
error: ->
|
|
debug: ->
|
|
unless console.debug
|
|
# Needed for IE10 and earlier
|
|
console.debug = console.log
|
|
|
|
watchForErrors = ->
|
|
currentErrors = 0
|
|
window.onerror = (msg, url, line, col, error) ->
|
|
return if currentErrors >= 3
|
|
return unless me.isAdmin() or document.location.href.search(/codecombat.com/) is -1 or document.location.href.search(/\/editor\//) isnt -1
|
|
++currentErrors
|
|
message = "Error: #{msg}<br>Check the JS console for more."
|
|
#msg += "\nLine: #{line}" if line?
|
|
#msg += "\nColumn: #{col}" if col?
|
|
#msg += "\nError: #{error}" if error?
|
|
#msg += "\nStack: #{stack}" if stack = error?.stack
|
|
unless webkit?.messageHandlers # Don't show these notys on iPad
|
|
noty text: message, layout: 'topCenter', type: 'error', killer: false, timeout: 5000, dismissQueue: true, maxVisible: 3, callback: {onClose: -> --currentErrors}
|
|
Backbone.Mediator.publish 'application:error', message: "Line #{line} of #{url}:\n#{msg}" # For iOS app
|
|
|
|
window.addIPadSubscription = (channel) ->
|
|
window.iPadSubscriptions[channel] = true
|
|
|
|
window.removeIPadSubscription = (channel) ->
|
|
window.iPadSubscriptions[channel] = false
|
|
|
|
setUpIOSLogging = ->
|
|
return unless webkit?.messageHandlers
|
|
for level in ['debug', 'log', 'info', 'warn', 'error']
|
|
do (level) ->
|
|
originalLog = console[level]
|
|
console[level] = ->
|
|
originalLog.apply console, arguments
|
|
try
|
|
webkit?.messageHandlers?.consoleLogHandler?.postMessage level: level, arguments: (a?.toString?() ? ('' + a) for a in arguments)
|
|
catch e
|
|
webkit?.messageHandlers?.consoleLogHandler?.postMessage level: level, arguments: ['could not post log: ' + e]
|
|
|
|
loadOfflineFonts = ->
|
|
$('head').prepend '<link rel="stylesheet" type="text/css" href="/fonts/openSansCondensed.css">'
|
|
$('head').prepend '<link rel="stylesheet" type="text/css" href="/fonts/openSans.css">'
|
|
|
|
# This is so hacky... hopefully it's restrictive enough to not be slow.
|
|
# We could also keep a list of events we are actually subscribed for and only try to send those over.
|
|
seen = null
|
|
window.serializeForIOS = serializeForIOS = (obj, depth=3) ->
|
|
return {} unless depth
|
|
root = not seen?
|
|
seen ?= []
|
|
clone = {}
|
|
keysHandled = 0
|
|
for own key, value of obj
|
|
continue if ++keysHandled > 50
|
|
if not value
|
|
clone[key] = value
|
|
else if value is window or value.firstElementChild or value.preventDefault
|
|
null # Don't include these things
|
|
else if value in seen
|
|
null # No circular references
|
|
else if _.isArray value
|
|
clone[key] = (serializeForIOS(child, depth - 1) for child in value)
|
|
seen.push value
|
|
else if _.isObject value
|
|
value = value.attributes if value.id and value.attributes
|
|
clone[key] = serializeForIOS value, depth - 1
|
|
seen.push value
|
|
else
|
|
clone[key] = value
|
|
seen = null if root
|
|
clone
|
|
|
|
window.onbeforeunload = (e) ->
|
|
leavingMessage = _.result(window.currentView, 'onLeaveMessage')
|
|
if leavingMessage
|
|
return leavingMessage
|
|
else
|
|
return
|
|
|
|
$ -> init()
|