Skip to content

Commit

Permalink
Merge pull request #1063 from waterbearlang/1059-single-step-blocks
Browse files Browse the repository at this point in the history
Single Step Blocks... sort of!
  • Loading branch information
dethe committed Mar 27, 2015
2 parents ef18060 + 531d9b9 commit 5fb1c2b
Show file tree
Hide file tree
Showing 7 changed files with 654 additions and 80 deletions.
4 changes: 4 additions & 0 deletions css/app.css
Expand Up @@ -51,6 +51,10 @@ body > header > h1{
padding: 0px;
}

.menu button[disabled] {
color: #999;
border-color: #333;
}

.menu button, .menu a, .do-run, .do-stop{

Expand Down
7 changes: 7 additions & 0 deletions css/block.css
Expand Up @@ -149,6 +149,13 @@ wb-context[closed] > wb-contains{
display: none;
}

/* TODO: Better styles for paused. */
wb-step[script].wb-paused,
wb-context[script].wb-paused {
background-color: #EEE;
border-color: #CCC;
}

.hide{
display: none;
}
Expand Down
31 changes: 21 additions & 10 deletions js/app.js
@@ -1,6 +1,8 @@
(function(){
'use strict';

var process;

// FIXME: This feedback is important and useful, but using it this way violates
// our localization principle: All user-visible text should be in HTML text,
// not attributes, CSS, or JavaScript. Once the messages have stabilized, move them
Expand Down Expand Up @@ -79,6 +81,12 @@ Event.on(document.body, 'ui:click', '.show-tutorial', function(evt){

Event.on('.do-run', 'ui:click', null, startScript);
Event.on('.do-stop', 'ui:click', null, stopScript);
Event.on('.do-pause', 'ui:click', null, function () {
/* TODO */
});
Event.on('.do-step', 'ui:click', null, function () {
/* TODO */
});

function startScript(evt){
// Do any necessary cleanup (e.g., clear event handlers).
Expand All @@ -89,11 +97,16 @@ function startScript(evt){
preload().whenLoaded(runScript);
}

function stopScript(evt){
runtime.stopEventLoop();
function stopScript(evt) {
if (process) {
process.terminate();
/* Throw out the now-useless process. */
process = null;
runtime.stopEventLoop();
runtime.clear();
}
evt.target.blur();
runtime.getStage().focus()
runtime.clear();
runtime.getStage().focus();
}

function stopAndClearScripts(){
Expand All @@ -114,13 +127,11 @@ function preload() {
}

function runScript(){
var globalScope = {};
runtime.startEventLoop();
dom.findAll('wb-workspace > wb-contains > *').forEach(function(block){
if (block.run){
block.run(globalScope);
}
});
console.assert(!process, 'Tried to run, but Process instance already exists!');
/* Create brand new Process instance (because each process can only be
* started once). */
process = new WaterbearProcess().start();
}

function handleFileButton(evt){
Expand Down
69 changes: 54 additions & 15 deletions js/block.js
Expand Up @@ -113,6 +113,12 @@ BlockProto.gatherValues = function(scope){
return value.getValue(scope);
});
};
/* Applicable for both <wb-step> and <wb-context>.
* The next element is simply the nextElementSibling. */
BlockProto.next = function() {
return this.nextElementSibling;
};


/*****************
*
Expand All @@ -133,7 +139,6 @@ StepProto.run = function(scope){
this.fn = runtime[fnName[0]][fnName[1]];
}
_gaq.push(['_trackEvent', 'Blocks', this.getAttribute('script')]);
// console.log('calling step %s with scope %s, values %o', this.getAttribute('script'), scope, this.gatherValues(scope));
return this.fn.apply(scope, this.gatherValues(scope));
};
window.WBStep = document.registerElement('wb-step', {prototype: StepProto});
Expand All @@ -146,7 +151,7 @@ function handleVariableFocus(evt){
// TODO: Cancel if the new variable name is already in scope
var input = evt.target;
if (!input.parentElement.hasAttribute('isvariable')){
return
return;
}
var parentContext = dom.closest(input, 'wb-contains');
var variableName = input.parentElement.getAttribute('value');
Expand Down Expand Up @@ -211,25 +216,29 @@ ContextProto.createdCallback = function contextCreated(){
setDefaultByTag(header, 'wb-disclosure');
setDefaultByTag(this, 'wb-local');
setDefaultByTag(this, 'wb-contains');
// console.log('Context created');
};
ContextProto.gatherContains = function(){
// returns an array of arrays of blocks (steps and contexts)
return dom.children(this, 'wb-contains').map(function(container){
return [].slice.call(container.children);
});
return dom.children(this, 'wb-contains');
};
ContextProto.run = function(parentScope){
if (!this.fn){
var fnName = this.getAttribute('script').split('.');
this.fn = runtime[fnName[0]][fnName[1]];
ContextProto.run = function(strand, frame){
var args, containers;
/* Set this function's setup() callback */
if (!this.setup){
this.setupCallbacks();
}
var scope = util.extend({}, parentScope);
// expressions are eagerly evaluated against scope, contains are late-evaluated
// I'm not yet sure if this is the Right Thing™

/* Google analytics event tracking. */
_gaq.push(['_trackEvent', 'Blocks', this.getAttribute('script')]);
// console.log('calling context %s with scope %o, values %o', this.getAttribute('script'), scope, this.gatherValues(scope));
return this.fn.call(scope, this.gatherValues(scope), this.gatherContains());

/* FIXME: Allow for optional evaluation of values. */
// expressions are evaluated if and only if shouldEvaluateValues returns
// true. Containers are evaluated when needed.
args = this.gatherValues(strand.scope);
containers = this.gatherContains();

/* Call setup! */
return this.setup.call(strand.scope, strand, this, containers, args);
};
ContextProto.showLocals = function(evt){
// This is way too specific to the needs to the loopOver block
Expand Down Expand Up @@ -267,6 +276,29 @@ ContextProto.hideLocals = function(evt){
});
}
};
/**
* Prepares the setup() callback.
*/
ContextProto.setupCallbacks = function() {
/* Fetch the callback object from runtime. */
var qualifiedName = this.getAttribute('script').split('.');
var category = qualifiedName[0], name = qualifiedName[1];
var callback = runtime[category][name];

console.assert(!!callback, 'Could not find script: ' + qualifiedName);

this.setup = callback;
};

/** Default: Always get the next DOM element and assume it's a wb-contains. */
function defaultNextCallback(strand, args, containers, elem) {
return elem.nextElementSibling;
}

/** Default: Always evaluate arugments before calling setup(). */
function defaultShouldEvaluateValues(strand, containers, elem) {
return true;
}

window.WBContext = document.registerElement('wb-context', {prototype: ContextProto});

Expand Down Expand Up @@ -608,6 +640,13 @@ var convert = {
};

var ContainsProto = Object.create(HTMLElement.prototype);
/* You sure love Object.defineProperty, dontcha, Eddie? */
Object.defineProperty(ContainsProto, 'firstInstruction', {
get: function () {
return this.firstElementChild;
}
});

window.WBContains = document.registerElement('wb-contains', {prototype: ContainsProto});


Expand Down

0 comments on commit 5fb1c2b

Please sign in to comment.