From 16ca994818f74892dd636d6cbb0e0e3ed97886ca Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Wed, 8 Nov 2017 10:37:38 -0500 Subject: [PATCH] Allow ask to use say bubble via events --- src/blocks/scratch3_looks.js | 4 ++++ src/blocks/scratch3_sensing.js | 25 +++++++++++++++++------ test/unit/blocks_sensing.js | 37 ++++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js index 399c6efa5..70238a786 100644 --- a/src/blocks/scratch3_looks.js +++ b/src/blocks/scratch3_looks.js @@ -23,10 +23,14 @@ class Scratch3LooksBlocks { this._onTargetMoved = this._onTargetMoved.bind(this); this._onResetBubbles = this._onResetBubbles.bind(this); this._onTargetWillExit = this._onTargetWillExit.bind(this); + this._updateBubble = this._updateBubble.bind(this); // Reset all bubbles on start/stop this.runtime.on('PROJECT_STOP_ALL', this._onResetBubbles); this.runtime.on('targetWasRemoved', this._onTargetWillExit); + + // Enable other blocks to use bubbles like ask/answer + this.runtime.on('SAY', this._updateBubble); } /** diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index d9c2ab12f..17dc87e9d 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -53,19 +53,31 @@ class Scratch3SensingBlocks { this._answer = answer; const questionObj = this._questionList.shift(); if (questionObj) { - const resolve = questionObj[1]; + const [_question, resolve, target, wasVisible] = questionObj; + // If the target was visible when asked, hide the say bubble. + if (wasVisible) { + this.runtime.emit('SAY', target, 'say', ''); + } resolve(); this._askNextQuestion(); } } - _enqueueAsk (question, resolve) { - this._questionList.push([question, resolve]); + _enqueueAsk (question, resolve, target, wasVisible) { + this._questionList.push([question, resolve, target, wasVisible]); } _askNextQuestion () { if (this._questionList.length > 0) { - this.runtime.emit('QUESTION', this._questionList[0][0]); + const [question, _resolve, target, wasVisible] = this._questionList[0]; + // If the target is visible, emit a blank question and use the + // say event to trigger a bubble. + if (wasVisible) { + this.runtime.emit('SAY', target, 'say', question); + this.runtime.emit('QUESTION', ''); + } else { + this.runtime.emit('QUESTION', question); + } } } @@ -74,10 +86,11 @@ class Scratch3SensingBlocks { this.runtime.emit('QUESTION', null); } - askAndWait (args) { + askAndWait (args, util) { + const _target = util.target; return new Promise(resolve => { const isQuestionAsked = this._questionList.length > 0; - this._enqueueAsk(args.QUESTION, resolve); + this._enqueueAsk(args.QUESTION, resolve, _target, _target.visible); if (!isQuestionAsked) { this._askNextQuestion(); } diff --git a/test/unit/blocks_sensing.js b/test/unit/blocks_sensing.js index e0c60b4ba..5c2b927a8 100644 --- a/test/unit/blocks_sensing.js +++ b/test/unit/blocks_sensing.js @@ -9,9 +9,10 @@ test('getPrimitives', t => { t.end(); }); -test('ask and answer', t => { +test('ask and answer with a hidden target', t => { const rt = new Runtime(); const s = new Sensing(rt); + const util = {target: {visible: false}}; const expectedQuestion = 'a question'; const expectedAnswer = 'the answer'; @@ -24,7 +25,7 @@ test('ask and answer', t => { }); // (1) Emit the question. - const promise = s.askAndWait({QUESTION: expectedQuestion}); + const promise = s.askAndWait({QUESTION: expectedQuestion}, util); // (3) Ask block resolves after the answer is emitted. promise.then(() => { @@ -32,3 +33,35 @@ test('ask and answer', t => { t.end(); }); }); + +test('ask and answer with a visible target', t => { + const rt = new Runtime(); + const s = new Sensing(rt); + const util = {target: {visible: true}}; + + const expectedQuestion = 'a question'; + const expectedAnswer = 'the answer'; + + rt.removeAllListeners('SAY'); // Prevent say blocks from executing + + rt.addListener('SAY', (target, type, question) => { + // Should emit SAY with the question + t.strictEqual(question, expectedQuestion); + }); + + rt.addListener('QUESTION', question => { + // Question should be blank for a visible target + t.strictEqual(question, ''); + + // Remove the say listener and add a new one to assert bubble is cleared + // by setting say to empty string after answer is received. + rt.removeAllListeners('SAY'); + rt.addListener('SAY', (target, type, text) => { + t.strictEqual(text, ''); + t.end(); + }); + rt.emit('ANSWER', expectedAnswer); + }); + + s.askAndWait({QUESTION: expectedQuestion}, util); +});