Skip to content

Commit

Permalink
Add bulk delete feature (#3885)
Browse files Browse the repository at this point in the history
* add bulk delete feature

* Fix creation of space blocks on bulk delete

* fix space around operators

* fix comment

* fix spaces
  • Loading branch information
apsinghdev authored May 22, 2024
1 parent 43ac915 commit 5413a5b
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 14 deletions.
227 changes: 221 additions & 6 deletions js/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,15 @@ class Activity {
this.projectID = null;
this.storage = localStorage;

// Flag to indicate whether the user is performing a 2D drag operation.
this.isDragging = false;

// Flag to indicate the selection mode is on
this.selectionModeOn = false;

// Flag to check if the helpful search widget is active or not (for "click" event handler purpose)
this.isHelpfulSearchWidgetOn = false;

this.beginnerMode = true;
try {
if (this.storage.beginnerMode === undefined) {
Expand Down Expand Up @@ -457,6 +466,19 @@ class Activity {
}

this.showHelpfulSearchWidget();
this.isHelpfulSearchWidgetOn = true;
}

// hides helpfulSearchDiv on canvas

this._hideHelpfulSearchWidget = (e) => {
if (docById("helpfulWheelDiv").style.display !== "none") {
docById("helpfulWheelDiv").style.display = "none";
}
if (docById("helpfulSearchDiv").style.display !== "none" && e.target.id !== "helpfulSearch") {
docById("helpfulSearchDiv").style.display = "none";
}
that.__tick();
}

/*
Expand Down Expand Up @@ -5009,6 +5031,195 @@ class Activity {
img.src = "data:image/svg+xml;base64," + window.btoa(base64Encode(svgData));
};

// Setup mouse events to start the drag

this.setupMouseEvents = () => {
document.addEventListener(
"mousedown",
(event) => {
event.preventDefault();
event.stopPropagation();
if (event.target.id === "myCanvas") {
this._createDrag(event);
}
},
false
);
};

// deselect the selected blocks

this.deselectSelectedBlocks = () => {
this.unhighlightSelectedBlocks(false);
this.setSelectionMode(false);
}


this._create2Ddrag = () => {
this.dragArea = {};
this.selectedBlocks = [];
this.startX = 0;
this.startY = 0;
this.currentX = 0;
this.currentY = 0;
this.hasMouseMoved = false;
this.selectionArea = document.createElement("div");
document.body.appendChild(this.selectionArea);

this.setupMouseEvents();

document.addEventListener("mousemove", (event) => {
this.hasMouseMoved = true;
event.preventDefault();
// this.selectedBlocks = [];
if(this.isDragging){
this.currentX = event.clientX;
this.currentY = event.clientY;
if (!this.blocks.isBlockMoving) {
this.setSelectionMode(true);
this.drawSelectionArea();
this.selectedBlocks = this.selectBlocksInDragArea();
this.unhighlightSelectedBlocks(true, true);
this.blocks.setSelectedBlocks(this.selectedBlocks);
}
}
})

document.addEventListener("mouseup", (event) => {
event.preventDefault();
this.isDragging = false;
this.selectionArea.style.display = "none";
this.startX = 0;
this.startY = 0;
this.currentX = 0;
this.currentY = 0;
setTimeout(() => {
this.hasMouseMoved = false;
}, 100);
})

};

// Set starting points of the drag

this._createDrag = (event) => {
this.isDragging = true;
this.startX = event.clientX;
this.startY = event.clientY;
};

// Draw the area that has been dragged

this.drawSelectionArea = () => {
let x = Math.min(this.startX, this.currentX);
let y = Math.min(this.startY, this.currentY);
let width = Math.abs(this.currentX - this.startX);
let height = Math.abs(this.currentY - this.startY);

this.selectionArea.style.display = "block";
this.selectionArea.style.position = "absolute";
this.selectionArea.style.left = x + "px";
this.selectionArea.style.top = y + "px";
this.selectionArea.style.height = height + "px";
this.selectionArea.style.width = width + "px";
this.selectionArea.style.zIndex = "9999";
this.selectionArea.style.backgroundColor = "rgba(137, 207, 240, 0.5)";
this.selectionArea.style.pointerEvents = "none";

this.dragArea = { x, y, width, height };
};

// Check if the block is overlapping the dragged area.

this.rectanglesOverlap = (rect1, rect2) => {
return (
rect1.x + rect1.width > rect2.x &&
rect1.x < rect2.x + rect2.width &&
rect1.y + rect1.height > rect2.y &&
rect1.y < rect2.y + rect2.height
);
}

// Select the blocks that overlap the dragged area.

this.selectBlocksInDragArea = (dragArea, blocks) => {
let selectedBlocks = [];
this.dragRect = this.dragArea;

this.blocks.blockList.forEach((block) => {
this.blockRect = {
x: this.scrollBlockContainer ? block.container.x + this.blocksContainer.x : block.container.x,
y: block.container.y + this.blocksContainer.y,
height: block.height,
width: block.width
};

if(this.rectanglesOverlap(this.blockRect, this.dragRect)){
selectedBlocks.push(block);
}
})
return selectedBlocks;
}

// Unhighlight the selected blocks

this.unhighlightSelectedBlocks = (unhighlight, selectionModeOn) => {
for (let i = 0; i < this.selectedBlocks.length; i++) {
for (const blk in this.blocks.blockList) {
if (this.isEqual(this.blocks.blockList[blk], this.selectedBlocks[i])){
if (unhighlight) {
this.blocks.unhighlightSelectedBlocks(blk, true);
} else {
this.blocks.highlight(blk, true);
this.refreshCanvas();
}
}
}
}
}

// Check if two blocks are same or not.

this.isEqual = (obj1, obj2) => {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);

if (keys1.length !== keys2.length) {
return false;
}

for (let key of keys1) {
if (!obj2.hasOwnProperty(key)) {
return false;
}
}

for (let key of keys1) {
if (obj1[key] !== obj2[key]) {
return false;
}
}

return true;
};

this.setSelectionMode = (selection) => {
if (selection) {
if (!this.selectionModeOn) {
if (this.selectedBlocks.length !== 0) {
this.selectedBlocks = [];
this.selectionModeOn = selection;
this.blocks.setSelection(this.selectionModeOn);
}
}
} else {
this.selectedBlocks = [];
this.selectionModeOn = selection;
this.blocks.setSelection(this.selectionModeOn);
}
}


/*
* Inits everything. The main function.
*/
Expand Down Expand Up @@ -5056,13 +5267,13 @@ class Activity {
});

document.addEventListener("click", (e) => {
if (docById("helpfulWheelDiv").style.display !== "none") {
docById("helpfulWheelDiv").style.display = "none";
}
if (docById("helpfulSearchDiv").style.display !== "none" && e.target.id !== "helpfulSearch") {
docById("helpfulSearchDiv").style.display = "none";
if(!this.hasMouseMoved){
if (this.selectionModeOn) {
this.deselectSelectedBlocks();
} else {
this._hideHelpfulSearchWidget(e);
}
}
that.__tick();
});

this._createMsgContainer(
Expand Down Expand Up @@ -5614,6 +5825,10 @@ class Activity {

this.prepSearchWidget();

// create functionality of 2D drag to select blocks in bulk

this._create2Ddrag();

/*
document.addEventListener("mousewheel", scrollEvent, false);
document.addEventListener("DOMMouseScroll", scrollEvent, false);
Expand Down
18 changes: 14 additions & 4 deletions js/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,14 @@ class Block {
this.container.updateCache();
}

unhighlightSelectedBlocks(blk, selection) {
if (selection) {
this.blocks.unhighlight(blk, true);
this.disconnectedBitmap.visible = true;
this.container.updateCache();
};
}

/**
* Resize and update number of slots in argClamp.
* @public
Expand Down Expand Up @@ -2752,8 +2760,9 @@ class Block {
if (!that.activity.logo.runningLilypond) {
document.body.style.cursor = "pointer";
}

that.blocks.highlight(thisBlock, true);
if (!that.blocks.selectionModeOn) {
that.blocks.highlight(thisBlock, true);
}
that.blocks.activeBlock = thisBlock;
// that.activity.refreshCanvas();
});
Expand Down Expand Up @@ -3043,8 +3052,9 @@ class Block {
that.blocks.longPressTimeout = null;
that.blocks.clearLongPress();
}

that.blocks.unhighlight(thisBlock, true);
if (!that.blocks.selectionModeOn) {
that.blocks.unhighlight(thisBlock, true);
}
that.blocks.activeBlock = null;

moved = false;
Expand Down
27 changes: 25 additions & 2 deletions js/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ class Blocks {
this.inLongPress = false;
this.customTemperamentDefined = false;

// Flag to track a block's movement to avoid drag-to-select functionality while moving a block
this.isBlockMoving = false;

this.selectionModeOn = false;

this.selectedBlocks = [];

/**
* We stage deletion of prototype action blocks on the palette so
* as to avoid palette refresh race conditions.
Expand Down Expand Up @@ -2134,7 +2141,7 @@ class Blocks {

blk = this.insideExpandableBlock(blk);
}

this.isBlockMoving = false;
this.adjustExpandableClampBlock();
this.activity.refreshCanvas();
};
Expand Down Expand Up @@ -2395,7 +2402,7 @@ class Blocks {
*/
this.moveBlockRelative = (blk, dx, dy) => {
this.inLongPress = false;

this.isBlockMoving = true;
const myBlock = this.blockList[blk];
if (myBlock.container != null) {
myBlock.container.x += dx;
Expand Down Expand Up @@ -7013,5 +7020,21 @@ class Blocks {
this.bringToTop();
this.activity.refreshCanvas();
};

this.setSelection = (selection) => {
this.selectionModeOn = selection;
};

this.setSelectionToActivity = (selection) => {
this.activity.setSelectionMode(selection);
};

this.unhighlightSelectedBlocks = (blk, selection) => {
this.blockList[blk].unhighlightSelectedBlocks(blk, selection);
};

this.setSelectedBlocks = (blocks) => {
this.selectedBlocks = blocks;
};
}
}
30 changes: 28 additions & 2 deletions js/piemenus.js
Original file line number Diff line number Diff line change
Expand Up @@ -3436,7 +3436,7 @@ const piemenuBlockContext = (block) => {
ele.display = true;
ele.fn = stackPasting.bind(that);
}
})
});
};

