Skip to content

Commit 11cdfdc

Browse files
authored
Add "Copy to Clipboard" button (#4712)
1 parent 8056cdf commit 11cdfdc

File tree

1 file changed

+59
-36
lines changed

1 file changed

+59
-36
lines changed

js/SaveInterface.js

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class SaveInterface {
5757
this.htmlSaveTemplate =
5858
'<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="description" content="{{ project_description }}"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <title>{{ project_name }}</title> <meta property="og:site_name" content="Music Blocks"/> <meta property="og:type" content="website"/> <meta property="og:title" content="' +
5959
_("Music Blocks Project") +
60-
' - {{ project_name }}"/> <meta property="og:description" content="{{ project_description }}"/> <style>body{background-color: #dbf0fb;}#main{background-color: white; padding: 5%; position: fixed; width: 80vw; height: max-content; margin: auto; top: 0; left: 0; bottom: 0; right: 0; display: flex; flex-direction: column; justify-content: center; text-align: center; color: #424242; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); font-family: "Roboto", "Helvetica","Arial",sans-serif;}h3{font-weight: 400; font-size: 36px; margin-top: 10px;}hr{border-top: 0px solid #ccc; margin: 1em;}.btn{border: solid; border-color: #96D3F3; padding: 5px 10px; line-height: 50px; color: #0a3e58;}.btn:hover{transition: 0.4s; -webkit-transition: 0.3s; -moz-transition: 0.3s; background-color: #96D3F3;}.code{word-break: break-all; height: 15vh; background: #f6f8fa; color: #494949; text-align: justify; margin-right: 10vw; margin-left: 10vw; padding: 16px; overflow: auto; line-height: 1.45; background-color: #f6f8fa; border-radius: 3px; font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;}.image{border-radius: 2px 2px 0 0; position: relative; background-color: #96D3F3;}.image-div{margin-bottom: 10px;}.moreinfo-div{margin-top: 20px;}h4{font-weight: 500; font-size: 1.4em; margin-top: 10px; margin-bottom: 10px;}.tbcode{margin-bottom: 10px;}</style></head><body> <div id="main"> <div class="image-div"><img class="image" id="project-image" src="{{ project_image }}"></div><h3 id="title">' +
60+
' - {{ project_name }}"/> <meta property="og:description" content="{{ project_description }}"/> <style>body{background-color: #dbf0fb;}#main{background-color: white; padding: 5%; position: fixed; width: 80vw; height: max-content; margin: auto; top: 0; left: 0; bottom: 0; right: 0; display: flex; flex-direction: column; justify-content: center; text-align: center; color: #424242; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); font-family: "Roboto", "Helvetica","Arial",sans-serif;}h3{font-weight: 400; font-size: 36px; margin-top: 10px;}hr{border-top: 0px solid #ccc; margin: 1em;}.btn {display: inline-block; margin-left: 10px; cursor: pointer; font-size: 14px; border-radius: 12px; border: 1px solid #1678ad; padding: 3px 5px; line-height: 20px; color: #181818;}.btn:hover {transition: 0.4s; -webkit-transition: 0.3s; -moz-transition: 0.3s; background-color: #3eb7e7;}.code{word-break: break-all; height: 15vh; background: #f6f8fa; color: #494949; text-align: justify; margin-right: 10vw; margin-left: 10vw; padding: 16px; overflow: auto; line-height: 1.45; background-color: #f6f8fa; border-radius: 3px; font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;}.image{border-radius: 2px 2px 0 0; position: relative; background-color: #96D3F3;}.image-div{margin-bottom: 10px;}.moreinfo-div{margin-top: 20px;}h4{font-weight: 500; font-size: 1.4em; margin-top: 10px; margin-bottom: 10px;}.tbcode{margin-bottom: 10px;}</style></head><body> <div id="main"> <div class="image-div"><img class="image" id="project-image" src="{{ project_image }}"></div><h3 id="title">' +
6161
_("Music Blocks Project") +
6262
' - {{ project_name }}</h3> <p>{{ project_description }}</p><hr> <div> <div style="color: #9E9E9E"><p>' +
6363
_("This project was created in Music Blocks") +
@@ -85,17 +85,40 @@ class SaveInterface {
8585
_("Project Code") +
8686
"</h4>" +
8787
_("This code stores data about the blocks in a project.") +
88-
' <a href="javascript:toggle();" id="showhide">' +
88+
'<a href="javascript:toggle();" id="showhide">' +
8989
_("Show") +
90-
'</a></div> <div class="code">{{ data }}</div></div></div></div><script type="text/javascript">function toggle(){if (document.getElementsByClassName("code")[0].style.display=="none"){document.getElementsByClassName("code")[0].style.display="flex";document.getElementById("showhide").textContent = "' +
91-
_("Hide") +
92-
'";} else {document.getElementsByClassName("code")[0].style.display="none";document.getElementById("showhide").textContent = "Show";}} var name=decodeURIComponent(window.location.pathname.split("/").pop().slice(0, -5)); var prefix="' +
93-
_("Music Blocks Project") +
94-
' - "; var title=prefix+name; document.querySelector(' +
95-
"'" +
96-
'meta[property="og:title"]' +
97-
"'" +
98-
').content=title; document.title=name; document.getElementById("title").textContent=title; document.getElementsByClassName("code")[0].style.display = "none";</script></body></html>';
90+
"</a>" +
91+
'<button class="btn" onclick="copyCode()" style="margin-left: 10px;">' +
92+
_("Copy to Clipboard") +
93+
"</button>" +
94+
'</div> <div class="code" id="codeBlock">{{ data }}</div></div></div></div>' +
95+
'<script type="text/javascript">' +
96+
"function toggle() {" +
97+
' var codeBlock = document.getElementsByClassName("code")[0];' +
98+
' var showHideButton = document.getElementById("showhide");' +
99+
' if (codeBlock.style.display === "none") {' +
100+
' codeBlock.style.display = "flex";' +
101+
' showHideButton.textContent = "' + _("Hide") + '";' +
102+
" } else {" +
103+
' codeBlock.style.display = "none";' +
104+
' showHideButton.textContent = "' + _("Show") + '";' +
105+
" }" +
106+
"}" +
107+
"window.onload = function() {" +
108+
' var codeBlock = document.getElementById("codeBlock");' +
109+
' var showHideButton = document.getElementById("showhide");' +
110+
' codeBlock.style.display = "none";' +
111+
' showHideButton.textContent = "' + _("Show") + '";' +
112+
"};" +
113+
"function copyCode() {" +
114+
' var text = document.getElementById("codeBlock").innerText;' +
115+
" navigator.clipboard.writeText(text).then(function() {" +
116+
' alert("' + _("Project code copied to clipboard!") + '");' +
117+
" }).catch(function() {" +
118+
' alert("' + _("Failed to copy.") + '");' +
119+
" });" +
120+
"}" +
121+
"</script>";
99122

100123
this.timeLastSaved = -100;
101124
const $j = jQuery.noConflict();
@@ -118,12 +141,12 @@ class SaveInterface {
118141
}
119142

120143
/**
121-
* Download a file to the user's computer.
122-
* @param {string} extension - The file extension (including the dot).
123-
* @param {string} dataurl - The base64 data url of the file.
124-
* @param {string} defaultfilename - The default filename to be used.
125-
* @returns {void}
126-
*/
144+
* Download a file to the user's computer.
145+
* @param {string} extension - The file extension (including the dot).
146+
* @param {string} dataurl - The base64 data url of the file.
147+
* @param {string} defaultfilename - The default filename to be used.
148+
* @returns {void}
149+
*/
127150
download(extension, dataurl, defaultfilename) {
128151
let filename = null;
129152
if (defaultfilename === undefined || defaultfilename === null) {
@@ -304,7 +327,6 @@ class SaveInterface {
304327
midi.header.ticksPerBeat = 480;
305328

306329
Object.entries(data).forEach(([blockIndex, notes]) => {
307-
308330
const mainTrack = midi.addTrack();
309331
mainTrack.name = `Track ${parseInt(blockIndex) + 1}`;
310332

@@ -332,21 +354,22 @@ class SaveInterface {
332354
midi: midiNumber,
333355
time: globalTime,
334356
duration: duration,
335-
velocity: 0.9,
357+
velocity: 0.9
336358
});
337-
338359
} else {
339360
if (!trackMap.has(instrument)) {
340361
const instrumentTrack = midi.addTrack();
341-
instrumentTrack.name = `Track ${parseInt(blockIndex) + 1} - ${instrument}`;
342-
instrumentTrack.instrument.number = instrumentMIDI[instrument] ?? instrumentMIDI["default"];
362+
instrumentTrack.name = `Track ${
363+
parseInt(blockIndex) + 1
364+
} - ${instrument}`;
365+
instrumentTrack.instrument.number =
366+
instrumentMIDI[instrument] ?? instrumentMIDI["default"];
343367
trackMap.set(instrument, instrumentTrack);
344368
}
345369

346370
const instrumentTrack = trackMap.get(instrument);
347371

348372
noteData.note.forEach((pitch) => {
349-
350373
if (!pitch.includes("R")) {
351374
instrumentTrack.addNote({
352375
name: normalizeNote(pitch),
@@ -400,7 +423,7 @@ class SaveInterface {
400423

401424
/**
402425
* This method is to save PNG representation of an activity
403-
*
426+
*
404427
* @param {SaveInterface} activity -The activity object to save
405428
* @returns {void}
406429
* @method
@@ -413,7 +436,7 @@ class SaveInterface {
413436

414437
/**
415438
* This method is to save BlockArtwork and download the SVG representation of block artwork from the provided activity.
416-
*
439+
*
417440
* @param {SaveInterface} activity - The activity object containing block artwork to save.
418441
* @returns {void}
419442
* @method
@@ -426,7 +449,7 @@ class SaveInterface {
426449

427450
/**
428451
* This method is to save BlockArtwork and download the PNG representation of block artwork from the provided activity.
429-
*
452+
*
430453
* @param {SaveInterface} activity - The activity object containing block artwork to save.
431454
* @returns {void}
432455
* @method
@@ -439,16 +462,16 @@ class SaveInterface {
439462
}
440463

441464
/**
442-
* Save audio recording in WAV format.
443-
*
444-
* This method initiates the process of recording audio in WAV format within the provided activity.
445-
*
446-
* @param {SaveInterface} activity - The activity object for which audio recording is to be saved.
447-
* @returns {void}
448-
* @memberof SaveInterface
449-
* @method
450-
* @instance
451-
*/
465+
* Save audio recording in WAV format.
466+
*
467+
* This method initiates the process of recording audio in WAV format within the provided activity.
468+
*
469+
* @param {SaveInterface} activity - The activity object for which audio recording is to be saved.
470+
* @returns {void}
471+
* @memberof SaveInterface
472+
* @method
473+
* @instance
474+
*/
452475
saveWAV(activity) {
453476
document.body.style.cursor = "wait";
454477
activity.logo.recording = true;

0 commit comments

Comments
 (0)