Skip to content

Commit

Permalink
🪲 Fix bug in custom Skulpt module extensions (#5763)
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
boryanagoncharenko committed Sep 13, 2024
1 parent b99b788 commit ac1f8c0
Showing 1 changed file with 47 additions and 25 deletions.
72 changes: 47 additions & 25 deletions static/vendor/skulpt-stdlib-extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit ac1f8c0

Please sign in to comment.