updates to finish doAsk

This commit is contained in:
Brian Pilati 2014-03-09 11:59:38 -06:00
parent 6f54f52f3c
commit e59b279be1
19 changed files with 341 additions and 62 deletions

View file

@ -40,6 +40,7 @@ var Thread = function(block, target) {
this.tmp = null; // used for thread operations like Timer
this.tmpObj = []; // used for Sprite operations like glide
this.firstTime = true;
this.paused = false;
};
var Interpreter = function() {
@ -126,6 +127,13 @@ Interpreter.prototype.stepThreads = function() {
}
};
Interpreter.prototype.pauseActiveThread = function() {
var self = this;
var timeoutId = setTimeout(function () {
(self.activeThread.paused) ? self.pauseActiveThread() : clearTimeout(timeoutId);
}, 1000);
}
Interpreter.prototype.stepActiveThread = function() {
// Run the active thread until it yields.
if (typeof(this.activeThread) == 'undefined') {
@ -135,6 +143,8 @@ Interpreter.prototype.stepActiveThread = function() {
if (b == null) return;
this.yield = false;
while (true) {
if (this.activeThread.paused) return;
++this.opCount;
// Advance the "program counter" to the next block before running the primitive.
// Control flow primitives (e.g. if) may change activeThread.nextBlock.
@ -247,6 +257,10 @@ Interpreter.prototype.targetSprite = function() {
return this.activeThread.target;
};
Interpreter.prototype.targetStage = function() {
return runtime.stage;
};
// Timer
Interpreter.prototype.startTimer = function(secs) {
var waitMSecs = 1000 * secs;

View file

@ -29,14 +29,19 @@ var Reporter = function(data) {
this.y = data.y;
this.z = io.getCount();
//Set the label after hydrating the cmd and param variables
this.label = this.determineReporterLabel();
this.el = null; // jQuery Element for the outer box
this.valueEl = null; // jQ element containing the reporter value
this.slider = null; // slider jQ element
};
Reporter.prototype.determineReporterLabel = function() {
if (this.target === 'Stage') {
if (this.target === 'Stage' && this.cmd === "getVar:") {
return this.param;
} else if (this.target === 'Stage' && this.param === null) {
return this.cmd;
} else {
return this.target + ': ' + this.param;
}
@ -46,7 +51,7 @@ Reporter.prototype.attach = function(scene) {
switch (this.mode) {
case 1: // Normal
case 3: // Slider
this.el = $('<div class="reporter-normal">' + this.determineReporterLabel() + '</div>');
this.el = $('<div class="reporter-normal">' + this.label + '</div>');
this.valueEl = $('<div class="reporter-inset">null</div>');
this.el.append(this.valueEl);
if (this.mode == 3) {
@ -84,6 +89,9 @@ Reporter.prototype.update = function() {
var newValue = '';
var target = runtime.spriteNamed(this.target);
switch (this.cmd) {
case 'answer':
newValue = target.askAnswer;
break;
case 'getVar:':
newValue = target.variables[this.param];
break;

View file

@ -80,7 +80,6 @@ var Sprite = function(data) {
this.askInputOn = false;
// Internal variables used for rendering meshes.
this.askAnswer = null; //this is a private variable
this.textures = [];
this.materials = [];
this.geometries = [];
@ -161,9 +160,10 @@ Sprite.prototype.attach = function(scene) {
this.askInput = $('<div class="ask-container"></div>');
this.askInput.css('display', 'none');
this.askInputField = $('<div class="ask-field"></div>');
this.askInputTextField = $('<input class="ask-text-field"></input>');
this.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
this.askInputField.append(this.askInputTextField);
this.askInputButton = $('<div class="ask-button"></div>');
this.bindDoAskButton();
this.askInput.append(this.askInputField);
this.askInput.append(this.askInputButton);
@ -368,8 +368,8 @@ Sprite.prototype.showBubble = function(text, type) {
this.talkBubble.css('left', xy[0] + 'px');
this.talkBubble.css('top', xy[1] + 'px');
this.talkBubble.removeClass('say-think-border');
this.talkBubble.removeClass('ask-border');
this.talkBubbleBox.removeClass('say-think-border');
this.talkBubbleBox.removeClass('ask-border');
this.talkBubbleStyler.removeClass('bubble-say');
this.talkBubbleStyler.removeClass('bubble-think');
@ -412,9 +412,24 @@ Sprite.prototype.showAsk = function() {
Sprite.prototype.hideAsk = function() {
this.askInputOn = false;
this.askInputTextField.val('');
this.askInput.css('display', 'none');
};
Sprite.prototype.bindDoAskButton = function() {
var self = this;
this.askInputButton.on("keypress click", function(e){
var eType = e.type;
if (eType === 'click' || (eType === 'keypress' && e.which === 13)) {
var stage = interp.targetStage();
stage.askAnswer = $(self.askInputTextField).val();
self.hideBubble();
self.hideAsk();
interp.activeThread.paused = false;
}
});
};
Sprite.prototype.setXY = function(x, y) {
this.scratchX = x;
this.scratchY = y;

View file

@ -34,6 +34,7 @@ var Stage = function(data) {
this.lineCanvas.height = 360;
this.lineCache = this.lineCanvas.getContext('2d');
this.isStage = true;
this.askAnswer = ""; //this is a private variable and should be blank
Sprite.call(this, data);
};

View file

@ -43,9 +43,6 @@ LooksPrims.prototype.addPrimsTo = function(primTable) {
primTable['setGraphicEffect:to:'] = this.primSetEffect;
primTable['filterReset'] = this.primClearEffects;
primTable['doAsk'] = this.primDoAsk;
primTable['answer'] = this.primAnswer;
primTable['say:'] = function(b) { showBubble(b, 'say'); };
primTable['say:duration:elapsed:from:'] = function(b) { showBubbleAndWait(b, 'say'); };
primTable['think:'] = function(b) { showBubble(b, 'think'); };
@ -173,25 +170,14 @@ LooksPrims.prototype.primClearEffects = function(b) {
s.updateFilters();
};
LooksPrims.prototype.primDoAsk= function(b) {
showBubble(b, "doAsk");
var s = interp.targetSprite();
if (s != null) s.showAsk();
};
LooksPrims.prototype.primAnswer = function() {
var s = interp.targetSprite();
return ((s != null) ? s.answer : undefined);
};
var showBubble = function(b, type) {
var s = interp.targetSprite();
if (s != null) s.showBubble(interp.arg(b, 0), type);
if (s !== null) s.showBubble(interp.arg(b, 0), type);
};
var showBubbleAndWait = function(b, type) {
var s = interp.targetSprite();
if (s == null) return;
if (s === null) return;
if (interp.activeThread.firstTime) {
var text = interp.arg(b, 0);
var secs = interp.numarg(b, 1);

View file

@ -22,6 +22,9 @@ SensingPrims.prototype.addPrimsTo = function(primTable) {
primTable['touchingColor:'] = this.primTouchingColor;
primTable['color:sees:'] = this.primColorTouchingColor;
primTable['doAsk'] = this.primDoAsk;
primTable['answer'] = this.primAnswer;
primTable['keyPressed:'] = this.primKeyPressed;
primTable['mousePressed'] = function(b) { return runtime.mouseDown; };
primTable['mouseX'] = function(b) { return runtime.mousePos[0]; };
@ -174,6 +177,21 @@ var stageColorByColorHitTest = function(target, myColor, otherColor) {
return false;
};
SensingPrims.prototype.primDoAsk= function(b) {
showBubble(b, "doAsk");
var s = interp.targetSprite();
if (s !== null) {
interp.activeThread.paused = true;
s.showAsk();
}
};
SensingPrims.prototype.primAnswer = function(b) {
var s = interp.targetStage();
return (s !== null ? s.askAnswer : undefined);
};
SensingPrims.prototype.primKeyPressed = function(b) {
var key = interp.arg(b, 0);
var ch = key.charCodeAt(0);

View file

@ -22,6 +22,7 @@ var interpreterMock = function() {
return {
'targetSprite' : function() { return getArgs('targetSprite'); },
'arg': function(block, index) { return getArgs('arg');},
'activeThread': undefined
'activeThread': new threadMock(),
'targetStage': function() { var rtMock = new runtimeMock(); return rtMock.stage}
}
};

View file

@ -20,6 +20,7 @@ var stageMock = function() {
}
return {
'resetFilters' : function() { return getArgs('resetFilters'); }
'resetFilters' : function() { return getArgs('resetFilters'); },
'askAnswer' : 12
}
};

View file

@ -4,7 +4,7 @@ var targetMock = function() {
return {
'showBubble' : function() {},
'showAsk' : function() {},
'answer' : 22
'askAnswer' : 22
};
}

View file

@ -0,0 +1,5 @@
'use strict';
var deepCopy = function(object) {
return jQuery.extend(true, {}, object);
}

View file

@ -20,5 +20,6 @@ var threadMock = function() {
}
return {
'paused' : getArgs('paused')
}
};

View file

@ -0,0 +1,94 @@
/* jasmine specs for Interpreter.js go here */
describe ('Interpreter', function() {
var interp;
beforeEach(function() {
interp = Interpreter;
});
describe('Instantization variables', function() {
var initInterp, realThread, realTimer;
beforeEach(function() {
realThread = Thread;
realTimer = Timer;
Thread = threadMock;
Timer = function() {};
initInterp = new interp();
});
afterEach(function() {
Thread = realThread;
Timer = realTimer;
});
describe('Interpreter Variables', function() {
it('should have a primitiveTable collection', function() {
expect(initInterp.primitiveTable).toEqual({});
});
it('should have a variables collection', function() {
expect(initInterp.variables).toEqual({});
});
it('should have a threads array', function() {
expect(initInterp.threads).toEqual([]);
});
it('should have an activeThread variable', function() {
expect(initInterp.activeThread).toEqual(threadMock());
});
it('should have a WorkTime variable', function() {
expect(initInterp.WorkTime).toBe(30);
});
it('should have a currentMSecs variable', function() {
expect(initInterp.currentMSecs).toBe(null);
});
it('should have a timer variable', function() {
expect(initInterp.timer).toEqual({});
});
it('should have a yield variable', function() {
expect(initInterp.yield).toBe(false);
});
it('should have a doRedraw variable', function() {
expect(initInterp.doRedraw).toBe(false);
});
it('should have an opCount variable', function() {
expect(initInterp.opCount).toBe(0);
});
it('should have a debugOps variable', function() {
expect(initInterp.debugOps).toBe(false);
});
it('should have a debugFunc variable', function() {
expect(initInterp.debugFunc).toBe(null);
});
it('should have an opCount2 variable', function() {
expect(initInterp.opCount2).toBe(0);
});
});
});
describe('PauseActiveThread', function() {
it('should call clearTimeout', function() {
spyOn(window, "setTimeout");
interp.prototype.pauseActiveThread();
expect(window.setTimeout).toHaveBeenCalled();
});
});
describe('TargetStage', function() {
it('should return the target.stage object', function() {
runtime = new runtimeMock();
expect(interp.prototype.targetStage()).toEqual(runtime.stage);
});
});
});

View file

@ -17,7 +17,7 @@ describe ('LooksPrims', function() {
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
showBubble(sayBlock, "say");
expect(targetSpriteMock.showBubble).toHaveBeenCalled;
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to say']}, 'say');
});
});
@ -31,35 +31,21 @@ describe ('LooksPrims', function() {
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
showBubble(thinkBlock, "think");
expect(targetSpriteMock.showBubble).toHaveBeenCalled;
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to think']}, 'think');
});
});
describe('showBubble for Ask', function(){
var askBlock;
beforeEach(function() {
askBlock = {'args': 'what to ask'};
askBlock = {'args': ['what to ask']};
interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': askBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
spyOn(targetSpriteMock, "showAsk");
looksPrims.prototype.primDoAsk(askBlock);
expect(targetSpriteMock.showBubble).toHaveBeenCalled;
expect(targetSpriteMock.showAsk).toHaveBeenCalled;
});
});
describe('primAnswer', function(){
beforeEach(function() {
interp = interpreterMock({'targetSprite': targetSpriteMock });
});
it('should return the answer variable from the targetedSprite', function() {
expect(looksPrims.prototype.primAnswer()).toBe(22);
showBubble(askBlock, "ask");
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to ask']}, 'ask');
});
});
});

View file

@ -64,6 +64,10 @@ describe ('Reporter', function() {
expect(initReporter.z).toBe(4);
});
it('should have a label variable', function() {
expect(initReporter.label).toBe('myAnswer');
});
it('should have an el variable', function() {
expect(initReporter.el).toBe(null);
});
@ -77,19 +81,27 @@ describe ('Reporter', function() {
});
});
});
describe('determineReporterLabel', function() {
describe('determineReporterLabel', function() {
it('should return a stage variable', function() {
reporter.prototype.target = "Stage";
reporter.prototype.param = "myAnswer";
reporter.prototype.cmd = "getVar:";
expect(reporter.prototype.determineReporterLabel()).toBe('myAnswer');
});
it('should return a sprite variable', function() {
reporter.prototype.target = "Sprite 1";
reporter.prototype.param = "localAnswer";
reporter.prototype.cmd = "getVar:";
expect(reporter.prototype.determineReporterLabel()).toBe('Sprite 1: localAnswer');
});
it('should return a stage answer variable', function() {
reporter.prototype.target = "Stage";
reporter.prototype.param = null;
reporter.prototype.cmd = "answer";
expect(reporter.prototype.determineReporterLabel()).toBe('answer');
});
});

View file

@ -61,6 +61,7 @@ describe ('Runtime', function() {
});
describe('Stop All', function() {
var realThread;
beforeEach(function() {
runtime = new runtimeMock
spyOn(window, "stopAllSounds");
@ -68,18 +69,23 @@ describe ('Runtime', function() {
spyOn(runtime.sprites[0], "hideBubble");
spyOn(runtime.sprites[0], "resetFilters");
spyOn(runtime.sprites[0], "hideAsk");
realThread = Thread;
Thread = threadMock;
interp = new interpreterMock();
});
afterEach(function() {
Thread = realThread;
});
it('should call a new Thread Object', function() {
runtimeObj.prototype.stopAll();
expect(interp.activeThread).toEqual({});
expect(interp.activeThread).toEqual(new threadMock());
});
it('should call a blank thread array ', function() {
runtimeObj.prototype.stopAll();
expect(interp.activeThread).toEqual([]);
expect(interp.activeThread).toEqual(new threadMock());
});
it('should call stopAllSounds', function() {

View file

@ -78,4 +78,35 @@ describe ('SensingPrims', function() {
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(0);
});
});
describe('primAnswer', function(){
beforeEach(function() {
interp = interpreterMock({'targetSprite': new targetMock()});
});
it('should return the answer variable from the targetedSprite', function() {
expect(sensingPrims.prototype.primAnswer()).toBe(12);
});
});
describe('primDoAsk', function(){
var askBlock, targetSpriteMock;
beforeEach(function() {
targetSpriteMock = targetMock();
askBlock = {'args': 'what to ask'};
interp = interpreterMock({'targetSprite': targetSpriteMock}, {'arg': askBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(window, "showBubble");
spyOn(targetSpriteMock, "showAsk");
sensingPrims.prototype.primDoAsk(askBlock);
expect(window.showBubble).toHaveBeenCalledWith({args:'what to ask'}, 'doAsk');
expect(targetSpriteMock.showAsk).toHaveBeenCalled;
expect(interp.activeThread.paused).toBe(true);
});
});
});

View file

@ -3,7 +3,6 @@
describe ('Sprite', function() {
var sprite;
beforeEach(function() {
sprite = Sprite;
});
@ -59,17 +58,13 @@ describe ('Sprite', function() {
it('should have an askInputOn variable', function() {
expect(initSprite.askInputOn).toBe(false);
});
it('should have an answer variable', function() {
expect(initSprite.askAnswer).toBe(null);
});
});
})
describe('showBubble', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
spriteProto.visible = true;
setFixtures('<div class="bubble-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
@ -133,7 +128,7 @@ describe ('Sprite', function() {
describe('hideBubble', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
setFixtures('<div class="bubble-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('display', 'inline');
@ -150,7 +145,7 @@ describe ('Sprite', function() {
describe('showAsk', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
spriteProto.visible = true;
spriteProto.z = 22;
setFixtures('<div class="ask-container"></div>');
@ -158,7 +153,7 @@ describe ('Sprite', function() {
spriteProto.askInput.css('display','none');
spriteProto.askInput.css('position','relative');
spriteProto.askInputField = $('<div class="ask-input"></div>');
spriteProto.askInputTextField = $('<input class="ask-text-field"></input>');
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputField.append(spriteProto.askInputTextField);
spriteProto.askInputButton = $('<div class="ask-button"></div>');
spriteProto.askInput.append(spriteProto.askInputField);
@ -189,9 +184,11 @@ describe ('Sprite', function() {
describe('hideAsk', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
setFixtures('<div class="ask-container"></div>');
spriteProto.askInput = $('.ask-container');
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputTextField.val("Delete Me");
spriteProto.askInput.css('display', 'inline');
});
@ -199,14 +196,63 @@ describe ('Sprite', function() {
spriteProto.hideAsk();
expect($('.ask-container').css('display')).toBe('none');
expect(spriteProto.askInputOn).toBe(false);
expect(spriteProto.askInputTextField.val()).toBe('');
});
});
describe('bindAsk', function() {
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputButton = $('<div class="ask-button"></div>');
spyOn(spriteProto, "hideBubble");
spyOn(spriteProto, "hideAsk");
});
it('should bind to the askInputButton and handle a click', function() {
interp = new interpreterMock();
spyOn(interp, "targetStage").andCallThrough();
$(spriteProto.askInputTextField).val('Hellow World');
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(interp.targetStage).toHaveBeenCalled();
});
it('should bind to the askInputButton and handle a enter/return', function() {
interp = new interpreterMock();
spyOn(interp, "targetStage").andCallThrough();
spriteProto.bindDoAskButton();
var e = $.Event( "keypress", { which: 13 } );
$(spriteProto.askInputButton).trigger(e);
expect(interp.targetStage).toHaveBeenCalled();
});
it('should call hideBubble', function() {
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(spriteProto.hideBubble).toHaveBeenCalled();
expect(spriteProto.hideAsk).toHaveBeenCalled();
});
it('should call hideAsk', function() {
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(spriteProto.hideAsk).toHaveBeenCalled();
});
it('should have interp.activeThread.paused be false', function() {
interp = new interpreterMock();
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(interp.activeThread.paused).toBe(false);
});
});
describe('updateLayer', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('position', 'relative');
@ -239,7 +285,7 @@ describe ('Sprite', function() {
describe('updateVisible', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('display', 'none');
@ -323,12 +369,12 @@ describe ('Sprite', function() {
describe('setVisible', function() {
var spriteProto;
beforeEach(function() {
spriteProto = sprite.prototype;
spriteProto = deepCopy(sprite.prototype);
spyOn(spriteProto, "updateVisible");
});
it('should set visible to true', function() {
expect(spriteProto.visible).toBe(false);
expect(spriteProto.visible).toBe(undefined);
spriteProto.setVisible(true);
expect(spriteProto.visible).toBe(true);
expect(spriteProto.updateVisible).toHaveBeenCalled();
@ -347,6 +393,6 @@ describe ('Sprite', function() {
expect(spriteProto.visible).toBe(true);
expect(spriteProto.updateVisible).not.toHaveBeenCalled();
});
});
});

View file

@ -43,6 +43,10 @@ describe ('Stage', function() {
expect(initStage.isStage).toBe(true);
});
it('should have an askAnswer variable', function() {
expect(initStage.askAnswer).toBe("");
});
it('should have called Sprite.call', function() {
expect(Sprite.call).toHaveBeenCalled();
});

50
test/unit/threadSpec.js Normal file
View file

@ -0,0 +1,50 @@
/* jasmine specs for Interpreter.js -> Thread go here */
describe ('Thread', function() {
var thread;
beforeEach(function() {
thread = Thread;
});
describe('Instantization variables', function() {
var initThread;
beforeEach(function() {
initThread = new thread('block', 'target');
});
describe('Thread Variables', function() {
it('should have a nextBlock variable', function() {
expect(initThread.nextBlock).toBe('block');
});
it('should have a firstBlock variable', function() {
expect(initThread.firstBlock).toBe('block');
});
it('should have a stack variable', function() {
expect(initThread.stack).toEqual([]);
});
it('should have a target variable', function() {
expect(initThread.target).toBe('target');
});
it('should have a tmp variable', function() {
expect(initThread.tmp).toBe(null);
});
it('should have a tmpObj variable', function() {
expect(initThread.tmpObj).toEqual([]);
});
it('should have a firstTime variable', function() {
expect(initThread.firstTime).toBe(true);
});
it('should have a paused variable', function() {
expect(initThread.paused).toBe(false);
});
});
});
});