Skip to content

Commit 39171f4

Browse files
Crearting 'View Trash' and more restore option in Musicblocks (#4191)
* Creating View Trash option * creating view trash option * creating view trash option * Creating view trash list and more restore options * Creating view trash list and more restore options * Creating view trash and more restore options * create view trash option * Creating view trash and more restore options * Creating view trash and more restore options * Creating view trash and more restore options * Creating view Trash and more restore options * Creating view trash and more restore options
1 parent 6efdccf commit 39171f4

File tree

3 files changed

+212
-61
lines changed

3 files changed

+212
-61
lines changed

css/activities.css

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,72 @@
9090
font-size: large;
9191
}
9292

93+
.trash-view {
94+
position: relative;
95+
background-color: white;
96+
max-width: 396px;
97+
max-height: 200px;
98+
overflow-y: auto;
99+
font-size: 16px;
100+
color: black;
101+
border: 2px solid #87cefa;
102+
list-style-type: none;
103+
margin: 0;
104+
padding: 0;
105+
text-align: left;
106+
}
107+
108+
.button-container {
109+
position: sticky;
110+
display: flex;
111+
justify-content: space-between;
112+
top: 0;
113+
z-index: 10;
114+
display: flex;
115+
gap: 10px;
116+
background: #2196F3;
117+
margin: 0;
118+
padding: 5px;
119+
border-bottom: 1px solid #d9d9d9;
120+
}
121+
122+
.trash-item {
123+
padding: 2px 12px;
124+
margin: 1px 0;
125+
border-radius: 4px;
126+
transition: background-color 0.3s;
127+
}
128+
129+
.trash-item.hover {
130+
background-color: #d9d9d9;
131+
}
132+
133+
.trash-item-icon {
134+
width: 30px;
135+
height: 30px;
136+
margin-right: 10px;
137+
vertical-align: middle;
138+
}
139+
140+
#restoreLastIcon, #restoreAllIcon {
141+
display: flex;
142+
align-items: center;
143+
justify-content: center;
144+
width: 48px;
145+
height: 48px;
146+
cursor: pointer;
147+
}
148+
149+
150+
.material-icons.md-48 {
151+
font-size: 32px;
152+
}
153+
154+
155+
.hidden {
156+
display: none;
157+
}
158+
93159
.ui-menu {
94160
position: relative;
95161
background-color: rgba(255, 255, 255, 1);

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@
780780
>
781781
<a style="color: transparent;">space&nbsp;&nbsp;&nbsp;</a>
782782
</li>
783+
783784
<li>
784785
<a
785786
id="restoreIcon"
@@ -789,6 +790,7 @@
789790
>restore_from_trash</i
790791
></a
791792
>
793+
<div id="trashList"></div>
792794
</li>
793795
<li>
794796
<a

js/activity.js

Lines changed: 144 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3346,91 +3346,89 @@ class Activity {
33463346
const restoreTrash = (activity) => {
33473347
if (!activity.blocks || !activity.blocks.trashStacks || activity.blocks.trashStacks.length === 0) {
33483348
activity.textMsg(
3349-
_("Nothing in the trash to restore."),
3349+
_("Trash can is empty."),
33503350
3000
33513351
);
33523352
return;
33533353
}
3354-
activity._restoreTrash();
3354+
3355+
if (docById("helpfulWheelDiv").style.display !== "none") {
3356+
docById("helpfulWheelDiv").style.display = "none";
3357+
activity.__tick();
3358+
}
3359+
};
3360+
3361+
const restoreTrashPop = (activity) => {
3362+
if (!activity.blocks || !activity.blocks.trashStacks || activity.blocks.trashStacks.length === 0) {
3363+
activity.textMsg(
3364+
_("Trash can is empty."),
3365+
3000
3366+
);
3367+
return;
3368+
}
3369+
this._restoreTrashById(this.blocks.trashStacks[this.blocks.trashStacks.length - 1]);
33553370
activity.textMsg(
33563371
_("Item restored from the trash."),
33573372
3000
33583373
);
3359-
3374+
33603375
if (docById("helpfulWheelDiv").style.display !== "none") {
33613376
docById("helpfulWheelDiv").style.display = "none";
33623377
activity.__tick();
33633378
}
3364-
};
3379+
3380+
}
33653381

3366-
this._restoreTrash = () => {
3382+
this._restoreTrashById = (blockId) => {
3383+
const blockIndex = this.blocks.trashStacks.indexOf(blockId);
3384+
if (blockIndex === -1) return; // Block not found in trash
3385+
3386+
this.blocks.trashStacks.splice(blockIndex, 1); // Remove from trash
3387+
33673388
for (const name in this.palettes.dict) {
33683389
this.palettes.dict[name].hideMenu(true);
33693390
}
3370-
3391+
33713392
this.blocks.activeBlock = null;
33723393
this.refreshCanvas();
33733394

33743395
const dx = 0;
33753396
const dy = -this.cellSize * 3; // Reposition
3376-
3377-
if (this.blocks.trashStacks.length === 0) {
3378-
return;
3379-
}
3380-
3381-
const thisBlock = this.blocks.trashStacks.pop();
3382-
3383-
// Restore drag group in trash
3384-
this.blocks.findDragGroup(thisBlock);
3397+
3398+
// Restore drag group
3399+
this.blocks.findDragGroup(blockId);
33853400
for (let b = 0; b < this.blocks.dragGroup.length; b++) {
33863401
const blk = this.blocks.dragGroup[b];
33873402
this.blocks.blockList[blk].trash = false;
33883403
this.blocks.moveBlockRelative(blk, dx, dy);
33893404
this.blocks.blockList[blk].show();
33903405
}
3391-
3392-
this.blocks.raiseStackToTop(thisBlock);
3393-
3394-
if (
3395-
this.blocks.blockList[thisBlock].name === "start" ||
3396-
this.blocks.blockList[thisBlock].name === "drum"
3397-
) {
3398-
const turtle = this.blocks.blockList[thisBlock].value;
3406+
3407+
this.blocks.raiseStackToTop(blockId);
3408+
const restoredBlock = this.blocks.blockList[blockId];
3409+
3410+
if (restoredBlock.name === 'start' || restoredBlock.name === 'drum') {
3411+
const turtle = restoredBlock.value;
33993412
this.turtles.turtleList[turtle].inTrash = false;
34003413
this.turtles.turtleList[turtle].container.visible = true;
3401-
} else if (this.blocks.blockList[thisBlock].name === "action") {
3402-
// We need to add a palette entry for this action.
3403-
// But first we need to ensure we have a unqiue name,
3404-
// as the name could have been taken in the interim.
3405-
const actionArg = this.blocks.blockList[
3406-
this.blocks.blockList[thisBlock].connections[1]
3407-
];
3414+
} else if (restoredBlock.name === 'action') {
3415+
const actionArg = this.blocks.blockList[restoredBlock.connections[1]];
34083416
if (actionArg !== null) {
34093417
let label;
34103418
const oldName = actionArg.value;
3411-
// Mark the action block as still being in the
3412-
// trash so that its name won't be considered when
3413-
// looking for a unique name.
3414-
this.blocks.blockList[thisBlock].trash = true;
3419+
restoredBlock.trash = true;
34153420
const uniqueName = this.blocks.findUniqueActionName(oldName);
3416-
this.blocks.blockList[thisBlock].trash = false;
3421+
restoredBlock.trash = false;
34173422

34183423
if (uniqueName !== actionArg) {
34193424
actionArg.value = uniqueName;
3420-
3421-
label = actionArg.value.toString();
3422-
if (label.length > 8) {
3423-
label = label.substr(0, 7) + "...";
3424-
}
3425+
label = uniqueName.length > 8 ? uniqueName.substr(0, 7) + '...' : uniqueName;
34253426
actionArg.text.text = label;
34263427

34273428
if (actionArg.label !== null) {
34283429
actionArg.label.value = uniqueName;
34293430
}
3430-
34313431
actionArg.container.updateCache();
3432-
3433-
// Check the drag group to ensure any do blocks are updated (in case of recursion).
34343432
for (let b = 0; b < this.blocks.dragGroup.length; b++) {
34353433
const me = this.blocks.blockList[this.blocks.dragGroup[b]];
34363434
if (
@@ -3441,11 +3439,7 @@ class Activity {
34413439
) {
34423440
me.privateData = uniqueName;
34433441
me.value = uniqueName;
3444-
3445-
label = me.value.toString();
3446-
if (label.length > 8) {
3447-
label = label.substr(0, 7) + "...";
3448-
}
3442+
label = uniqueName.length > 8 ? uniqueName.substr(0, 7) + '...' : uniqueName;
34493443
me.text.text = label;
34503444
me.overrideName = label;
34513445
me.regenerateArtwork();
@@ -3455,21 +3449,110 @@ class Activity {
34553449
}
34563450
}
34573451
}
3458-
3452+
activity.textMsg(
3453+
_("Item restored from the trash."),
3454+
3000
3455+
);
3456+
34593457
this.refreshCanvas();
3460-
};
3458+
};
3459+
3460+
// Add event listener for trash icon click
3461+
document.getElementById('restoreIcon').addEventListener('click', () => {
3462+
this._renderTrashView();
3463+
});
3464+
3465+
// function to hide trashView from canvas
3466+
function handleClickOutsideTrashView(trashView) {
3467+
let firstClick = true;
3468+
document.addEventListener('click', (event) => {
3469+
if (firstClick) {
3470+
firstClick = false;
3471+
return;
3472+
}
3473+
if (!trashView.contains(event.target) && event.target !== trashView) {
3474+
trashView.style.display = 'none';
3475+
}
3476+
});
3477+
}
34613478

3462-
this.handleKeyDown = (event) => {
3463-
3464-
if (event.ctrlKey && event.key === "z") {
3465-
this._restoreTrash(activity);
3466-
activity.__tick();
3467-
event.preventDefault();
3479+
this._renderTrashView = () => {
3480+
if (!activity.blocks || !activity.blocks.trashStacks || activity.blocks.trashStacks.length === 0) {
3481+
return;
34683482
}
3469-
};
3470-
3471-
// Attach keydown event listener to document
3472-
document.addEventListener("keydown", this.handleKeyDown);
3483+
const trashList = document.getElementById('trashList');
3484+
const trashView = document.createElement('div');
3485+
trashView.id = 'trashView';
3486+
trashView.classList.add('trash-view');
3487+
3488+
// Sticky icons
3489+
const buttonContainer = document.createElement('div');
3490+
buttonContainer.classList.add('button-container');
3491+
3492+
const restoreLastIcon = document.createElement('a');
3493+
restoreLastIcon.id = 'restoreLastIcon';
3494+
restoreLastIcon.classList.add('restore-last-icon');
3495+
restoreLastIcon.innerHTML = '<i class="material-icons md-48">restore_from_trash</i>';
3496+
restoreLastIcon.addEventListener('click', () => {
3497+
this._restoreTrashById(this.blocks.trashStacks[this.blocks.trashStacks.length - 1]);
3498+
trashView.classList.add('hidden');
3499+
});
3500+
3501+
const restoreAllIcon = document.createElement('a');
3502+
restoreAllIcon.id = 'restoreAllIcon';
3503+
restoreAllIcon.classList.add('restore-all-icon');
3504+
restoreAllIcon.innerHTML = '<i class="material-icons md-48">delete_sweep</i>';
3505+
restoreAllIcon.addEventListener('click', () => {
3506+
while (this.blocks.trashStacks.length > 0) {
3507+
this._restoreTrashById(this.blocks.trashStacks[0]);
3508+
}
3509+
trashView.classList.add('hidden');
3510+
});
3511+
restoreLastIcon.setAttribute("title", _("Restore last item"));
3512+
restoreAllIcon.setAttribute("title", _("Restore all items"));
3513+
3514+
buttonContainer.appendChild(restoreLastIcon);
3515+
buttonContainer.appendChild(restoreAllIcon);
3516+
trashView.appendChild(buttonContainer);
3517+
3518+
// Render trash items
3519+
this.blocks.trashStacks.forEach((blockId) => {
3520+
const block = this.blocks.blockList[blockId];
3521+
const listItem = document.createElement('div');
3522+
listItem.classList.add('trash-item');
3523+
3524+
const svgData = block.artwork;
3525+
const encodedData = 'data:image/svg+xml;utf8,' + encodeURIComponent(svgData);
3526+
3527+
const img = document.createElement('img');
3528+
img.src = encodedData;
3529+
img.alt = 'Block Icon';
3530+
img.classList.add('trash-item-icon');
3531+
3532+
const textNode = document.createTextNode(block.name);
3533+
3534+
listItem.appendChild(img);
3535+
listItem.appendChild(textNode);
3536+
listItem.dataset.blockId = blockId;
3537+
3538+
listItem.addEventListener('mouseover', () => listItem.classList.add('hover'));
3539+
listItem.addEventListener('mouseout', () => listItem.classList.remove('hover'));
3540+
listItem.addEventListener('click', () => {
3541+
this._restoreTrashById(blockId);
3542+
trashView.classList.add('hidden');
3543+
});
3544+
handleClickOutsideTrashView(trashView);
3545+
3546+
trashView.appendChild(listItem);
3547+
});
3548+
3549+
const existingView = document.getElementById('trashView');
3550+
if (existingView) {
3551+
trashList.replaceChild(trashView, existingView);
3552+
} else {
3553+
trashList.appendChild(trashView);
3554+
}
3555+
};
34733556

34743557
/*
34753558
* Open aux menu
@@ -5840,7 +5923,7 @@ class Activity {
58405923
this.helpfulWheelItems.push({label: "Increase block size", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(BIGGERBUTTON)), display: true, fn: doLargerBlocks});
58415924

58425925
if (!this.helpfulWheelItems.find(ele => ele.label === "Restore"))
5843-
this.helpfulWheelItems.push({label: "Restore", icon: "imgsrc:header-icons/restore-from-trash.svg", display: true, fn: restoreTrash});
5926+
this.helpfulWheelItems.push({label: "Restore", icon: "imgsrc:header-icons/restore-from-trash.svg", display: true, fn: restoreTrashPop});
58445927

58455928
if (!this.helpfulWheelItems.find(ele => ele.label === "Turtle Wrap Off"))
58465929
this.helpfulWheelItems.push({label: "Turtle Wrap Off", icon: "imgsrc:header-icons/wrap-text.svg", display: true, fn: this.toolbar.changeWrap});

0 commit comments

Comments
 (0)