wheel.navItems[0].navigateFunction = stackPasting;
Expand All @@ -3450,7 +3450,33 @@ const piemenuBlockContext = (block) => {
wheel.navItems[2].navigateFunction = () => {
that.blocks.activeBlock = blockBlock;
that.blocks.extract();
that.blocks.sendStackToTrash(that.blocks.blockList[blockBlock]);
if (that.blocks.selectionModeOn){
const blocksArray = that.blocks.selectedBlocks;
// figure out which of the blocks in selectedBlocks are clamp blocks and nonClamp blocks.
const clampBlocks = [];
const nonClampBlocks = [];

for (let i = 0; i < blocksArray.length; i++) {
if (that.blocks.selectedBlocks[i].isClampBlock()) {
clampBlocks.push(that.blocks.selectedBlocks[i]);
} else if (that.blocks.selectedBlocks[i].isDisconnected()) {
nonClampBlocks.push(that.blocks.selectedBlocks[i]);
}
}

for (let i = 0; i < clampBlocks.length; i++) {
that.blocks.sendStackToTrash(clampBlocks[i]);
}

for (let i = 0; i < nonClampBlocks.length; i++) {
that.blocks.sendStackToTrash(nonClampBlocks[i]);
}
// set selection mode to false
that.blocks.setSelectionToActivity(false);
that.blocks.activity.refreshCanvas();
} else {
that.blocks.sendStackToTrash(that.blocks.blockList[blockBlock]);
}
docById("contextWheelDiv").style.display = "none";
};

Expand Down

0 comments on commit 5413a5b

Please sign in to comment.