mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Sending goal states to GoalManager and GoalStatusView
This commit is contained in:
parent
c44c16e5d2
commit
739973cb47
4 changed files with 52 additions and 24 deletions
|
@ -1,27 +1,36 @@
|
|||
// TODO: don't serve this script from codecombat.com; serve it from a harmless extra domain we don't have yet.
|
||||
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
window.addEventListener('message', receiveMessage, false);
|
||||
|
||||
var concreteDOM;
|
||||
var virtualDOM;
|
||||
var goalStates;
|
||||
|
||||
var allowedOrigins = [
|
||||
'https://codecombat.com',
|
||||
'http://localhost:3000',
|
||||
'http://direct.codecombat.com',
|
||||
'http://staging.codecombat.com'
|
||||
];
|
||||
|
||||
function receiveMessage(event) {
|
||||
var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
|
||||
if (origin != 'https://codecombat.com' && origin != 'http://localhost:3000') {
|
||||
console.log("Bad origin:", origin);
|
||||
if (allowedOrigins.indexOf(origin) == -1) {
|
||||
console.log('Ignoring message from bad origin:', origin);
|
||||
return;
|
||||
}
|
||||
//console.log(event);
|
||||
switch (event.data.type) {
|
||||
case 'create':
|
||||
create(event.data.dom);
|
||||
checkGoals(event.data.goals);
|
||||
checkGoals(event.data.goals, event.source);
|
||||
break;
|
||||
case 'update':
|
||||
if (virtualDOM)
|
||||
update(event.data.dom);
|
||||
else
|
||||
create(event.data.dom);
|
||||
checkGoals(event.data.goals);
|
||||
checkGoals(event.data.goals, event.source);
|
||||
break;
|
||||
case 'log':
|
||||
console.log(event.data.text);
|
||||
|
@ -29,8 +38,6 @@ function receiveMessage(event) {
|
|||
default:
|
||||
console.log('Unknown message type:', event.data.type);
|
||||
}
|
||||
|
||||
//event.source.postMessage("hi there yourself! the secret response is: rheeeeet!", event.origin);
|
||||
}
|
||||
|
||||
function create(dom) {
|
||||
|
@ -44,21 +51,29 @@ function update(dom) {
|
|||
function dispatch() {} // Might want to do something here in the future
|
||||
var context = {}; // Might want to use this to send shared state to every component
|
||||
var changes = deku.diff.diffNode(virtualDOM, event.data.dom);
|
||||
changes.reduce(deku.dom.update(dispatch, context), concreteDOM) // Rerender
|
||||
changes.reduce(deku.dom.update(dispatch, context), concreteDOM); // Rerender
|
||||
virtualDOM = event.data.dom;
|
||||
}
|
||||
|
||||
function checkGoals(goals) {
|
||||
var newGoalStates = {};
|
||||
var overallSuccess = true;
|
||||
goals.forEach(function(goal) {
|
||||
var $result = $(goal.html.selector);
|
||||
//console.log('ran selector', goal.html.selector, 'to find element(s)', $result);
|
||||
var success = true;
|
||||
goal.html.valueChecks.forEach(function(check) {
|
||||
//console.log(' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps'), '?', matchesCheck($result, check))
|
||||
success = success && matchesCheck($result, check)
|
||||
success = success && matchesCheck($result, check);
|
||||
});
|
||||
console.log('HTML', goal.id, '-', goal.name, '- succeeds?', success)
|
||||
overallSuccess = overallSuccess && success;
|
||||
newGoalStates[goal.id] = {status: success ? 'success' : 'incomplete'}; // No 'failure' state
|
||||
});
|
||||
if (!_.isEqual(newGoalStates, goalStates)) {
|
||||
goalStates = newGoalStates;
|
||||
var overallStatus = overallSuccess ? 'success' : null; // Can't really get to 'failure', just 'incomplete', which is represented by null here
|
||||
event.source.postMessage({type: 'goals-updated', goalStates: goalStates, overallStatus: overallStatus}, event.origin);
|
||||
}
|
||||
}
|
||||
|
||||
function downTheChain(obj, keyChain) {
|
||||
|
@ -71,7 +86,7 @@ function downTheChain(obj, keyChain) {
|
|||
if (keyChain[0].match(/\(.*\)$/)) {
|
||||
var args, argsString = keyChain[0].match(/\((.*)\)$/)[1];
|
||||
if (argsString)
|
||||
args = eval(argsString).split(/, ?/g).filter(function(x) { return x !== ""; }); // TODO: can/should we avoid eval here?
|
||||
args = eval(argsString).split(/, ?/g).filter(function(x) { return x !== ''; }); // TODO: can/should we avoid eval here?
|
||||
else
|
||||
args = [];
|
||||
value = value[keyChain[0].split('(')[0]].apply(value, args); // value.text(), value.css('background-color'), etc.
|
||||
|
|
|
@ -38,8 +38,8 @@ module.exports = class GoalManager extends CocoClass
|
|||
|
||||
subscriptions:
|
||||
'god:new-world-created': 'onNewWorldCreated'
|
||||
'god:new-html-goal-states': 'onNewHTMLGoalStates'
|
||||
'level:restarted': 'onLevelRestarted'
|
||||
#'tome:html-updated': 'onHTMLUpdated'
|
||||
|
||||
backgroundSubscriptions:
|
||||
'world:thang-died': 'onThangDied'
|
||||
|
@ -87,6 +87,9 @@ module.exports = class GoalManager extends CocoClass
|
|||
@world = e.world
|
||||
@updateGoalStates(e.goalStates) if e.goalStates?
|
||||
|
||||
onNewHTMLGoalStates: (e) ->
|
||||
@updateGoalStates(e.goalStates) if e.goalStates?
|
||||
|
||||
updateGoalStates: (newGoalStates) ->
|
||||
for goalID, goalState of newGoalStates
|
||||
continue unless @goalStates[goalID]?
|
||||
|
@ -221,11 +224,6 @@ module.exports = class GoalManager extends CocoClass
|
|||
return unless linesAllowed = who[thang.id] ? who[thang.team]
|
||||
@updateGoalState goalID, thang.id, 'lines', frameNumber if linesUsed > linesAllowed
|
||||
|
||||
#checkHTML: (goal, html) ->
|
||||
# console.log 'should run selector', goal.html.selector, 'to find element(s)'
|
||||
# console.log ' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps') for check in goal.html.valueChecks
|
||||
# console.log 'should do it with cheerio', window.cheerio
|
||||
|
||||
wrapUpGoalStates: (finalFrame) ->
|
||||
for goalID, state of @goalStates
|
||||
if state.status is null
|
||||
|
@ -320,9 +318,6 @@ module.exports = class GoalManager extends CocoClass
|
|||
linesOfCode: 0
|
||||
codeProblems: 0
|
||||
|
||||
#onHTMLUpdated: (e) ->
|
||||
# @checkHTML goal, e.html for goal in @goals when goal.html
|
||||
|
||||
updateCodeGoalStates: ->
|
||||
# TODO
|
||||
|
||||
|
|
|
@ -45,6 +45,10 @@ module.exports =
|
|||
|
||||
'god:streaming-world-updated': worldUpdatedEventSchema
|
||||
|
||||
'god:new-html-goal-states': c.object {required: ['goalStates', 'overallStatus']},
|
||||
goalStates: goalStatesSchema
|
||||
overallStatus: {type: ['string', 'null'], enum: ['success', 'failure', 'incomplete', null]}
|
||||
|
||||
'god:goals-calculated': c.object {required: ['goalStates', 'god']},
|
||||
god: {type: 'object'}
|
||||
goalStates: goalStatesSchema
|
||||
|
|
|
@ -20,7 +20,8 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
super()
|
||||
@iframe = @$('iframe')[0]
|
||||
$(@iframe).on 'load', (e) =>
|
||||
@iframe.contentWindow.postMessage {type: 'log', text: 'Player HTML iframe is ready.'}, "*"
|
||||
window.addEventListener 'message', @onIframeMessage
|
||||
#@iframe.contentWindow.postMessage {type: 'log', text: 'Player HTML iframe is ready.'}, "*"
|
||||
@iframeLoaded = true
|
||||
@onIframeLoaded?()
|
||||
@onIframeLoaded = null
|
||||
|
@ -39,9 +40,6 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM, goals: @goals}, '*'
|
||||
@virtualDOM = virtualDOM
|
||||
|
||||
checkGoals: (dom) ->
|
||||
# TODO: uhh, figure these out
|
||||
|
||||
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
|
||||
|
@ -49,3 +47,19 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
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()
|
||||
|
|
Loading…
Reference in a new issue