Extract styles and scripts

This commit is contained in:
phoenixeliot 2016-07-20 15:44:01 -07:00
parent 5bb7f243f5
commit 62813e41a3
3 changed files with 67 additions and 19 deletions

View file

@ -2,8 +2,8 @@
window.addEventListener('message', receiveMessage, false);
var concreteDOM;
var virtualDOM;
var concreteDom;
var virtualDom;
var goalStates;
var allowedOrigins = [
@ -19,7 +19,7 @@ function receiveMessage(event) {
var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
var allowed = false;
allowedOrigins.forEach(function(pattern) {
allowed = allowed || pattern.test(origin);
allowed = allowed || pattern.test(origin);
});
if (!allowed) {
console.log('Ignoring message from bad origin:', origin);
@ -30,14 +30,14 @@ function receiveMessage(event) {
var source = event.source;
switch (data.type) {
case 'create':
create(data.dom);
create(_.pick(data, 'dom', 'styles', 'scripts'));
checkGoals(data.goals, source, origin);
break;
case 'update':
if (virtualDOM)
update(data.dom);
if (virtualDom)
update(_.pick(data, 'dom', 'styles', 'scripts'));
else
create(data.dom);
create(_.pick(data, 'dom', 'styles', 'scripts'));
checkGoals(data.goals, source, origin);
break;
case 'log':
@ -48,20 +48,40 @@ function receiveMessage(event) {
}
}
function create(dom) {
virtualDOM = dom;
concreteDOM = deku.dom.create(dom);
function create({ dom, styles, scripts }) {
virtualDom = dom;
virtualStyles = styles;
virtualScripts = scripts;
concreteDom = deku.dom.create(dom);
concreteStyles = styles.map(function(style){return deku.dom.create(style)});
concreteScripts = scripts.map(function(script){return deku.dom.create(script)});
// TODO: target the actual HTML tag and combine our initial structure for styles/scripts/tags with theirs
// TODO: :after elements don't seem to work? (:before do)
$('body').empty().append(concreteDOM);
$('body').first().empty().append(concreteDom);
$('#player-styles').first().empty().append(concreteStyles);
$('#player-scripts').first().empty().append(concreteScripts);
}
function update(dom) {
function update({ dom, styles, scripts }) {
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, dom);
changes.reduce(deku.dom.update(dispatch, context), concreteDOM); // Rerender
virtualDOM = dom;
var domChanges = deku.diff.diffNode(virtualDom, dom);
domChanges.reduce(deku.dom.update(dispatch, context), concreteDom); // Rerender
var scriptChanges = virtualScripts.map(function(virtualScript, index){
return deku.diff.diffNode(virtualScripts[index], scripts[index]);
});
scriptChanges.forEach(function(scriptChange, index){
scriptChange.reduce(deku.dom.update(dispatch, context), concreteStyles[index])
});
var styleChanges = virtualStyles.map(function(virtualStyle, index){
return deku.diff.diffNode(virtualStyles[index], styles[index]);
});
styleChanges.forEach(function(styleChange, index){
styleChange.reduce(deku.dom.update(dispatch, context), concreteStyles[index])
});
virtualDom = dom;
}
function checkGoals(goals, source, origin) {

View file

@ -30,6 +30,12 @@
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<!-- Extracted player/level styles and scripts -->
<style id="player-styles">
</style>
<script id="player-scripts">
</script>
</head>
<body>
<h1>Loading...</h1>

View file

@ -31,18 +31,40 @@ module.exports = class WebSurfaceView extends CocoView
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
{ virtualDom, styles, scripts } = @extractStylesAndScripts(@dekuify html)
messageType = if e.create or not @virtualDom then 'create' else 'update'
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDom, styles, scripts, 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
elem.attribs = _.omit elem.attribs, (val, attr) -> attr.indexOf('<') > -1 # Deku chokes on `<thing <p></p>`
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 ? []))
extractStylesAndScripts: (dekuTree) ->
#base case
if dekuTree.type is '#text'
return { virtualDom: dekuTree, styles: [], scripts: [] }
if dekuTree.type is 'style'
console.log 'Found a style: ', dekuTree
return { styles: [dekuTree], scripts: [] }
if dekuTree.type is 'script'
console.log 'Found a script: ', dekuTree
return { styles: [], scripts: [dekuTree] }
# recurse over children
childStyles = []
childScripts = []
dekuTree.children?.forEach (dekuChild, index) =>
{ virtualDom, styles, scripts } = @extractStylesAndScripts(dekuChild)
dekuTree.children[index] = virtualDom
childStyles = childStyles.concat(styles)
childScripts = childScripts.concat(scripts)
dekuTree.children = _.filter dekuTree.children # Remove the nodes we extracted
return { virtualDom: dekuTree, scripts: childScripts, styles: childStyles }
onIframeMessage: (event) =>
origin = event.origin or event.originalEvent.origin