codecombat/app/views/play/level/WebSurfaceView.coffee

65 lines
2.7 KiB
CoffeeScript

CocoView = require 'views/core/CocoView'
State = require 'models/State'
template = require 'templates/play/level/web-surface-view'
module.exports = class WebSurfaceView extends CocoView
id: 'web-surface-view'
template: template
subscriptions:
'tome:html-updated': 'onHTMLUpdated'
initialize: (options) ->
@state = new State
blah: 'blah'
@goals = (goal for goal in options.goalManager.goals when goal.html)
# Consider https://www.npmjs.com/package/css-select to do this on virtualDOM instead of in iframe on concreteDOM
super(options)
afterRender: ->
super()
@iframe = @$('iframe')[0]
$(@iframe).on 'load', (e) =>
window.addEventListener 'message', @onIframeMessage
#@iframe.contentWindow.postMessage {type: 'log', text: 'Player HTML iframe is ready.'}, "*"
@iframeLoaded = true
@onIframeLoaded?()
@onIframeLoaded = null
# TODO: make clicking Run actually trigger a 'create' update here (for resetting scripts)
onHTMLUpdated: (e) ->
unless @iframeLoaded
return @onIframeLoaded = => @onHTMLUpdated e unless @destroyed
dom = htmlparser2.parseDOM e.html, {}
body = _.find(dom, name: 'body') ? {name: 'body', attribs: null, children: dom}
html = _.find(dom, name: 'html') ? {name: 'html', attribs: null, children: [body]}
# TODO: pull out the actual scripts, styles, and body/elements they are doing so we can merge them with our initial structure on the other side
virtualDOM = @dekuify html
messageType = if e.create or not @virtualDOM then 'create' else 'update'
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM, goals: @goals}, '*'
@virtualDOM = virtualDOM
dekuify: (elem) ->
return elem.data if elem.type is 'text'
return null if elem.type is 'comment' # TODO: figure out how to make a comment in virtual dom
unless elem.name
console.log("Failed to dekuify", elem)
return elem.type
deku.element(elem.name, elem.attribs, (@dekuify(c) for c in elem.children ? []))
onIframeMessage: (e) =>
origin = e.origin or e.originalEvent.origin
unless origin in ['https://codecombat.com', 'http://localhost:3000']
return console.log 'Ignoring message from bad origin:', origin
unless event.source is @iframe.contentWindow
return console.log 'Ignoring message from somewhere other than our iframe:', event.source
switch event.data.type
when 'goals-updated'
Backbone.Mediator.publish 'god:new-html-goal-states', goalStates: event.data.goalStates, overallStatus: event.data.overallStatus
else
console.warn 'Unknown message type', event.data.type, 'for message', e, 'from origin', origin
destroy: ->
window.removeEventListener 'message', @onIframeMessage
super()