From ac1f8c05c59cc1504cf0f37a0384c88ae53e30e4 Mon Sep 17 00:00:00 2001 From: boryanagoncharenko <3010723+boryanagoncharenko@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:00:27 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=B2=20Fix=20bug=20in=20custom=20Skulpt?= =?UTF-8?q?=20module=20extensions=20(#5763)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR addresses the following issues: - When the body of an if-pressed command contains more than one turtle functions, only the first one will be executed. - When the body of an if-pressed command contains time.sleep(), the execution would terminate when reaching this line. Fixes #5729 #5681 **How to test** Run locally, go to level 15 and run the following scenarios: 1. Check that the code below outputs all items in the list. Note that they should not appear at once, but with a tiny delay in between: ``` lijstje is "1", "2", "3", "4", "5" if x is pressed for dier in lijstje print dier else print 'onbekend dier' ``` 2. Check that when pressing x, all statements are executed. Note that the waiting-for-key-press modal should appear and then disappear while the action is being executed. Note that pressing the x button while the turtle is moving should not trigger a new run. If an error occurs, the keys should not be animated anymore. ``` i = 0 while i < 20 if x is pressed turn 10 color 'blue' turn 90 forward 50 color 'red' turn 90 forward 50 color 'orange' turn 90 forward 50 color 'green' turn 90 forward 50 else turn -15 color 'blue' turn -90 forward 50 color 'red' turn -90 forward 50 color 'orange' turn -90 forward 50 color 'green' turn -90 forward 50 i = i + 1 ``` --- static/vendor/skulpt-stdlib-extensions.js | 72 +++++++++++++++-------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/static/vendor/skulpt-stdlib-extensions.js b/static/vendor/skulpt-stdlib-extensions.js index d0c6c6b6745..126d0e34249 100644 --- a/static/vendor/skulpt-stdlib-extensions.js +++ b/static/vendor/skulpt-stdlib-extensions.js @@ -21,49 +21,71 @@ var $builtinmodule = function (name) { keyElement.remove() }, 1500); } - } + } + + var ongoingIfPressedCall = false; + + function callIfPressedFunc(name, resolve, reject) { + var f = Sk.misceval.loadname(name, Sk.globals); + var currentProgram = window.sessionStorage.getItem("currentProgram"); + + Sk.misceval.asyncToPromise(() => + Sk.misceval.callOrSuspend(f), {}, currentProgram).then(() => { + resolve(); + }).catch((e) => { + reject(e); + }).finally(() => { + ongoingIfPressedCall = false; + }); + } function keyBoardInputPromise(if_pressed_mapping) { + ongoingIfPressedCall = true; $('#keybinding_modal').show(); return new Promise((resolve, reject) => { window.addEventListener("keydown", (event) => { - let pressed_mapped_key = false; + try { + let pressed_mapped_key = false; - for (const [key, value] of Object.entries(if_pressed_mapping.entries)) { - // If mapped key is a variable (not char), we retrieve variable value and use that - // otherwise if char, use that. - const charOrVar = value[0].v; + for (const [key, value] of Object.entries(if_pressed_mapping.entries)) { + // if the mapped key is a variable, we retrieve variable value and use that + // if the mapped key is not a variable, use it as a char + const charOrVar = value[0].v; + let mapLetterKey = charOrVar; + if (Object.hasOwn(Sk.globals, charOrVar)) { + if (Sk.globals[charOrVar].hasOwnProperty('v')) { + mapLetterKey = Sk.globals[charOrVar].v; + } else { + mapLetterKey = Sk.globals[charOrVar].$d.entries['data'][1].v; + } + } - let mapLetterKey = charOrVar; - if (Object.hasOwn(Sk.globals, charOrVar)) { - if (Sk.globals[charOrVar].hasOwnProperty('v')) { - mapLetterKey = Sk.globals[charOrVar].v; - } else { - mapLetterKey = Sk.globals[charOrVar].$d.entries['data'][1].v; + if (event.key === `${mapLetterKey}`) { + pressed_mapped_key = true; + callIfPressedFunc(value[1].v, resolve, reject); } } - if (event.key === `${mapLetterKey}`){ - pressed_mapped_key = true; - Sk.misceval.callOrSuspend(Sk.globals[value[1].v]); + if (!pressed_mapped_key) { + callIfPressedFunc(if_pressed_mapping.entries['else'][1].v, resolve, reject); } + } catch (err) { + ongoingIfPressedCall = false; + reject(err); + } finally { + $('#keybinding_modal').hide(); } - - if (!pressed_mapped_key){ - Sk.misceval.callOrSuspend(Sk.globals[if_pressed_mapping.entries['else'][1].v]); - } - - $('#keybinding_modal').hide(); - resolve(); }, { once: true }); }) } mod.if_pressed = new Sk.builtin.func(function (if_pressed_mapping) { document.onkeydown = animateKeys; - return new Sk.misceval.promiseToSuspension(keyBoardInputPromise( - if_pressed_mapping - ).then(() => {document.onkeydown = null; return Sk.builtin.none.none$})); + return new Sk.misceval.promiseToSuspension( + keyBoardInputPromise(if_pressed_mapping) + .then(() => { return Sk.builtin.none.none$ }) + .finally(() => { document.onkeydown = null;}) + ); }); return mod;