diff --git a/js/activity.js b/js/activity.js index ed4a6cd6a0..9ee72697d3 100644 --- a/js/activity.js +++ b/js/activity.js @@ -441,7 +441,7 @@ class Activity { // Create the div for the close button (cross button) const closeButtonDiv = document.createElement("div"); - closeButtonDiv.style.cssText = + closeButtonDiv.style.cssText = "position: absolute;" + "top: 10px;" + // Adjust the top position to center it vertically "right: 10px;" + // Position the button on the right side of the helpfulSearchDiv @@ -450,7 +450,7 @@ class Activity { // Create the cross button itself const closeButton = document.createElement("button"); closeButton.textContent = "×"; // You can use HTML entity or an icon - closeButton.style.cssText = + closeButton.style.cssText = "position: absolute;" + "top: 50%;" + // Center vertically "right: -30px;" + // Place it outside the input, adjust as needed @@ -528,10 +528,10 @@ class Activity { if (this.isHelpfulSearchWidgetOn) { this._hideHelpfulSearchWidget(); } - if (!this.blocks.isCoordinateOnBlock(event.clientX, event.clientY) && + if (!this.blocks.isCoordinateOnBlock(event.clientX, event.clientY) && event.target.id === "myCanvas") { this._displayHelpfulWheel(event); - } + } }, false ); @@ -545,20 +545,20 @@ class Activity { const x = event.clientX; const y = event.clientY; - + const canvasLeft = this.canvas.offsetLeft + 28 * this.getStageScale(); const canvasTop = this.canvas.offsetTop + 6 * this.getStageScale(); - + const helpfulWheelLeft = Math.max(Math.round(x * this.getStageScale() + canvasLeft) - 150, canvasLeft); const helpfulWheelTop = Math.max(Math.round(y * this.getStageScale() + canvasTop) - 150, canvasTop); docById("helpfulWheelDiv").style.left = helpfulWheelLeft + "px"; - + docById("helpfulWheelDiv").style.top = helpfulWheelTop + "px"; - + const windowWidth = window.innerWidth - 20; const windowHeight = window.innerHeight - 20; - + if (helpfulWheelLeft + 350 > windowWidth) { docById("helpfulWheelDiv").style.left = (windowWidth - 350) + "px"; } @@ -590,11 +590,11 @@ class Activity { const closeHelpfulWheel = (e) => { const isClickInside = helpfulWheelDiv.contains(e.target); if (!isClickInside) { - helpfulWheelDiv.style.display = "none"; + helpfulWheelDiv.style.display = "none"; document.removeEventListener("click", closeHelpfulWheel); } }; - + document.addEventListener("click", closeHelpfulWheel); } @@ -662,11 +662,11 @@ class Activity { /** * Recenters blocks by updating their position on the screen. - * + * * This function triggers the `_findBlocks` method on the provided `activity` object, * which recalculates the positions of blocks. If the 'helpfulWheelDiv' element is visible, * it is hidden, and the `__tick` method is called to update the activity state. - * + * * @param {Object} activity - The activity instance containing the blocks to recenter. * @constructor */ @@ -684,6 +684,9 @@ class Activity { * This method is part of the internal mechanism to ensure that blocks are displayed correctly and efficiently. * @constructor */ + // Flag to track number of clicks and for alternate mode switching while clicking + this._isFirstHomeClick = true; + this._findBlocks = () => { // Ensure visibility of blocks if (!this.blocks.visible) { @@ -699,100 +702,156 @@ class Activity { this.blocksContainer.x = 0; this.blocksContainer.y = 0; - // Calculate top and left positions for block placement - let toppos; - if (this.auxToolbar.style.display === "block") { - toppos = 90 + this.toolbarHeight; - } else { - toppos = 90; - } - const leftpos = Math.floor(this.canvas.width / 4); + if (this._isFirstHomeClick) { + // First clicked logic (arrange blocks in rows may have overlapping of blocks) + let toppos; + if (this.auxToolbar.style.display === "block") { + toppos = 90 + this.toolbarHeight; + } else { + toppos = 90; + } + const leftpos = Math.floor(this.canvas.width / 4); - // Update palettes and calculate initial block position - this.palettes.updatePalettes(); - let x = Math.floor(leftpos * this.turtleBlocksScale); - let y = Math.floor(toppos * this.turtleBlocksScale); - let even = true; + this.palettes.updatePalettes(); + let x = Math.floor(leftpos * this.turtleBlocksScale); + let y = Math.floor(toppos * this.turtleBlocksScale); + let even = true; - // Position start blocks first - for (const blk in this.blocks.blockList) { - if (!this.blocks.blockList[blk].trash) { - const myBlock = this.blocks.blockList[blk]; - if (myBlock.name !== "start") { - continue; - } + // Position "start" blocks first + for (const blk in this.blocks.blockList) { + if (!this.blocks.blockList[blk].trash) { + const myBlock = this.blocks.blockList[blk]; + if (myBlock.name !== "start") { + continue; + } + if (myBlock.connections[0] === null) { + const dx = x - myBlock.container.x; + const dy = y - myBlock.container.y; + this.blocks.moveBlockRelative(blk, dx, dy); + this.blocks.findDragGroup(blk); + + if (this.blocks.dragGroup.length > 0) { + for (let b = 0; b < this.blocks.dragGroup.length; b++) { + const bblk = this.blocks.dragGroup[b]; + if (b !== 0) { + this.blocks.moveBlockRelative(bblk, dx, dy); + } + } + } - // Move block and its connected group - if (myBlock.connections[0] === null) { - const dx = x - myBlock.container.x; - const dy = y - myBlock.container.y; - this.blocks.moveBlockRelative(blk, dx, dy); - this.blocks.findDragGroup(blk); - if (this.blocks.dragGroup.length > 0) { - for (let b = 0; b < this.blocks.dragGroup.length; b++) { - const bblk = this.blocks.dragGroup[b]; - if (b !== 0) { - this.blocks.moveBlockRelative(bblk, dx, dy); + x += Math.floor(150 * this.turtleBlocksScale); + if (x > (this.canvas.width * 7) / 8 / this.turtleBlocksScale) { + even = !even; + if (even) { + x = Math.floor(leftpos); + } else { + x = Math.floor(leftpos + STANDARDBLOCKHEIGHT); } + y += STANDARDBLOCKHEIGHT; } } + } + } - // Update x and y positions for next block placement - x += Math.floor(150 * this.turtleBlocksScale); - if (x > (this.canvas.width * 7) / 8 / this.turtleBlocksScale) { - even = !even; - if (even) { - x = Math.floor(leftpos); - } else { - x = Math.floor(leftpos + STANDARDBLOCKHEIGHT); + // Position other blocks + for (const blk in this.blocks.blockList) { + if (!this.blocks.blockList[blk].trash) { + const myBlock = this.blocks.blockList[blk]; + if (myBlock.name === "start") { + continue; + } + if (myBlock.connections[0] === null) { + const dx = x - myBlock.container.x; + const dy = y - myBlock.container.y; + this.blocks.moveBlockRelative(blk, dx, dy); + this.blocks.findDragGroup(blk); + + if (this.blocks.dragGroup.length > 0) { + for (let b = 0; b < this.blocks.dragGroup.length; b++) { + const bblk = this.blocks.dragGroup[b]; + if (b !== 0) { + this.blocks.moveBlockRelative(bblk, dx, dy); + } + } } - y += STANDARDBLOCKHEIGHT; + x += Math.floor(150 * this.turtleBlocksScale); + if (x > (this.canvas.width * 7) / 8 / this.turtleBlocksScale) { + even = !even; + if (even) { + x = Math.floor(leftpos); + } else { + x = Math.floor(leftpos + STANDARDBLOCKHEIGHT); + } + y += STANDARDBLOCKHEIGHT; + } } } } - } + } else { + // Second click logic (arrange blocks in columns this avoid overlapping of blocks) + let toppos; + if (this.auxToolbar.style.display === "block") { + toppos = 90 + this.toolbarHeight; + } else { + toppos = 90; + } - // Position other blocks - for (const blk in this.blocks.blockList) { - if (!this.blocks.blockList[blk].trash) { - const myBlock = this.blocks.blockList[blk]; - if (myBlock.name === "start") { - continue; - } + /** + * Device type resolution ranges and typical orientation: + * Desktop: 1024x768 to 5120x2880 (Landscape primary, Portrait supported) + * Tablet: 768x1024 to 2560x1600 (Portrait common, Landscape supported) + * Mobile: 320x480 to 1440x3200 (Portrait primary, Landscape supported) + * Minimum column width is set to 400px to ensure readability and usability. + */ + + const screenWidth = window.innerWidth; + const minColumnWidth = 400; + let numColumns = screenWidth <= 320 ? 1 : Math.floor(screenWidth / minColumnWidth); + + const baseColumnSpacing = screenWidth / numColumns; + const columnSpacing = baseColumnSpacing * 1.2; + + const initialY = Math.floor(toppos * this.turtleBlocksScale); + const baseVerticalSpacing = Math.floor(20 * this.turtleBlocksScale); + const verticalSpacing = baseVerticalSpacing * 1.2; - // Move block and its connected group - if (myBlock.connections[0] === null) { - const dx = x - myBlock.container.x; - const dy = y - myBlock.container.y; - this.blocks.moveBlockRelative(blk, dx, dy); - this.blocks.findDragGroup(blk); - if (this.blocks.dragGroup.length > 0) { - for (let b = 0; b < this.blocks.dragGroup.length; b++) { - const bblk = this.blocks.dragGroup[b]; - if (b !== 0) { - this.blocks.moveBlockRelative(bblk, dx, dy); + const columnXPositions = Array.from({ length: numColumns }, (_, i) => + Math.floor(i * columnSpacing + columnSpacing / 2) + ); + const columnYPositions = Array(numColumns).fill(initialY); + + for (const blk in this.blocks.blockList) { + if (!this.blocks.blockList[blk].trash) { + const myBlock = this.blocks.blockList[blk]; + if (myBlock.connections[0] === null) { + let minYIndex = 0; + for (let i = 1; i < numColumns; i++) { + if (columnYPositions[i] < columnYPositions[minYIndex]) { + minYIndex = i; } } - } - // Update x and y positions for next block placement - x += 150 * this.turtleBlocksScale; - if (x > (this.canvas.width * 7) / 8 / this.turtleBlocksScale) { - even = !even; - if (even) { - x = Math.floor(leftpos); - } else { - x = Math.floor(leftpos + STANDARDBLOCKHEIGHT); - } + const dx = columnXPositions[minYIndex] - myBlock.container.x; + const dy = columnYPositions[minYIndex] - myBlock.container.y; + this.blocks.moveBlockRelative(blk, dx, dy); + this.blocks.findDragGroup(blk); - y += STANDARDBLOCKHEIGHT; + if (this.blocks.dragGroup.length > 0) { + for (let b = 0; b < this.blocks.dragGroup.length; b++) { + const bblk = this.blocks.dragGroup[b]; + if (b !== 0) { + this.blocks.moveBlockRelative(bblk, dx, dy); + } + } + } + columnYPositions[minYIndex] += myBlock.height + verticalSpacing; } } } } - // Blocks are all home, so reset go-home-button. + // Reset go-home button this.setHomeContainers(false); this.boundary.hide(); @@ -805,14 +864,16 @@ class Activity { this.turtles.turtleList[turtle].painter.doSetHeading(0); this.turtles.turtleList[turtle].painter.penState = savedPenState; } + // Alternate mode switching on clicking Home button + this._isFirstHomeClick = !this._isFirstHomeClick; }; /** * Toggles the visibility of the home button container. - * + * * Depending on the state provided, this method will either hide or show the home button container. * If the home button container is not initialized, the function will exit early. - * + * * @param {boolean} homeState - If true, shows the container; if false, hides it. * @constructor */ @@ -1139,7 +1200,7 @@ class Activity { document.body.removeChild(modal); clearCanvasAction(); }); - + const cancelBtn = document.createElement("button"); cancelBtn.textContent = "Cancel"; cancelBtn.style.backgroundColor = "#f1f1f1"; @@ -1152,18 +1213,18 @@ class Activity { cancelBtn.addEventListener("click", () => { document.body.removeChild(modal); }); - + buttonContainer.appendChild(confirmBtn); buttonContainer.appendChild(cancelBtn); modal.appendChild(buttonContainer); document.body.appendChild(modal); }; - + this._allClear = (noErase, skipConfirmation = false) => { const clearCanvasAction = () => { this.blocks.activeBlock = null; hideDOMLabel(); - + this.logo.boxes = {}; this.logo.time = 0; this.hideMsgs(); @@ -1180,14 +1241,14 @@ class Activity { this.turtles.turtleList[turtle].painter.doClear(true, true, true); } } - + this.blocksContainer.x = 0; this.blocksContainer.y = 0; - + Element.prototype.remove = () => { this.parentElement.removeChild(this); }; - + NodeList.prototype.remove = HTMLCollection.prototype.remove = () => { for (let i = 0, len = this.length; i < len; i++) { if (this[i] && this[i].parentElement) { @@ -1195,18 +1256,18 @@ class Activity { } } }; - + const table = docById("myTable"); if (table !== null) { table.remove(); } - + if (docById("helpfulWheelDiv").style.display !== "none") { docById("helpfulWheelDiv").style.display = "none"; this.__tick(); } }; - + if (skipConfirmation) { clearCanvasAction(); } else { @@ -1566,12 +1627,12 @@ class Activity { activity.save.saveBlockArtwork.bind(activity.save), activity.save.saveBlockArtworkPNG.bind(activity.save) ); - + // Regenerate palettes if (activity.regeneratePalettes) { activity.regeneratePalettes(); } - + // Force immediate canvas refresh activity.refreshCanvas(); }; @@ -1692,7 +1753,7 @@ class Activity { that.resizeDebounce = false; }, 200); } - + await this.setSmallerLargerStatus(); await this.stage.update(); }; @@ -1709,7 +1770,7 @@ class Activity { } }; - + /** * Manages the resizing of blocks to handle larger size. */ @@ -2054,7 +2115,7 @@ class Activity { const data = normalizeWheel(event); const delY = data.pixelY; const delX = data.pixelX; - + if (event.ctrlKey) { event.preventDefault(); delY < 0 ? doLargerBlocks(that) : doSmallerBlocks(that); @@ -2067,7 +2128,7 @@ class Activity { } else { event.preventDefault(); } - + that.refreshCanvas(); }; @@ -2121,7 +2182,7 @@ class Activity { that.stage.on("stagemousemove", (event) => { that.stageX = event.stageX; that.stageY = event.stageY; - + if (!that.moving) return; // if we are moving the block container, deselect the active block. @@ -2845,7 +2906,7 @@ class Activity { this.blocksContainer.x -= this.canvas.width / 10; this.stage.update(); } - + } } else if (event.ctrlKey) { switch (event.keyCode) { @@ -3161,7 +3222,7 @@ class Activity { this._innerHeight = window.innerHeight; this._outerWidth = window.outerWidth; this._outerHeight = window.outerHeight; - + if (docById("labelDiv").classList.contains("hasKeyboard")) { return; } @@ -3327,7 +3388,7 @@ class Activity { this.blocks.checkBounds(); }; - + const container = document.getElementById("canvasContainer"); const canvas = document.getElementById("myCanvas"); const overCanvas = document.getElementById("canvas"); @@ -3376,7 +3437,7 @@ class Activity { }, 100); }); window.addEventListener("orientationchange", handleResize); - const that = this; + const that = this; const resizeCanvas_ = () => { try { that._onResize(false); @@ -3386,10 +3447,10 @@ class Activity { console.error("An error occurred in resizeCanvas_:", error); } }; - + resizeCanvas_(); window.addEventListener("orientationchange", resizeCanvas_); - + /* * Restore last stack pushed to trashStack back onto canvas. * Hides palettes before update @@ -3421,7 +3482,7 @@ class Activity { this._restoreTrashById(this.blocks.trashStacks[this.blocks.trashStacks.length - 1]); activity.textMsg( _("Item restored from the trash."), - 3000 + 3000 ); if (docById("helpfulWheelDiv").style.display !== "none") { @@ -3440,7 +3501,6 @@ class Activity { for (const name in this.palettes.dict) { this.palettes.dict[name].hideMenu(true); } - this.blocks.activeBlock = null; this.refreshCanvas(); @@ -3636,10 +3696,10 @@ class Activity { child.style.top = `${btnY + value}px`; }); }; - + if (!resize && this.toolbarHeight === 0) { dy = cellsize + LEADING + 5; - + this.toolbarHeight = dy; this.palettes.deltaY(dy); this.turtles.deltaY(dy); @@ -3655,16 +3715,16 @@ class Activity { this.tenorBitmap.y += dy; this.bassBitmap.y += dy; this.blocks.checkBounds(); - + } else{ dy = this.toolbarHeight ; - this.toolbarHeight = 0; - + this.toolbarHeight = 0; + this.turtles.deltaY(-dy); this.palettes.deltaY(-dy); this.blocksContainer.y -= dy this.changeTopButtonsPosition(-dy); - + this.cartesianBitmap.y -= dy; this.polarBitmap.y -= dy; this.trebleBitmap.y -= dy; @@ -3832,7 +3892,7 @@ class Activity { block.container.uncache(); block.container.cache(); } - if (block.bitmap) { + if (block.bitmap) { block.bitmap.uncache(); block.bitmap.cache(); } @@ -3847,12 +3907,12 @@ class Activity { return; } - this.blockRefreshCanvas = true; + this.blockRefreshCanvas = true; // Force stage clear and update this.stage.clear(); this.stage.update(); this.update = true; - + const that = this; setTimeout(() => { that.blockRefreshCanvas = false; @@ -3944,7 +4004,7 @@ class Activity { }, 5000); }; - + const standardDurations = [ { value: "1/1", duration: 1 }, { value: "1/2", duration: 0.5 }, @@ -3955,11 +4015,11 @@ class Activity { { value: "1/64", duration: 0.015625 }, { value: "1/128", duration: 0.0078125 } ]; - + this.getClosestStandardNoteValue = function(duration) { let closest = standardDurations[0]; let minDiff = Math.abs(duration - closest.duration); - + for (let i = 1; i < standardDurations.length; i++) { let diff = Math.abs(duration - standardDurations[i].duration); if (diff < minDiff) { @@ -3967,12 +4027,12 @@ class Activity { minDiff = diff; } } - + return closest.value.split('/').map(Number); } - + this.transcribeMidi = async function(midi) { - let currentMidi = midi; + let currentMidi = midi; let jsONON = [] ; let actionBlockCounter = 0; // Counter for action blocks let actionBlockNames = []; // Array to store action block names @@ -3992,7 +4052,7 @@ class Activity { } else { currentMidiTempoBpm = defaultTempo; } - + let defaultTimeSignature = [4, 4]; let currentMidiTimeSignature = currentMidi.header.timeSignatures; if (currentMidiTimeSignature && currentMidiTimeSignature.length > 0) { @@ -4000,7 +4060,7 @@ class Activity { } else { currentMidiTimeSignature = defaultTimeSignature; } - + let precurssionFlag = false; const isPercussion=[]; // console.log("tempoBpm is: ", currentMidiTempoBpm); @@ -4012,7 +4072,7 @@ class Activity { let isPercussionTrack =(track.instrument.percussion && (track.channel===9 || track.channel===10)) isPercussion.push(isPercussionTrack); if (!track.notes.length) return; - let r = jsONON.length; + let r = jsONON.length; // console.log("notes: ",track.notes); if(track.instrument.percussion && (track.channel==9 || track.channel==10) && precurssionFlag==false){ jsONON.push( @@ -4228,9 +4288,9 @@ class Activity { } actionBlockPerTrack[trackCount] = 0; instruments[trackCount] = instrument; - + let actionBlockName = `track${trackCount}chunk${actionBlockCounter}`; - + jsONON.push( [r, ["action", { collapsed: false }], 150, 100, [null, r+1, r+2, null]], [r+1, ["text", { value: actionBlockName }], 0, 0, [r]] @@ -4262,7 +4322,7 @@ class Activity { let lastNotes=[]; let lastNote = sched[sched.length - 1]; // let secondLastNote = sched.length > 1 ? sched[sched.length - 2] : null; - + if (sched[sched.length - 1].start === start && sched[sched.length - 1].end === end) { sched[sched.length - 1].notes.push(name); } @@ -4280,7 +4340,7 @@ class Activity { let newNotes2 = [...prevNotes2]; newNotes2.push(name); lastNote.end = start; - + if (start < oldEnd2) { sched.push({ start: start, @@ -4295,7 +4355,7 @@ class Activity { let oldStart = lastNotes[lastNotes.length-1].start; let newNotes = [...prevNotes]; newNotes.push(name); - + if (lastNotes[lastNotes.length-1].end <= end) { sched.push( { @@ -4406,7 +4466,7 @@ class Activity { let noteSum = 0; let currentActionBlock = []; - + let addNewActionBlock = (isLastBlock=false) => { let r = jsONON.length; let actionBlockName = `track${trackCount}chunk${actionBlockCounter}`; @@ -4426,14 +4486,14 @@ class Activity { [r+1, ["text", { value: actionBlockName }], 0, 0, [r]], ...currentActionBlock ); - + } if (isLastBlock) { let lastIndex = jsONON.length - 1; // Set the last hidden block's second value to null jsONON[lastIndex][4][1] = null; } - + currentActionBlock = []; actionBlockCounter++; // Increment the action block counter offset+=100; @@ -4446,7 +4506,7 @@ class Activity { let temp = this.getClosestStandardNoteValue(dur * 3 / 8); shortestNoteDenominator=Math.max(shortestNoteDenominator,temp[1]); } - + for (let i in sched) { if (stopProcessing) break; // Exit inner loop if flag is set let notes = sched[i].notes; @@ -4494,24 +4554,24 @@ class Activity { // obj[1]=obj[1]/scalingFactor; // else // obj[0]=obj[0]*scalingFactor; - + // To get the reduced fraction for 4/2 to 2/1 obj=this.getClosestStandardNoteValue(obj[0]/obj[1]); - + // Since we are going to add action block in the front later if (k != 0) val = val + 2; let pitches = getPitch(val + 5, notes, val); currentActionBlock.push( - [val, ["newnote", {"collapsed": true}], 0, 0, [first ? val-2 : val-1, val+1, val+4, val+pitches.length+5]], - [val + 1, "divide", 0, 0, [val, val+2, val+3]], - [val + 2, ["number", { value: obj[0] }], 0, 0, [val + 1]], + [val, ["newnote", {"collapsed": true}], 0, 0, [first ? val-2 : val-1, val+1, val+4, val+pitches.length+5]], + [val + 1, "divide", 0, 0, [val, val+2, val+3]], + [val + 2, ["number", { value: obj[0] }], 0, 0, [val + 1]], [val + 3, ["number", { value: obj[1] }], 0, 0, [val + 1]], [val + 4, "vspace", 0, 0, [val, val + 5]], ); noteblockCount++; pitches[0][4][0] = val + 4; currentActionBlock = currentActionBlock.concat(pitches); - + let newLen = jsONON.length + currentActionBlock.length; if (k != 0) newLen = newLen + 2; currentActionBlock.push( @@ -4520,18 +4580,18 @@ class Activity { if (isLastNoteInBlock || isLastNoteInSched ) { addNewActionBlock(isLastNoteInSched); } - + if (totalnoteblockCount >= MAX_NOTEBLOCKS) { this.textMsg("MIDI file is too large.. Generating only 100 noteblocks"); stopProcessing = true; break; } } - + if (currentActionBlock.length > 0) { - addNewActionBlock(true); + addNewActionBlock(true); } - + trackCount++; // console.log("current action block: ", currentActionBlock); // console.log("current json: ", jsONON); @@ -4539,11 +4599,11 @@ class Activity { // console.debug('finished when you see: "block loading finished "'); document.body.style.cursor = "wait"; }); - + let len = jsONON.length; let m = 0; let actionIndex = 0; - + for (let i = 0; i < trackCount; i++) { let vspaceIndex=len+m+6; let startIndex=len+m; @@ -4604,12 +4664,12 @@ class Activity { m+=2; } - + this.blocks.loadNewBlocks(jsONON); // this.textMsg("MIDI import is not currently precise. Consider changing the speed with the Beats Per Minute block or modifying note value with the Multiply Note Value block"); return null; }; - + /** * Loads MB project from Planet. * @param projectID {Planet project ID} @@ -4789,7 +4849,7 @@ class Activity { note = note.replace(',', ''); return noteToCompare.toLowerCase() === note.toLowerCase(); }); - + if (accidental) { return note + (accidental.acc === "sharp" ? "♯" : (accidental.acc === "flat" ? "♭" : "")); } else { @@ -4799,21 +4859,21 @@ class Activity { // When converting to pitch value from ABC to MB there is issue // with the octave conversion. We map the pitch to audible pitch. function _abcToStandardValue(pitchValue) { - const octave = Math.floor(pitchValue/ 7) + 4; + const octave = Math.floor(pitchValue/ 7) + 4; return octave; } // Creates pitch which consist of note pitch notename you could // see them in the function. function _createPitchBlocks(pitches, blockId, pitchDuration,keySignature,actionBlock,triplet,meterDen) { const blocks = []; - + const pitch = pitches; - pitchDuration = toFraction(pitchDuration); + pitchDuration = toFraction(pitchDuration); const adjustedNote = _adjustPitch(pitch.name , keySignature).toUpperCase(); if (triplet !== undefined && triplet !== null){ pitchDuration[1] = meterDen * triplet } - + actionBlock.push( [blockId, ["newnote", {"collapsed": true}], 0, 0, [blockId - 1, blockId + 1, blockId + 4, blockId + 8]], [blockId + 1, "divide", 0, 0, [blockId, blockId + 2, blockId + 3]], @@ -4867,7 +4927,7 @@ class Activity { organizeBlock[staffIndex] = { arrangedBlocks:[] }; - + } organizeBlock[staffIndex].arrangedBlocks.push(staff) @@ -4906,7 +4966,7 @@ class Activity { nameddoArray:{}, }; - // For adding 17 blocks above + // For adding 17 blocks above blockId += 17 } @@ -4914,11 +4974,11 @@ class Activity { staff.voices.forEach(voice => { voice.forEach(element => { if (element.el_type === "note") { - //check if triplet exists + //check if triplet exists if (element?.startTriplet !== null&&element?.startTriplet !== undefined) { tripletFinder = element.startTriplet; } - + // Check and set tripletFinder to null // if element?.endTriplets exists. _createPitchBlocks(element.pitches[0], blockId,element.duration,staff.key,actionBlock,tripletFinder,staffBlocksMap[lineId].meterDen); @@ -4936,17 +4996,17 @@ class Activity { if (endBlockSearch[repeatbar].end === -1) { staffBlocksMap[lineId].repeatArray[repeatbar].end = staffBlocksMap[lineId].baseBlocks.length; } - } + } } } }); - + // Update the newnote connection with hidden actionBlock[0][4][0] = blockId + 3; actionBlock[actionBlock.length-1][4][1] = null; - + // Update the namedo block if not first // nameddo block appear if (staffBlocksMap[lineId].baseBlocks.length != 0) { @@ -4992,16 +5052,16 @@ class Activity { [blockId + 1, actionBlock[0][0]] ] ); // blockid of topaction block - + if (!staffBlocksMap[lineId].nameddoArray) { staffBlocksMap[lineId].nameddoArray = {}; } - + // Ensure the array at nameddoArray[lineId] is initialized if it doesn't exist if (!staffBlocksMap[lineId].nameddoArray[lineId]) { staffBlocksMap[lineId].nameddoArray[lineId] = []; } - + staffBlocksMap[lineId].nameddoArray[lineId].push(blockId); blockId += 4; @@ -5010,9 +5070,9 @@ class Activity { }); }); } - + let finalBlock = []; - // Some Error are here need to be fixed + // Some Error are here need to be fixed for (const staffIndex in staffBlocksMap) { staffBlocksMap[staffIndex].startBlock[staffBlocksMap[staffIndex].startBlock.length - 3][4][2] = staffBlocksMap[staffIndex].baseBlocks[0][0][staffBlocksMap[staffIndex].baseBlocks[0][0].length - 4][0]; // Update the first namedo block with settimbre @@ -5037,7 +5097,7 @@ class Activity { // exists and has a [0] element if (staffBlocksMap[staffIndex].baseBlocks[repeatId.end + 1] && staffBlocksMap[staffIndex].baseBlocks[repeatId.end + 1][0]) { let secondnammedo = _searchIndexForMusicBlock( - staffBlocksMap[staffIndex].baseBlocks[repeatId.end + 1][0], + staffBlocksMap[staffIndex].baseBlocks[repeatId.end + 1][0], staffBlocksMap[staffIndex].nameddoArray[staffIndex][repeatId.end + 1] ); @@ -5062,7 +5122,7 @@ class Activity { // Needs null checking optmizie let nextBlockId = staffBlocksMap[staffIndex].nameddoArray[staffIndex][repeatId.end+1]; - + staffBlocksMap[staffIndex].repeatBlock.push( [blockId,"repeat",0,0,[staffBlocksMap[staffIndex].baseBlocks[repeatId.start][0][currentnammeddo][4][0],blockId+1, currentBlockId,nextBlockId === null ? null : nextBlockId]] ); @@ -5090,11 +5150,11 @@ class Activity { // Flatten the multidimensional array let flattenedLineBlock = lineBlock.flat(); let combinedBlock = [...staffBlocksMap[staffIndex].startBlock, ...flattenedLineBlock]; - + finalBlock.push(...staffBlocksMap[staffIndex].startBlock); finalBlock.push(...flattenedLineBlock); finalBlock.push(...staffBlocksMap[staffIndex].repeatBlock); - + } this.blocks.loadNewBlocks(finalBlock); return null; @@ -5948,75 +6008,75 @@ class Activity { ); this.boundary.hide(); - if (!this.helpfulWheelItems.find(ele => ele.label === "Home [HOME]")) + if (!this.helpfulWheelItems.find(ele => ele.label === "Home [HOME]")) this.helpfulWheelItems.push({label: "Home [HOME]", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(GOHOMEFADEDBUTTON)), display: true, fn: findBlocks}); this.hideBlocksContainer = createButton(SHOWBLOCKSBUTTON, _("Show/hide blocks"), changeBlockVisibility); - if (!this.helpfulWheelItems.find(ele => ele.label === "Show/hide blocks")) + if (!this.helpfulWheelItems.find(ele => ele.label === "Show/hide blocks")) this.helpfulWheelItems.push({label: "Show/hide blocks", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(SHOWBLOCKSBUTTON)), display: true, fn: changeBlockVisibility}); - + this.collapseBlocksContainer = createButton(COLLAPSEBLOCKSBUTTON, _("Expand/collapse blocks"), toggleCollapsibleStacks); - if (!this.helpfulWheelItems.find(ele => ele.label === "Expand/collapse blocks")) + if (!this.helpfulWheelItems.find(ele => ele.label === "Expand/collapse blocks")) this.helpfulWheelItems.push({label: "Expand/collapse blocks", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(COLLAPSEBLOCKSBUTTON)), display: true, fn: toggleCollapsibleStacks}); - + this.smallerContainer = createButton(SMALLERBUTTON, _("Decrease block size"), doSmallerBlocks); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Decrease block size")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Decrease block size")) this.helpfulWheelItems.push({label: "Decrease block size", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(SMALLERBUTTON)), display: true, fn: doSmallerBlocks}); - + this.largerContainer = createButton(BIGGERBUTTON, _("Increase block size"), doLargerBlocks); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Increase block size")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Increase block size")) this.helpfulWheelItems.push({label: "Increase block size", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(BIGGERBUTTON)), display: true, fn: doLargerBlocks}); if (!this.helpfulWheelItems.find(ele => ele.label === "Restore")) this.helpfulWheelItems.push({label: "Restore", icon: "imgsrc:header-icons/restore-from-trash.svg", display: true, fn: restoreTrashPop}); - + if (!this.helpfulWheelItems.find(ele => ele.label === "Turtle Wrap Off")) this.helpfulWheelItems.push({label: "Turtle Wrap Off", icon: "imgsrc:header-icons/wrap-text.svg", display: true, fn: this.toolbar.changeWrap}); if (!this.helpfulWheelItems.find(ele => ele.label === "Turtle Wrap On")) this.helpfulWheelItems.push({label: "Turtle Wrap On", icon: "imgsrc:header-icons/wrap-text.svg", display: false, fn: this.toolbar.changeWrap}); - if (!this.helpfulWheelItems.find(ele => ele.label === "Enable horizontal scrolling")) + if (!this.helpfulWheelItems.find(ele => ele.label === "Enable horizontal scrolling")) this.helpfulWheelItems.push({label: "Enable horizontal scrolling", icon: "imgsrc:header-icons/compare-arrows.svg", display: this.beginnerMode ? false: true, fn: setScroller}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Disable horizontal scrolling")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Disable horizontal scrolling")) this.helpfulWheelItems.push({label: "Disable horizontal scrolling", icon: "imgsrc:header-icons/lock.svg", display: false, fn: setScroller}); - - if (_THIS_IS_MUSIC_BLOCKS_ && !this.helpfulWheelItems.find(ele => ele.label === "Set Pitch Preview")) + + if (_THIS_IS_MUSIC_BLOCKS_ && !this.helpfulWheelItems.find(ele => ele.label === "Set Pitch Preview")) this.helpfulWheelItems.push({label: "Set Pitch Preview", icon: "imgsrc:header-icons/music-note.svg", display: true, fn: chooseKeyMenu}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Grid")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Grid")) this.helpfulWheelItems.push({label: "Grid", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(CARTESIANBUTTON)), display: true, fn: piemenuGrid}); - if (!this.helpfulWheelItems.find(ele => ele.label === "Select")) + if (!this.helpfulWheelItems.find(ele => ele.label === "Select")) this.helpfulWheelItems.push({label: "Select", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(SELECTBUTTON)), display: true, fn: this.selectMode }); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Clear")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Clear")) this.helpfulWheelItems.push({label: "Clear", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(CLEARBUTTON)), display: true, fn: () => this._allClear(false)}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Collapse")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Collapse")) this.helpfulWheelItems.push({label: "Collapse", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(COLLAPSEBUTTON)), display: true, fn: this.turtles.collapse}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Expand")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Expand")) this.helpfulWheelItems.push({label: "Expand", icon: "imgsrc:data:image/svg+xml;base64," + window.btoa(base64Encode(EXPANDBUTTON)), display: false, fn: this.turtles.expand}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Search for Blocks")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Search for Blocks")) this.helpfulWheelItems.push({label: "Search for Blocks", icon: "imgsrc:header-icons/search-button.svg", display: true, fn: this._displayHelpfulSearchDiv}); - - if (!this.helpfulWheelItems.find(ele => ele.label === "Paste previous stack")) + + if (!this.helpfulWheelItems.find(ele => ele.label === "Paste previous stack")) this.helpfulWheelItems.push({label: "Paste previous stack", icon: "imgsrc:header-icons/copy-button.svg", display: false, fn: this.turtles.expand}); if(!this.helpfulWheelItems.find(ele => ele.label=== "Close")) this.helpfulWheelItems.push({label: "Close", icon: "imgsrc:header-icons/cancel-button.svg", display: true, fn: this._hideHelpfulSearchWidget}); - + }; /* @@ -6359,7 +6419,7 @@ class Activity { this.unhighlightSelectedBlocks(false); this.setSelectionMode(false); } - + // end the drag on navbar document.getElementById("toolbars").addEventListener("mouseover", () => {this.isDragging = false;}); @@ -6379,7 +6439,7 @@ class Activity { this.hasMouseMoved = false; this.selectionArea = document.createElement("div"); document.body.appendChild(this.selectionArea); - + this.setupMouseEvents(); document.addEventListener("mousemove", (event) => { @@ -6395,7 +6455,7 @@ class Activity { this.selectedBlocks = this.selectBlocksInDragArea(); this.unhighlightSelectedBlocks(true, true); this.blocks.setSelectedBlocks(this.selectedBlocks); - } + } } }) @@ -6412,7 +6472,7 @@ class Activity { this.hasMouseMoved = false; }, 100); }) - + }; // Set starting points of the drag @@ -6468,7 +6528,7 @@ class Activity { height: block.height, width: block.width }; - + if (this.rectanglesOverlap(this.blockRect, this.dragRect)){ selectedBlocks.push(block); } @@ -6748,13 +6808,13 @@ class Activity { // Read file here. const reader = new FileReader(); const midiReader = new FileReader(); - + // eslint-disable-next-line no-unused-vars reader.onload = (theFile) => { that.loading = true; document.body.style.cursor = "wait"; that.doLoadAnimation(); - + setTimeout(() => { const rawData = reader.result; if (rawData === null || rawData === "") { @@ -6776,9 +6836,9 @@ class Activity { for (const name in that.palettes.dict) { that.palettes.dict[name].hideMenu(true); } - + that.stage.removeAllEventListeners("trashsignal"); - + if (!that.merging) { // Wait for the old blocks to be removed. // eslint-disable-next-line no-unused-vars @@ -6789,7 +6849,7 @@ class Activity { that.planet.saveLocally(); } }; - + that.stage.addEventListener("trashsignal", __listener, false); that.sendAllToTrash(false, false); that._allClear(false, true); @@ -6806,7 +6866,7 @@ class Activity { that.merging = false; that.blocks.loadNewBlocks(obj); } - + that.loading = false; that.refreshCanvas(); } catch (e) { @@ -6823,13 +6883,14 @@ class Activity { } }, 200); }; - + midiReader.onload = (e) => { const midi = new Midi(e.target.result); + // eslint-disable-next-line no-console console.debug(midi); this.transcribeMidi(midi); }; - + const file = that.fileChooser.files[0]; if (file) { const extension = file.name.split('.').pop().toLowerCase(); @@ -6843,7 +6904,7 @@ class Activity { }, false ); - + const __handleFileSelect = (event) => { event.stopPropagation(); @@ -6874,7 +6935,7 @@ class Activity { obj = JSON.parse( cleanData.match('
(.+?)
')[1] ); - } + } else { obj = JSON.parse(cleanData); } @@ -6925,6 +6986,7 @@ class Activity { }; midiReader.onload = (e) => { const midi = new Midi(e.target.result) + // eslint-disable-next-line no-console console.debug(midi); this.transcribeMidi(midi); } @@ -6934,17 +6996,17 @@ class Activity { //get the abc data and replace the / so that the block does not break let abcData = event.target.result; abcData = abcData.replace(/\\/g, ''); - + const tunebook = new ABCJS.parseOnly(abcData); - + // eslint-disable-next-line no-console console.log(tunebook) tunebook.forEach(tune => { //call parseABC to parse abcdata to MB json this.parseABC(tune); - + }); - - + + }; // Music Block Parser from abc to MB @@ -6952,17 +7014,17 @@ class Activity { //get the abc data and replace the / so that the block does not break let abcData = event.target.result; abcData = abcData.replace(/\\/g, ''); - + const tunebook = new ABCJS.parseOnly(abcData); - + // eslint-disable-next-line no-console console.log(tunebook) tunebook.forEach(tune => { //call parseABC to parse abcdata to MB json this.parseABC(tune); - + }); - - + + }; // Work-around in case the handler is called by the @@ -6979,7 +7041,6 @@ class Activity { let isABC = (extension == "abc"); if (isABC) { abcReader.readAsText(files[0]); - console.log('abc') return; } reader.readAsText(files[0]); @@ -7231,7 +7292,7 @@ class Activity { this.prepSearchWidget(); // create functionality of 2D drag to select blocks in bulk - + this._create2Ddrag(); /* @@ -7259,6 +7320,7 @@ class Activity { localStorage.setItem('beginnerMode', this.beginnerMode.toString()); localStorage.setItem('isDarkModeON', this.isDarkModeON.toString()); } catch (e) { + // eslint-disable-next-line no-console console.error('Error saving to localStorage:', e); } } @@ -7283,20 +7345,23 @@ class Activity { } } } - + // Safely hide and clear existing palettes if (!this.palettes) { + // eslint-disable-next-line no-console console.warn('Palettes object not initialized'); return; } - + if (typeof this.palettes.hide !== 'function') { + // eslint-disable-next-line no-console console.warn('Palettes hide method not available'); } else { this.palettes.hide(); } - + if (typeof this.palettes.clear !== 'function') { + // eslint-disable-next-line no-console console.warn('Palettes clear method not available'); // Fallback clear implementation this.palettes.dict = {}; @@ -7306,45 +7371,47 @@ class Activity { } else { this.palettes.clear(); } - + // Reinitialize palettes initPalettes(this.palettes); - + // Reinitialize blocks if (this.blocks) { initBasicProtoBlocks(this); } - + // Restore palette positions if (this.palettes && this.palettes.dict) { for (const name in palettePositions) { const palette = this.palettes.dict[name]; const pos = palettePositions[name]; - + if (palette && palette.container && pos) { palette.container.x = pos.x; palette.container.y = pos.y; - + if (pos.visible) { palette.showMenu(true); } } } } - + // Update the palette display if (this.palettes && typeof this.palettes.updatePalettes === 'function') { this.palettes.updatePalettes(); } - + // Update blocks if (this.blocks && typeof this.blocks.updateBlockPositions === 'function') { this.blocks.updateBlockPositions(); } - + + this.refreshCanvas(); - + } catch (e) { + // eslint-disable-next-line no-console console.error('Error regenerating palettes:', e); this.errorMsg(_('Error regenerating palettes. Please refresh the page.')); }