Skip to content

Commit 6f99505

Browse files
committed
Merge branch 'master' of github.com:sugarlabs/musicblocks
2 parents b3e87d7 + 65c5908 commit 6f99505

20 files changed

+9867
-3275
lines changed

jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
testMatch: ['**/__tests__/**/*.test.js', '**/?(*.)+(spec|test).[jt]s?(x)'],
3+
clearMocks: true,
4+
moduleFileExtensions: ['js', 'json', 'node'],
5+
};

js/activity.js

Lines changed: 157 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,54 +1017,125 @@ class Activity {
10171017
/*
10181018
* Clears "canvas"
10191019
*/
1020-
this._allClear = (noErase) => {
1021-
this.blocks.activeBlock = null;
1022-
hideDOMLabel();
1023-
1024-
this.logo.boxes = {};
1025-
this.logo.time = 0;
1026-
this.hideMsgs();
1027-
this.hideGrids();
1028-
this.turtles.setBackgroundColor(-1);
1029-
this.logo.svgOutput = "";
1030-
this.logo.notationOutput = "";
1031-
for (let turtle = 0; turtle < this.turtles.turtleList.length; turtle++) {
1032-
this.logo.turtleHeaps[turtle] = [];
1033-
this.logo.turtleDicts[turtle] = {};
1034-
this.logo.notation.notationStaging[turtle] = [];
1035-
this.logo.notation.notationDrumStaging[turtle] = [];
1036-
if (noErase === undefined || !noErase) {
1037-
this.turtles.turtleList[turtle].painter.doClear(true, true, true);
1020+
const renderClearConfirmation = (clearCanvasAction) => {
1021+
// Create a custom modal for confirmation
1022+
const modal = document.createElement("div");
1023+
modal.style.position = "fixed";
1024+
modal.style.top = "50%";
1025+
modal.style.left = "50%";
1026+
modal.style.transform = "translate(-50%, -50%)";
1027+
modal.style.width = "400px";
1028+
modal.style.padding = "24px";
1029+
modal.style.backgroundColor = "#fff";
1030+
modal.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)";
1031+
modal.style.borderRadius = "8px";
1032+
modal.style.zIndex = "10000";
1033+
modal.style.textAlign = "left";
1034+
const title = document.createElement("h2");
1035+
title.textContent = "Clear Workspace";
1036+
title.style.color = "#0066FF";
1037+
title.style.fontSize = "24px";
1038+
title.style.margin = "0 0 16px 0";
1039+
modal.appendChild(title);
1040+
const message = document.createElement("p");
1041+
message.textContent = "Are you sure you want to clear the workspace?";
1042+
message.style.color = "#666666";
1043+
message.style.fontSize = "16px";
1044+
message.style.marginBottom = "24px";
1045+
modal.appendChild(message);
1046+
// Add buttons
1047+
const buttonContainer = document.createElement("div");
1048+
buttonContainer.style.display = "flex";
1049+
buttonContainer.style.justifyContent = "flex-start";
1050+
1051+
const confirmBtn = document.createElement("button");
1052+
confirmBtn.textContent = "Confirm";
1053+
confirmBtn.style.backgroundColor = "#2196F3";
1054+
confirmBtn.style.color = "white";
1055+
confirmBtn.style.border = "none";
1056+
confirmBtn.style.borderRadius = "4px";
1057+
confirmBtn.style.padding = "8px 16px";
1058+
confirmBtn.style.fontWeight = "bold";
1059+
confirmBtn.style.cursor = "pointer";
1060+
confirmBtn.style.marginRight = "16px";
1061+
confirmBtn.addEventListener("click", () => {
1062+
document.body.removeChild(modal);
1063+
clearCanvasAction();
1064+
});
1065+
1066+
const cancelBtn = document.createElement("button");
1067+
cancelBtn.textContent = "Cancel";
1068+
cancelBtn.style.backgroundColor = "#f1f1f1";
1069+
cancelBtn.style.color = "black";
1070+
cancelBtn.style.border = "none";
1071+
cancelBtn.style.borderRadius = "4px";
1072+
cancelBtn.style.padding = "8px 16px";
1073+
cancelBtn.style.fontWeight = "bold";
1074+
cancelBtn.style.cursor = "pointer";
1075+
cancelBtn.addEventListener("click", () => {
1076+
document.body.removeChild(modal);
1077+
});
1078+
1079+
buttonContainer.appendChild(confirmBtn);
1080+
buttonContainer.appendChild(cancelBtn);
1081+
modal.appendChild(buttonContainer);
1082+
document.body.appendChild(modal);
1083+
};
1084+
1085+
this._allClear = (noErase, skipConfirmation = false) => {
1086+
const clearCanvasAction = () => {
1087+
this.blocks.activeBlock = null;
1088+
hideDOMLabel();
1089+
1090+
this.logo.boxes = {};
1091+
this.logo.time = 0;
1092+
this.hideMsgs();
1093+
this.hideGrids();
1094+
this.turtles.setBackgroundColor(-1);
1095+
this.logo.svgOutput = "";
1096+
this.logo.notationOutput = "";
1097+
for (let turtle = 0; turtle < this.turtles.turtleList.length; turtle++) {
1098+
this.logo.turtleHeaps[turtle] = [];
1099+
this.logo.turtleDicts[turtle] = {};
1100+
this.logo.notation.notationStaging[turtle] = [];
1101+
this.logo.notation.notationDrumStaging[turtle] = [];
1102+
if (noErase === undefined || !noErase) {
1103+
this.turtles.turtleList[turtle].painter.doClear(true, true, true);
1104+
}
10381105
}
1039-
}
1040-
1041-
this.blocksContainer.x = 0;
1042-
this.blocksContainer.y = 0;
1043-
1044-
// Code specific to cleaning up Music Blocks
1045-
Element.prototype.remove = () => {
1046-
this.parentElement.removeChild(this);
1047-
};
1048-
1049-
NodeList.prototype.remove = HTMLCollection.prototype.remove = () => {
1050-
for (let i = 0, len = this.length; i < len; i++) {
1051-
if (this[i] && this[i].parentElement) {
1052-
this[i].parentElement.removeChild(this[i]);
1106+
1107+
this.blocksContainer.x = 0;
1108+
this.blocksContainer.y = 0;
1109+
1110+
Element.prototype.remove = () => {
1111+
this.parentElement.removeChild(this);
1112+
};
1113+
1114+
NodeList.prototype.remove = HTMLCollection.prototype.remove = () => {
1115+
for (let i = 0, len = this.length; i < len; i++) {
1116+
if (this[i] && this[i].parentElement) {
1117+
this[i].parentElement.removeChild(this[i]);
1118+
}
10531119
}
1120+
};
1121+
1122+
const table = docById("myTable");
1123+
if (table !== null) {
1124+
table.remove();
1125+
}
1126+
1127+
if (docById("helpfulWheelDiv").style.display !== "none") {
1128+
docById("helpfulWheelDiv").style.display = "none";
1129+
this.__tick();
10541130
}
10551131
};
1056-
1057-
const table = docById("myTable");
1058-
if (table !== null) {
1059-
table.remove();
1060-
}
1061-
1062-
if (docById("helpfulWheelDiv").style.display !== "none") {
1063-
docById("helpfulWheelDiv").style.display = "none";
1064-
this.__tick();
1132+
1133+
if (skipConfirmation) {
1134+
clearCanvasAction();
1135+
} else {
1136+
renderClearConfirmation(clearCanvasAction);
10651137
}
10661138
};
1067-
10681139
/**
10691140
* Sets up play button functionality; runs Music Blocks.
10701141
* @param env {specifies environment}
@@ -1447,6 +1518,8 @@ class Activity {
14471518
else if (ele.label === "Disable horizontal scrolling")
14481519
ele.display = true;
14491520
})
1521+
activity.textMsg(("Horizontal scrolling enabled."), 3000);
1522+
14501523
} else {
14511524
enableHorizScrollIcon.style.display = "block";
14521525
disableHorizScrollIcon.style.display = "none";
@@ -1457,6 +1530,8 @@ class Activity {
14571530
else if (ele.label === "Disable horizontal scrolling")
14581531
ele.display = false;
14591532
})
1533+
activity.textMsg(("Horizontal scrolling disabled."), 3000);
1534+
14601535
}
14611536
};
14621537

@@ -1517,18 +1592,20 @@ class Activity {
15171592
if (this.blockscale < BLOCKSCALES.length - 1) {
15181593
this.resizeDebounce = true;
15191594
this.blockscale += 1;
1595+
this.clearCache();
15201596
await this.blocks.setBlockScale(BLOCKSCALES[this.blockscale]);
1597+
this.blocks.checkBounds();
1598+
this.refreshCanvas();
15211599
}
15221600

15231601
const that = this;
1524-
that.resizeDebounce = false;
1525-
await this.setSmallerLargerStatus();
1526-
1602+
setTimeout(() => {
1603+
that.resizeDebounce = false;
1604+
}, 200);
15271605
}
1528-
if (typeof(this.activity)!="undefined"){
1529-
await this.activity.refreshCanvas();
1530-
}
1531-
document.getElementById("hideContents").click();
1606+
1607+
await this.setSmallerLargerStatus();
1608+
await this.stage.update();
15321609
};
15331610

15341611
/**
@@ -1554,19 +1631,21 @@ class Activity {
15541631
if (this.blockscale > 0) {
15551632
this.resizeDebounce = true;
15561633
this.blockscale -= 1;
1634+
this.clearCache();
15571635
await this.blocks.setBlockScale(BLOCKSCALES[this.blockscale]);
1636+
this.blocks.checkBounds();
1637+
this.refreshCanvas();
15581638
}
15591639

15601640
const that = this;
1561-
that.resizeDebounce = false;
1641+
setTimeout(() => {
1642+
that.resizeDebounce = false;
1643+
}, 200);
15621644

15631645
}
15641646

15651647
await this.setSmallerLargerStatus();
1566-
if (typeof(this.activity)!="undefined"){
1567-
await this.activity.refreshCanvas();
1568-
}
1569-
document.getElementById("hideContents").click();
1648+
await this.stage.update();
15701649
};
15711650

15721651
/*
@@ -3568,6 +3647,22 @@ class Activity {
35683647
// TODO: plugin support
35693648
};
35703649

3650+
/*
3651+
* Clears cache for all blocks
3652+
*/
3653+
this.clearCache = () => {
3654+
this.blocks.blockList.forEach(block => {
3655+
if (block.container) {
3656+
block.container.uncache();
3657+
block.container.cache();
3658+
}
3659+
if (block.bitmap) {
3660+
block.bitmap.uncache();
3661+
block.bitmap.cache();
3662+
}
3663+
});
3664+
};
3665+
35713666
/*
35723667
* Updates all canvas elements
35733668
*/
@@ -3576,15 +3671,17 @@ class Activity {
35763671
return;
35773672
}
35783673

3579-
this.blockRefreshCanvas = true;
3580-
3674+
this.blockRefreshCanvas = true;
3675+
// Force stage clear and update
3676+
this.stage.clear();
3677+
this.stage.update();
3678+
this.update = true;
3679+
35813680
const that = this;
35823681
setTimeout(() => {
35833682
that.blockRefreshCanvas = false;
3683+
that.stage.update();
35843684
}, 5);
3585-
3586-
this.stage.update(event);
3587-
this.update = true;
35883685
};
35893686

35903687
/*
@@ -3652,7 +3749,7 @@ class Activity {
36523749
document.querySelector("#myOpenFile").click();
36533750
window.scroll(0, 0);
36543751
doHardStopButton(that);
3655-
that._allClear(true);
3752+
that._allClear(true, true);
36563753
};
36573754

36583755
window.prepareExport = this.prepareExport;

js/base64Utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ function base64Decode(str) {
2828
}
2929

3030
export default { base64Encode, base64Decode };
31+
//module.exports = { base64Encode, base64Decode };

0 commit comments

Comments
 (0)