From 0aff3c5afb19751db3daeb724032085b78d1a1a3 Mon Sep 17 00:00:00 2001 From: Suryaansh Chawla Date: Sun, 29 Dec 2024 01:36:00 +0530 Subject: [PATCH 01/19] add onResize refresh to play-button (#4198) --- js/activity.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/activity.js b/js/activity.js index 16fe737606..892fff5568 100644 --- a/js/activity.js +++ b/js/activity.js @@ -1160,6 +1160,7 @@ class Activity { }; this._doFastButton = (env) => { + this._onResize(); this.blocks.activeBlock = null; hideDOMLabel(); From 873fdf81def81c93c5665f31bd7451a23190cf48 Mon Sep 17 00:00:00 2001 From: Muhammad Haroon <104259212+haroon10725@users.noreply.github.com> Date: Sun, 29 Dec 2024 20:52:01 +0500 Subject: [PATCH 02/19] fix pitch octave limit to valid range (#4204) --- js/block.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/block.js b/js/block.js index 3b87ee5903..6420103b6b 100644 --- a/js/block.js +++ b/js/block.js @@ -4396,9 +4396,9 @@ class Block { this.value = oldValue; } - if(cblk1 != null && this.blocks.blockList[cblk1].name === "pitch" && (this.value > 10 || this.value < 1)) { + if(cblk1 != null && this.blocks.blockList[cblk1].name === "pitch" && (this.value > 8 || this.value < 1)) { const thisBlock = this.blocks.blockList.indexOf(this); - this.activity.errorMsg(_("Octave value must be between 1 and 10."), thisBlock); + this.activity.errorMsg(_("Octave value must be between 1 and 8."), thisBlock); this.activity.refreshCanvas(); this.label.value = oldValue; this.value = oldValue; From 2a08d519c5f21df809a9fb18d6efed4fa913fd3f Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Sun, 29 Dec 2024 11:02:25 -0500 Subject: [PATCH 03/19] set limit to 8 for octave value (#4206) Co-authored-by: Walter Bender --- localization.ini | 8 ++++---- po/MusicBlocks.pot | 2 +- po/af.po | 2 +- po/agr.po | 2 +- po/am.po | 2 +- po/ar.po | 2 +- po/ayc.po | 2 +- po/bg.po | 2 +- po/bi.po | 2 +- po/bn.po | 2 +- po/br.po | 2 +- po/ca.po | 2 +- po/cs.po | 2 +- po/da.po | 2 +- po/de.po | 2 +- po/dz.po | 2 +- po/el.po | 2 +- po/en.po | 2 +- po/en_GB.po | 2 +- po/es.po | 4 ++-- po/fa.po | 2 +- po/ff.po | 2 +- po/fi.po | 2 +- po/fil.po | 2 +- po/fr.po | 2 +- po/gn.po | 2 +- po/gug.po | 2 +- po/ha.po | 2 +- po/he.po | 4 ++-- po/hi.po | 2 +- po/ht.po | 2 +- po/hu.po | 2 +- po/hus.po | 2 +- po/hy.po | 2 +- po/ibo.po | 2 +- po/id.po | 2 +- po/is.po | 2 +- po/it.po | 4 ++-- po/ja-kana.po | 2 +- po/ja.po | 4 ++-- po/km.po | 2 +- po/kn.po | 2 +- po/ko.po | 2 +- po/kos.po | 2 +- po/mg.po | 2 +- po/mi.po | 2 +- po/mk.po | 2 +- po/ml.po | 2 +- po/mn.po | 2 +- po/mr.po | 2 +- po/ms.po | 2 +- po/mvo.po | 2 +- po/nb.po | 2 +- po/ne.po | 2 +- po/nl.po | 2 +- po/pa.po | 2 +- po/pap.po | 2 +- po/pbs.po | 2 +- po/pl.po | 2 +- po/pt.po | 2 +- po/quz.po | 2 +- po/ro.po | 2 +- po/ru.po | 2 +- po/rw.po | 2 +- po/sd.po | 2 +- po/si.po | 2 +- po/sk.po | 2 +- po/sl.po | 2 +- po/sq.po | 2 +- po/sv.po | 2 +- po/sw.po | 2 +- po/ta.po | 2 +- po/te.po | 2 +- po/th.po | 2 +- po/tr.po | 2 +- po/tvl.po | 2 +- po/tzo.po | 2 +- po/ug.po | 2 +- po/ur.po | 2 +- po/vi.po | 2 +- po/wa.po | 2 +- po/yo.po | 2 +- po/zh_CN.po | 2 +- po/zh_TW.po | 2 +- 84 files changed, 91 insertions(+), 91 deletions(-) diff --git a/localization.ini b/localization.ini index d7c585ddf1..be774d5805 100644 --- a/localization.ini +++ b/localization.ini @@ -2005,7 +2005,7 @@ bass = bass on2 = encendido off = apagado Not-a-number = no es un número -Octave-value-must-be-between-1-and-10 = El bloqueo de silencio no se puede eliminar. +Octave-value-must-be-between-1-and-8 = El valor de octava debe estar entre 1 y 8. Numbers-can-have-at-most-10-digits = El bloqueo de silencio no se puede eliminar. box = caja Consider-breaking-this-stack-into-parts = Considera dividir esta pila en partes. @@ -3961,7 +3961,7 @@ bass = בַּס on2 = עַל off = כבוי Not-a-number = לא מספר -Octave-value-must-be-between-1-and-10 = ערך האוקטבה חייב להיות בין 1 ל-10. +Octave-value-must-be-between-1-and-8 = ערך האוקטבה חייב להיות בין 1 ל-8. Numbers-can-have-at-most-10-digits = מספרים יכולים להכיל 10 ספרות לכל היותר. box = תיבה Consider-breaking-this-stack-into-parts = שקול לפרק את הערימה הזו לחלקים. @@ -6068,7 +6068,7 @@ alto = alto tenor = tenore bass = basso Not-a-number = Non un numero -Octave-value-must-be-between-1-and-10 = Il valore dell'ottava deve essere compreso tra 1 e 10 +Octave-value-must-be-between-1-and-8 = Il valore dell'ottava deve essere compreso tra 1 e 8 Numbers-can-have-at-most-10-digits = I numeri possono avere al massimo 10 cifre box = scatola open-file = aprire file @@ -11757,7 +11757,7 @@ bass = コントラバス on2 = オン off = オフ Not-a-number = 数字ではありません -Octave-value-must-be-between-1-and-10 = オクターヴの値が「1」から「10」までの範囲でなければなりません。 +Octave-value-must-be-between-1-and-8 = オクターヴの値が「1」から「8」までの範囲でなければなりません。 Numbers-can-have-at-most-10-digits = 数字は最大10桁までです。 box = 箱 Consider-breaking-this-stack-into-parts = アクションブロックを使ってプログラムをまとめませんか diff --git a/po/MusicBlocks.pot b/po/MusicBlocks.pot index e1efc780f4..fd5333a8e0 100644 --- a/po/MusicBlocks.pot +++ b/po/MusicBlocks.pot @@ -978,7 +978,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/af.po b/po/af.po index 6c48bd0dd1..7109757f1a 100644 --- a/po/af.po +++ b/po/af.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/agr.po b/po/agr.po index 526ca39cf2..906756c654 100644 --- a/po/agr.po +++ b/po/agr.po @@ -3101,7 +3101,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/am.po b/po/am.po index 48fdb61e39..d49c03e752 100644 --- a/po/am.po +++ b/po/am.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ar.po b/po/ar.po index f9337a9404..c7468c0b16 100644 --- a/po/ar.po +++ b/po/ar.po @@ -991,7 +991,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ayc.po b/po/ayc.po index 960ada9cb2..ebed2624a6 100644 --- a/po/ayc.po +++ b/po/ayc.po @@ -1140,7 +1140,7 @@ msgstr "" #: js/block.js:4401 #.TRANS: El bloqueo de silencio no se puede eliminar. -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/bg.po b/po/bg.po index fe36a5bdf4..854a32ec77 100644 --- a/po/bg.po +++ b/po/bg.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/bi.po b/po/bi.po index fc18845833..e7ec472080 100644 --- a/po/bi.po +++ b/po/bi.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/bn.po b/po/bn.po index 1d3684fe9c..114d4576eb 100644 --- a/po/bn.po +++ b/po/bn.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/br.po b/po/br.po index b013c62c89..dc906c139d 100644 --- a/po/br.po +++ b/po/br.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ca.po b/po/ca.po index 389c74d537..1b51169b8b 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/cs.po b/po/cs.po index be5c053fc9..4f680779e3 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/da.po b/po/da.po index 00d5003e55..f61e513152 100644 --- a/po/da.po +++ b/po/da.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/de.po b/po/de.po index e520134452..f85c0481a3 100644 --- a/po/de.po +++ b/po/de.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/dz.po b/po/dz.po index 1a3efef56f..c14f2073cc 100644 --- a/po/dz.po +++ b/po/dz.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/el.po b/po/el.po index ed3b35a1b4..3109102f45 100644 --- a/po/el.po +++ b/po/el.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/en.po b/po/en.po index faf9d0db1a..79a94168a1 100644 --- a/po/en.po +++ b/po/en.po @@ -3108,7 +3108,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/en_GB.po b/po/en_GB.po index fb71203472..1934d7034e 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -1658,7 +1658,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/es.po b/po/es.po index b87b96fda7..4cace16dbb 100644 --- a/po/es.po +++ b/po/es.po @@ -997,8 +997,8 @@ msgid "Not a number" msgstr "no es un número" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." -msgstr "El bloqueo de silencio no se puede eliminar." +msgid "Octave value must be between 1 and 8." +msgstr "El valor de octava debe estar entre 1 y 8." #: js/block.js:4409 msgid "Numbers can have at most 10 digits." diff --git a/po/fa.po b/po/fa.po index 992755a585..43b394af7f 100644 --- a/po/fa.po +++ b/po/fa.po @@ -3102,7 +3102,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ff.po b/po/ff.po index 0e95ffb204..0defe4ee25 100644 --- a/po/ff.po +++ b/po/ff.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/fi.po b/po/fi.po index 2be12b0365..607afccdeb 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/fil.po b/po/fil.po index 88c1614eb8..15d90444f7 100644 --- a/po/fil.po +++ b/po/fil.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/fr.po b/po/fr.po index 62ce2dd2e6..060354bd47 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3105,7 +3105,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/gn.po b/po/gn.po index df8e98f2b0..d9fc1b8dd2 100644 --- a/po/gn.po +++ b/po/gn.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/gug.po b/po/gug.po index 607c346924..8134d00f43 100644 --- a/po/gug.po +++ b/po/gug.po @@ -1145,7 +1145,7 @@ msgstr "" #: js/block.js:4401 #.TRANS: El bloqueo de silencio no se puede eliminar. -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ha.po b/po/ha.po index 09ff5c85dd..4eff95c456 100644 --- a/po/ha.po +++ b/po/ha.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/he.po b/po/he.po index 4133cf7184..5f9548f4fb 100644 --- a/po/he.po +++ b/po/he.po @@ -987,8 +987,8 @@ msgid "Not a number" msgstr "לא מספר" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." -msgstr "ערך האוקטבה חייב להיות בין 1 ל-10." +msgid "Octave value must be between 1 and 8." +msgstr "ערך האוקטבה חייב להיות בין 1 ל-8." #: js/block.js:4409 msgid "Numbers can have at most 10 digits." diff --git a/po/hi.po b/po/hi.po index c4ce9466e7..1db9815bb7 100644 --- a/po/hi.po +++ b/po/hi.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "एक संख्या नहीं" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ht.po b/po/ht.po index fe36a5bdf4..854a32ec77 100644 --- a/po/ht.po +++ b/po/ht.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/hu.po b/po/hu.po index fe36a5bdf4..854a32ec77 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/hus.po b/po/hus.po index 5f832f0d42..269480f44f 100644 --- a/po/hus.po +++ b/po/hus.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/hy.po b/po/hy.po index 2ffaacbf70..f10f58f771 100644 --- a/po/hy.po +++ b/po/hy.po @@ -3101,7 +3101,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ibo.po b/po/ibo.po index ef59287d1c..4eef28084c 100644 --- a/po/ibo.po +++ b/po/ibo.po @@ -992,7 +992,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/id.po b/po/id.po index 05f7812103..4087dc4d30 100644 --- a/po/id.po +++ b/po/id.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/is.po b/po/is.po index 4a41e49918..13d500407a 100644 --- a/po/is.po +++ b/po/is.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/it.po b/po/it.po index ff5df3c93f..939c08aff5 100644 --- a/po/it.po +++ b/po/it.po @@ -3104,8 +3104,8 @@ msgid "Not a number" msgstr "Non un numero" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." -msgstr "Il valore dell'ottava deve essere compreso tra 1 e 10" +msgid "Octave value must be between 1 and 8." +msgstr "Il valore dell'ottava deve essere compreso tra 1 e 8" #: js/block.js:4409 msgid "Numbers can have at most 10 digits." diff --git a/po/ja-kana.po b/po/ja-kana.po index 6739dc8b4d..f282d84c14 100644 --- a/po/ja-kana.po +++ b/po/ja-kana.po @@ -989,7 +989,7 @@ msgid "Not a number" msgstr "すうじではありません" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ja.po b/po/ja.po index 7121cd3bca..46bde23ce7 100644 --- a/po/ja.po +++ b/po/ja.po @@ -991,8 +991,8 @@ msgid "Not a number" msgstr "数字ではありません" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." -msgstr "オクターヴの値が「1」から「10」までの範囲でなければなりません。" +msgid "Octave value must be between 1 and 8." +msgstr "オクターヴの値が「1」から「8」までの範囲でなければなりません。" #: js/block.js:4409 msgid "Numbers can have at most 10 digits." diff --git a/po/km.po b/po/km.po index eea49fe222..a6119e05c8 100644 --- a/po/km.po +++ b/po/km.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/kn.po b/po/kn.po index ca21f142d1..18d4e9bc97 100644 --- a/po/kn.po +++ b/po/kn.po @@ -3101,7 +3101,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ko.po b/po/ko.po index c1a77f97c0..5170f0c622 100644 --- a/po/ko.po +++ b/po/ko.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/kos.po b/po/kos.po index 7b137564c0..e0ef5c683d 100644 --- a/po/kos.po +++ b/po/kos.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mg.po b/po/mg.po index 4642cc0047..82c8e30b4e 100644 --- a/po/mg.po +++ b/po/mg.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mi.po b/po/mi.po index 382fc45829..b709c902db 100644 --- a/po/mi.po +++ b/po/mi.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mk.po b/po/mk.po index 66b0c30285..dc17e29e72 100644 --- a/po/mk.po +++ b/po/mk.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ml.po b/po/ml.po index 616c4d5e16..f8f0245c5c 100644 --- a/po/ml.po +++ b/po/ml.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mn.po b/po/mn.po index 065b6e0320..384823aca8 100644 --- a/po/mn.po +++ b/po/mn.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mr.po b/po/mr.po index 323ae6cfd6..b7b6261f81 100644 --- a/po/mr.po +++ b/po/mr.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ms.po b/po/ms.po index fe36a5bdf4..854a32ec77 100644 --- a/po/ms.po +++ b/po/ms.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/mvo.po b/po/mvo.po index 517f64d9af..d996641d23 100644 --- a/po/mvo.po +++ b/po/mvo.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/nb.po b/po/nb.po index bf31354fcc..1b15c09535 100644 --- a/po/nb.po +++ b/po/nb.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ne.po b/po/ne.po index f516cf04d6..7997959094 100644 --- a/po/ne.po +++ b/po/ne.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/nl.po b/po/nl.po index 2668fb641b..c2a35b2338 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3102,7 +3102,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/pa.po b/po/pa.po index 480d94cf6e..ad993be0c6 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/pap.po b/po/pap.po index 13ee709178..c3bc4efe4a 100644 --- a/po/pap.po +++ b/po/pap.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/pbs.po b/po/pbs.po index 0b9fdf59a7..7e62980593 100644 --- a/po/pbs.po +++ b/po/pbs.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/pl.po b/po/pl.po index b0bc3dc7cc..9ce157748d 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3105,7 +3105,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/pt.po b/po/pt.po index da022621b3..f4e8697b42 100644 --- a/po/pt.po +++ b/po/pt.po @@ -994,7 +994,7 @@ msgid "Not a number" msgstr "Não um número" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/quz.po b/po/quz.po index fb7485ca1e..e56b0072ca 100644 --- a/po/quz.po +++ b/po/quz.po @@ -1543,7 +1543,7 @@ msgstr "" #: js/block.js:4401 #.TRANS: El bloqueo de silencio no se puede eliminar. -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ro.po b/po/ro.po index 4d5c5a1165..067843d916 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3105,7 +3105,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ru.po b/po/ru.po index a1f94f09aa..419043525b 100644 --- a/po/ru.po +++ b/po/ru.po @@ -3105,7 +3105,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/rw.po b/po/rw.po index 0dc8be1ac7..f0085a18ad 100644 --- a/po/rw.po +++ b/po/rw.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sd.po b/po/sd.po index 479b7ac095..e0bcd709d0 100644 --- a/po/sd.po +++ b/po/sd.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/si.po b/po/si.po index 8f084d94ae..1be2432554 100644 --- a/po/si.po +++ b/po/si.po @@ -3107,7 +3107,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sk.po b/po/sk.po index 4484ea63ec..e7c2834f7a 100644 --- a/po/sk.po +++ b/po/sk.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sl.po b/po/sl.po index 40fcbf7f2b..16e9b7c076 100644 --- a/po/sl.po +++ b/po/sl.po @@ -3105,7 +3105,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sq.po b/po/sq.po index 2a788adf67..7d148c58ca 100644 --- a/po/sq.po +++ b/po/sq.po @@ -3101,7 +3101,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sv.po b/po/sv.po index f4a54aa261..94222b221f 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/sw.po b/po/sw.po index 57880c6e70..06df776a82 100644 --- a/po/sw.po +++ b/po/sw.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ta.po b/po/ta.po index 2aefc224b8..a204c2a528 100644 --- a/po/ta.po +++ b/po/ta.po @@ -989,7 +989,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/te.po b/po/te.po index ce06477314..80be695265 100644 --- a/po/te.po +++ b/po/te.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "సంఖ్య కాదు" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/th.po b/po/th.po index 9afa0f4e0b..fe30b8e4c7 100644 --- a/po/th.po +++ b/po/th.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/tr.po b/po/tr.po index 2151908eff..336b035e9b 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/tvl.po b/po/tvl.po index 796aea84c9..e7b922b9e5 100644 --- a/po/tvl.po +++ b/po/tvl.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/tzo.po b/po/tzo.po index b013c62c89..dc906c139d 100644 --- a/po/tzo.po +++ b/po/tzo.po @@ -3103,7 +3103,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ug.po b/po/ug.po index 6212fb93c5..56d88595dd 100644 --- a/po/ug.po +++ b/po/ug.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/ur.po b/po/ur.po index d873127eee..f2c508a6c8 100644 --- a/po/ur.po +++ b/po/ur.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/vi.po b/po/vi.po index 643d96e848..0dee80faa1 100644 --- a/po/vi.po +++ b/po/vi.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/wa.po b/po/wa.po index d26e4ccee1..d35418c549 100644 --- a/po/wa.po +++ b/po/wa.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/yo.po b/po/yo.po index 2f3e1d8d4e..bdb481f79d 100644 --- a/po/yo.po +++ b/po/yo.po @@ -3104,7 +3104,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/zh_CN.po b/po/zh_CN.po index 75409eb24e..9c8be317ab 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -1385,7 +1385,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 diff --git a/po/zh_TW.po b/po/zh_TW.po index 7696d4e93d..e71f7b12c2 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -990,7 +990,7 @@ msgid "Not a number" msgstr "" #: js/block.js:4401 -msgid "Octave value must be between 1 and 10." +msgid "Octave value must be between 1 and 8." msgstr "" #: js/block.js:4409 From da7a2ef1b21ce70b95ed55f89dc03f8e62b82e50 Mon Sep 17 00:00:00 2001 From: Jivansh Date: Sun, 29 Dec 2024 23:35:13 +0530 Subject: [PATCH 04/19] Fixes #4189 2 blocks getting added (#4193) * Fixes sugarlabs#4189 2 blocks getting added * Only keep preventDefault for onMouseMove --- js/palette.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/js/palette.js b/js/palette.js index 4e3fe0a8b7..f2e5e8c160 100644 --- a/js/palette.js +++ b/js/palette.js @@ -980,6 +980,7 @@ class Palette { }; const onMouseMove = (e) => { + e.preventDefault(); let x, y; if (e.type === "touchmove") { x = e.touches[0].clientX; @@ -992,14 +993,16 @@ class Palette { }; onMouseMove(event); - document.addEventListener("touchmove", onMouseMove); + document.addEventListener("touchmove", onMouseMove, { passive: false }); document.addEventListener("mousemove", onMouseMove); const that = this; const up = (event) => { document.body.style.cursor = "default"; document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("touchmove", onMouseMove); img.onmouseup = null; + img.ontouchend = null; const x = parseInt(img.style.left); const y = parseInt(img.style.top); @@ -1009,15 +1012,15 @@ class Palette { document.body.removeChild(img); itemCell.appendChild(img); - if (!x || !y) return; + // if (!x || !y) return; that._makeBlockFromProtoblock( protoListScope[blk], true, b.modname, event, - x - that.activity.blocksContainer.x, - y - that.activity.blocksContainer.y + (x || that.activity.blocksContainer.x + 100) - that.activity.blocksContainer.x, + (y || that.activity.blocksContainer.y + 100) - that.activity.blocksContainer.y ); }; From 4e2bb7782c9a59d85fef3184804347f26ade3b64 Mon Sep 17 00:00:00 2001 From: Subhas Pramanik Date: Sun, 29 Dec 2024 23:37:50 +0530 Subject: [PATCH 05/19] helpful Search only visible in advance mode (#4203) * helpfulSearch only visible in advance mode * helpful search only visible in advance mode * helpful search only visible in advance mode --- js/activity.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/js/activity.js b/js/activity.js index 892fff5568..80fe79c855 100644 --- a/js/activity.js +++ b/js/activity.js @@ -452,16 +452,11 @@ class Activity { // Append the closeButtonDiv to the helpfulSearchDiv this.helpfulSearchDiv.appendChild(closeButtonDiv); - // Add event listener to remove the search div from the DOM when clicked on the close button - closeButton.addEventListener("click", () => { - this.helpfulSearchDiv.parentNode.removeChild(this.helpfulSearchDiv); // Remove from DOM - }); + // Add event listener to remove the search div from the DOM + const modeButton = docById("begIconText"); + closeButton.addEventListener("click", this._hideHelpfulSearchWidget); + modeButton.addEventListener("click", this._hideHelpfulSearchWidget); - if (docById("helpfulSearch")) { - docById("helpfulSearch").parentNode.removeChild( - docById("helpfulSearch") - ); - } this.helpfulSearchDiv.appendChild(this.helpfulSearchWidget); } @@ -498,6 +493,9 @@ class Activity { if (docById("helpfulWheelDiv").style.display !== "none") { docById("helpfulWheelDiv").style.display = "none"; } + if (this.helpfulSearchDiv && this.helpfulSearchDiv.parentNode) { + this.helpfulSearchDiv.parentNode.removeChild(this.helpfulSearchDiv); + } that.__tick(); } @@ -2391,6 +2389,9 @@ class Activity { // Bring widget to top. this.searchWidget.style.zIndex = 1001; this.searchWidget.style.border = "2px solid blue"; + if (this.helpfulSearchDiv) { + this._hideHelpfulSearchWidget(); + } if (this.searchWidget.style.visibility === "visible") { this.hideSearchWidget(); } else { From a65a8656e08a037f5f642ea23f4cfdb948b949b4 Mon Sep 17 00:00:00 2001 From: omsuneri <142336291+omsuneri@users.noreply.github.com> Date: Sun, 29 Dec 2024 23:40:36 +0530 Subject: [PATCH 06/19] Test File for the API (#4201) * Test File for the DictBlocksAPI * Create MeterBlocksAPI.test.js * Creating test for MeterBlocksAPI.js * Exporting modules for test * Creating PenBlocksAPI.test.js test for the PenBlocksAPI.js * Exporting modules for test * Creating test for the IntervalsBlocksAPI.js * Exporting modules for test * Adding test for ToneBlocksAPI * Creating test for PitchBlocksAPI.js * exp --- js/js-export/API/DictBlocksAPI.js | 2 + js/js-export/API/IntervalsBlocksAPI.js | 1 + js/js-export/API/MeterBlocksAPI.js | 3 + js/js-export/API/PenBlocksAPI.js | 1 + js/js-export/API/PitchBlocksAPI.js | 1 + js/js-export/API/ToneBlocksAPI.js | 1 + .../API/__tests__/DictBlocksAPI.test.js | 100 +++++++++++ .../API/__tests__/IntervalsBlocksAPI.test.js | 60 +++++++ .../API/__tests__/MeterBlocksAPI.test.js | 88 ++++++++++ .../API/__tests__/PenBlocksAPI.test.js | 111 +++++++++++++ .../API/__tests__/PitchBlocksAPI.test.js | 156 ++++++++++++++++++ .../API/__tests__/ToneBlocksAPI.test.js | 101 ++++++++++++ 12 files changed, 625 insertions(+) create mode 100644 js/js-export/API/__tests__/DictBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/IntervalsBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/MeterBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/PenBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/PitchBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/ToneBlocksAPI.test.js diff --git a/js/js-export/API/DictBlocksAPI.js b/js/js-export/API/DictBlocksAPI.js index 760d2cddff..899c83b098 100644 --- a/js/js-export/API/DictBlocksAPI.js +++ b/js/js-export/API/DictBlocksAPI.js @@ -51,3 +51,5 @@ class DictBlocksAPI { return this.runCommand("getValue", [args[1], args[0], this.turIndex]); } } + +module.exports = DictBlocksAPI; \ No newline at end of file diff --git a/js/js-export/API/IntervalsBlocksAPI.js b/js/js-export/API/IntervalsBlocksAPI.js index 8956023b5e..9ad3d719da 100644 --- a/js/js-export/API/IntervalsBlocksAPI.js +++ b/js/js-export/API/IntervalsBlocksAPI.js @@ -58,3 +58,4 @@ class IntervalsBlocksAPI { return this.runCommand("setTemperament", [args[0], args[1], args[2]]); } } +module.exports = IntervalsBlocksAPI; diff --git a/js/js-export/API/MeterBlocksAPI.js b/js/js-export/API/MeterBlocksAPI.js index 3a74993147..66ce847982 100644 --- a/js/js-export/API/MeterBlocksAPI.js +++ b/js/js-export/API/MeterBlocksAPI.js @@ -74,3 +74,6 @@ class MeterBlocksAPI { return Singer.MeterActions.getNotesPlayed(args[0], this.turIndex); } } + + +module.exports = MeterBlocksAPI; diff --git a/js/js-export/API/PenBlocksAPI.js b/js/js-export/API/PenBlocksAPI.js index 29685c75fb..b46cc8676f 100644 --- a/js/js-export/API/PenBlocksAPI.js +++ b/js/js-export/API/PenBlocksAPI.js @@ -99,3 +99,4 @@ class PenBlocksAPI { return this.runCommand("doSetFont", [args[0]]); } } +module.exports = PenBlocksAPI; diff --git a/js/js-export/API/PitchBlocksAPI.js b/js/js-export/API/PitchBlocksAPI.js index 93112bc2b8..ea786e2da4 100644 --- a/js/js-export/API/PitchBlocksAPI.js +++ b/js/js-export/API/PitchBlocksAPI.js @@ -179,3 +179,4 @@ class PitchBlocksAPI { return Singer.PitchActions.numToPitch(args[0], "octave", this.turIndex); } } +module.exports = PitchBlocksAPI; diff --git a/js/js-export/API/ToneBlocksAPI.js b/js/js-export/API/ToneBlocksAPI.js index 43b70417f0..f7fe4d420a 100644 --- a/js/js-export/API/ToneBlocksAPI.js +++ b/js/js-export/API/ToneBlocksAPI.js @@ -129,3 +129,4 @@ class ToneBlocksAPI { return this.ENDFLOWCOMMAND; } } +module.exports = ToneBlocksAPI; \ No newline at end of file diff --git a/js/js-export/API/__tests__/DictBlocksAPI.test.js b/js/js-export/API/__tests__/DictBlocksAPI.test.js new file mode 100644 index 0000000000..3daf3aee62 --- /dev/null +++ b/js/js-export/API/__tests__/DictBlocksAPI.test.js @@ -0,0 +1,100 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; + +global.globalActivity = { + turtles: { + ithTurtle: jest.fn(() => ({ name: "defaultDict" })), + }, +}; + +const DictBlocksAPI = require("../DictBlocksAPI"); + +describe("DictBlocksAPI", () => { + let dictBlocksAPI; + + beforeEach(() => { + dictBlocksAPI = new DictBlocksAPI(); + dictBlocksAPI.turIndex = 0; + dictBlocksAPI.runCommand = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("getDict calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["mockDict"]); + + dictBlocksAPI.getDict("testDict"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("getDict", ["testDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("getDict", ["mockDict", 0]); + }); + + test("getDict uses default turIndex when no dict is provided", () => { + JSInterface.validateArgs.mockReturnValue(["defaultDict"]); + + dictBlocksAPI.getDict(); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("getDict", [0]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("getDict", ["defaultDict", 0]); + }); + + test("showDict calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["mockDict"]); + + dictBlocksAPI.showDict("testDict"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("showDict", ["testDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("showDict", ["mockDict", 0]); + }); + + test("showDict uses default turIndex when no dict is provided", () => { + JSInterface.validateArgs.mockReturnValue(["defaultDict"]); + + dictBlocksAPI.showDict(); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("showDict", [0]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("showDict", ["defaultDict", 0]); + }); + + test("setValue calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["key", "value", "testDict"]); + + dictBlocksAPI.setValue("key", "value", "testDict"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setValue", ["key", "value", "testDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("setValue", ["testDict", "key", "value", 0]); + }); + + test("setValue uses default dict when no dict is provided", () => { + JSInterface.validateArgs.mockReturnValue(["key", "value", "defaultDict"]); + global.globalActivity.turtles.ithTurtle.mockReturnValue({ name: "defaultDict" }); + + dictBlocksAPI.setValue("key", "value"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setValue", ["key", "value", "defaultDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("setValue", ["defaultDict", "key", "value", 0]); + }); + + test("getValue calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["key", "testDict"]); + + dictBlocksAPI.getValue("key", "testDict"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("getValue", ["key", "testDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("getValue", ["testDict", "key", 0]); + }); + + test("getValue uses default dict when no dict is provided", () => { + JSInterface.validateArgs.mockReturnValue(["key", "defaultDict"]); + global.globalActivity.turtles.ithTurtle.mockReturnValue({ name: "defaultDict" }); + + dictBlocksAPI.getValue("key"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("getValue", ["key", "defaultDict"]); + expect(dictBlocksAPI.runCommand).toHaveBeenCalledWith("getValue", ["defaultDict", "key", 0]); + }); +}); diff --git a/js/js-export/API/__tests__/IntervalsBlocksAPI.test.js b/js/js-export/API/__tests__/IntervalsBlocksAPI.test.js new file mode 100644 index 0000000000..deafc1c899 --- /dev/null +++ b/js/js-export/API/__tests__/IntervalsBlocksAPI.test.js @@ -0,0 +1,60 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; +const IntervalsBlocksAPI = require('../IntervalsBlocksAPI'); + +const MusicBlocks = { BLK: 'mockedBlock' }; +global.MusicBlocks = MusicBlocks; + +describe('IntervalsBlocksAPI', () => { + let intervalsBlocksAPI; + + beforeEach(() => { + intervalsBlocksAPI = new IntervalsBlocksAPI(); + intervalsBlocksAPI.turIndex = 1; + intervalsBlocksAPI.ENDFLOWCOMMAND = 'end'; + intervalsBlocksAPI.runCommand = jest.fn(); + }); + + test('setKey calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue(['C', 'major']); + intervalsBlocksAPI.setKey('C', 'major'); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setKey', ['C', 'major']); + expect(intervalsBlocksAPI.runCommand).toHaveBeenCalledWith('setKey', ['C', 'major', 1]); + }); + + test('defineMode calls runCommand and awaits flow', async () => { + const flow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(['dorian', flow]); + await intervalsBlocksAPI.defineMode('dorian', flow); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('defineMode', ['dorian', flow]); + expect(intervalsBlocksAPI.runCommand).toHaveBeenCalledWith('defineMode', ['dorian', 1, 'mockedBlock']); + expect(flow).toHaveBeenCalled(); + }); + + test('setScalarInterval calls runCommand and awaits flow', async () => { + const flow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([5, flow]); + await intervalsBlocksAPI.setScalarInterval(5, flow); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setScalarInterval', [5, flow]); + expect(intervalsBlocksAPI.runCommand).toHaveBeenCalledWith('setScalarInterval', [5, 1]); + expect(flow).toHaveBeenCalled(); + }); + + test('setSemitoneInterval calls runCommand and awaits flow', async () => { + const flow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([7, flow]); + await intervalsBlocksAPI.setSemitoneInterval(7, flow); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setSemitoneInterval', [7, flow]); + expect(intervalsBlocksAPI.runCommand).toHaveBeenCalledWith('setSemitoneInterval', [7, 1]); + expect(flow).toHaveBeenCalled(); + }); + + test('setTemperament calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue(['equal', 440, 4]); + intervalsBlocksAPI.setTemperament('equal', 440, 4); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setTemperament', ['equal', 440, 4]); + expect(intervalsBlocksAPI.runCommand).toHaveBeenCalledWith('setTemperament', ['equal', 440, 4]); + }); +}); diff --git a/js/js-export/API/__tests__/MeterBlocksAPI.test.js b/js/js-export/API/__tests__/MeterBlocksAPI.test.js new file mode 100644 index 0000000000..fa309abc77 --- /dev/null +++ b/js/js-export/API/__tests__/MeterBlocksAPI.test.js @@ -0,0 +1,88 @@ + +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; +const MeterBlocksAPI = require('../MeterBlocksAPI'); +const Singer = { MeterActions: { getNotesPlayed: jest.fn() } }; +global.Singer = Singer; + +describe('MeterBlocksAPI', () => { + let meterBlocksAPI; + + beforeEach(() => { + meterBlocksAPI = new MeterBlocksAPI(); + meterBlocksAPI.turIndex = 1; + meterBlocksAPI.ENDFLOWCOMMAND = 'end'; + meterBlocksAPI.runCommand = jest.fn(); + }); + + test('setMeter calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([4, 4]); + meterBlocksAPI.setMeter(4, 4); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setMeter', [4, 4]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('setMeter', [4, 4, 1]); + }); + + test('setBPM calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([120, 4]); + meterBlocksAPI.setBPM(120, 4); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setBPM', [120, 4]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('setBPM', [120, 4, 1]); + }); + + test('setMasterBPM calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([100, 4]); + meterBlocksAPI.setMasterBPM(100, 4); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setMasterBPM', [100, 4]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('setMasterBPM', [100, 4]); + }); + + test('onEveryNoteDo calls runCommand with validated arguments', () => { + const action = jest.fn(); + JSInterface.validateArgs.mockReturnValue([action]); + meterBlocksAPI.onEveryNoteDo(action); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('onEveryNoteDo', [action]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('onEveryNoteDo', [action, null, null, 1]); + }); + + test('onEveryBeatDo calls runCommand with validated arguments', () => { + const action = jest.fn(); + JSInterface.validateArgs.mockReturnValue([action]); + meterBlocksAPI.onEveryBeatDo(action); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('onEveryBeatDo', [action]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('onEveryBeatDo', [action, null, null, 1]); + }); + + test('onStrongBeatDo calls runCommand with validated arguments', () => { + const action = jest.fn(); + JSInterface.validateArgs.mockReturnValue([2, action]); + meterBlocksAPI.onStrongBeatDo(2, action); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('onStrongBeatDo', [2, action]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('onStrongBeatDo', [2, action, null, null, 1]); + }); + + test('onWeakBeatDo calls runCommand with validated arguments', () => { + const action = jest.fn(); + JSInterface.validateArgs.mockReturnValue([action]); + meterBlocksAPI.onWeakBeatDo(action); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('onWeakBeatDo', [action]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('onWeakBeatDo', [action, null, null, 1]); + }); + + test('setNoClock calls runCommand and awaits flow', async () => { + const flow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([flow]); + await meterBlocksAPI.setNoClock(flow); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setNoClock', [flow]); + expect(meterBlocksAPI.runCommand).toHaveBeenCalledWith('setNoClock', [1]); + expect(flow).toHaveBeenCalled(); + }); + + test('getNotesPlayed calls Singer.MeterActions.getNotesPlayed with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([4]); + meterBlocksAPI.getNotesPlayed(4); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('getNotesPlayed', [4]); + expect(Singer.MeterActions.getNotesPlayed).toHaveBeenCalledWith(4, 1); + }); +}); diff --git a/js/js-export/API/__tests__/PenBlocksAPI.test.js b/js/js-export/API/__tests__/PenBlocksAPI.test.js new file mode 100644 index 0000000000..9fca7a9f21 --- /dev/null +++ b/js/js-export/API/__tests__/PenBlocksAPI.test.js @@ -0,0 +1,111 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; +const PenBlocksAPI = require('../PenBlocksAPI') +global.globalActivity = { + turtles: { + refreshCanvas: jest.fn(), + }, + logo: { + turtles: { + setBackgroundColor: jest.fn(), + }, + }, +}; + +describe('PenBlocksAPI', () => { + let penBlocksAPI; + + beforeEach(() => { + penBlocksAPI = new PenBlocksAPI(); + penBlocksAPI.turIndex = 1; + penBlocksAPI.ENDFLOW = 'end'; + penBlocksAPI.runCommand = jest.fn(); + }); + + test('setColor calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([50]); + penBlocksAPI.setColor(50); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setColor', [50]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetColor', [50]); + }); + + test('setGrey calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([30]); + penBlocksAPI.setGrey(30); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setGrey', [30]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetChroma', [30]); + }); + + test('setShade calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([70]); + penBlocksAPI.setShade(70); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setShade', [70]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetValue', [70]); + }); + + test('setHue calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([120]); + penBlocksAPI.setHue(120); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setHue', [120]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetHue', [120]); + }); + + test('setTranslucency calculates and calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([80]); + penBlocksAPI.setTranslucency(80); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setTranslucency', [80]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetPenAlpha', [1.0 - 80 / 100]); + }); + + test('setPensize calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([10]); + penBlocksAPI.setPensize(10); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setPensize', [10]); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetPensize', [10]); + }); + + test('penUp calls runCommand', () => { + penBlocksAPI.penUp(); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doPenUp'); + }); + + test('penDown calls runCommand', () => { + penBlocksAPI.penDown(); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doPenDown'); + }); + + test('fillShape calls commands and refreshCanvas', async () => { + const flow = jest.fn(); + await penBlocksAPI.fillShape(flow); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doStartFill'); + expect(flow).toHaveBeenCalled(); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doEndFill'); + expect(global.globalActivity.turtles.refreshCanvas).toHaveBeenCalled(); + }); + + test('hollowLine calls commands and refreshCanvas', async () => { + const flow = jest.fn(); + await penBlocksAPI.hollowLine(flow); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doStartHollowLine'); + expect(flow).toHaveBeenCalled(); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doEndHollowLine'); + expect(global.globalActivity.turtles.refreshCanvas).toHaveBeenCalled(); + }); + + test('fillBackground calls setBackgroundColor', () => { + penBlocksAPI.fillBackground(); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('_anonymous', expect.any(Function)); + const setBackgroundFunc = penBlocksAPI.runCommand.mock.calls[0][1]; + setBackgroundFunc(); + expect(global.globalActivity.logo.turtles.setBackgroundColor).toHaveBeenCalledWith(1); + }); + + test('setFont calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue(['Arial']); + penBlocksAPI.setFont('Arial'); + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setFont', ['Arial']); + expect(penBlocksAPI.runCommand).toHaveBeenCalledWith('doSetFont', ['Arial']); + }); +}); diff --git a/js/js-export/API/__tests__/PitchBlocksAPI.test.js b/js/js-export/API/__tests__/PitchBlocksAPI.test.js new file mode 100644 index 0000000000..89d413ca12 --- /dev/null +++ b/js/js-export/API/__tests__/PitchBlocksAPI.test.js @@ -0,0 +1,156 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; +const PitchBlocksAPI = require('../PitchBlocksAPI'); + +global.MusicBlocks = { BLK: 'mockBlock' }; +global.Singer = { + PitchActions: { + numToPitch: jest.fn() + } +}; + +describe('PitchBlocksAPI', () => { + let pitchBlocksAPI; + + beforeEach(() => { + pitchBlocksAPI = new PitchBlocksAPI(); + pitchBlocksAPI.turIndex = 1; + pitchBlocksAPI.ENDFLOWCOMMAND = 'end'; + pitchBlocksAPI.runCommand = jest.fn(); + }); + + test('playPitch calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue(['C', 4]); + + pitchBlocksAPI.playPitch('C', 4); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('playPitch', ['C', 4]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('playPitch', ['C', 4, 0, 1, MusicBlocks.BLK]); + }); + + test('stepPitch calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([2]); + + pitchBlocksAPI.stepPitch(2); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('stepPitch', [2]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('stepPitch', [2, 1]); + }); + + test('playNthModalPitch calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([3, 5]); + + pitchBlocksAPI.playNthModalPitch(3, 5); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('playNthModalPitch', [3, 5]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('playNthModalPitch', [3, 5, 1, MusicBlocks.BLK]); + }); + + test('playPitchNumber calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([7]); + + pitchBlocksAPI.playPitchNumber(7); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('playPitchNumber', [7]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('playPitchNumber', [7, 1, MusicBlocks.BLK]); + }); + + test('playHertz calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([440]); + + pitchBlocksAPI.playHertz(440); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('playHertz', [440]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('playHertz', [440, 1]); + }); + + test('setAccidental calls runCommand with validated arguments and executes flow', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(['sharp', mockFlow]); + + const result = await pitchBlocksAPI.setAccidental('sharp', mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setAccidental', ['sharp', mockFlow]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('setAccidental', ['sharp', 1, MusicBlocks.BLK]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(pitchBlocksAPI.ENDFLOWCOMMAND); + }); + + test('setScalarTranspose calls runCommand with validated arguments and executes flow', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([2, mockFlow]); + + const result = await pitchBlocksAPI.setScalarTranspose(2, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setScalarTranspose', [2, mockFlow]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('setScalarTranspose', [2, 1]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(pitchBlocksAPI.ENDFLOWCOMMAND); + }); + + test('setSemitoneTranspose calls runCommand with validated arguments and executes flow', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([1, mockFlow]); + + const result = await pitchBlocksAPI.setSemitoneTranspose(1, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setSemitoneTranspose', [1, mockFlow]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('setSemitoneTranspose', [1, 1]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(pitchBlocksAPI.ENDFLOWCOMMAND); + }); + + test('setRegister calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([3]); + + pitchBlocksAPI.setRegister(3); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setRegister', [3]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('setRegister', [3, 1]); + }); + + test('invert calls runCommand with validated arguments and executes flow', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(['inversionName', 4, 'mode', mockFlow]); + + const result = await pitchBlocksAPI.invert('inversionName', 4, 'mode', mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('invert', ['inversionName', 4, 'mode', mockFlow]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('invert', ['inversionName', 4, 'mode', 1]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(pitchBlocksAPI.ENDFLOWCOMMAND); + }); + + test('setPitchNumberOffset calls runCommand with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([7, 3]); + + pitchBlocksAPI.setPitchNumberOffset(7, 3); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setPitchNumberOffset', [7, 3]); + expect(pitchBlocksAPI.runCommand).toHaveBeenCalledWith('setPitchNumberOffset', [7, 3, 1]); + }); + + test('numToPitch calls numToPitch in Singer.PitchActions with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([5]); + Singer.PitchActions.numToPitch.mockReturnValue('C'); + + const result = pitchBlocksAPI.numToPitch(5); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('numToPitch', [5]); + expect(Singer.PitchActions.numToPitch).toHaveBeenCalledWith(5, 'pitch', 1); + expect(result).toBe('C'); + }); + + test('numToOctave calls numToPitch in Singer.PitchActions with validated arguments', () => { + JSInterface.validateArgs.mockReturnValue([5]); + Singer.PitchActions.numToPitch.mockReturnValue(4); + + const result = pitchBlocksAPI.numToOctave(5); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('numToOctave', [5]); + expect(Singer.PitchActions.numToPitch).toHaveBeenCalledWith(5, 'octave', 1); + expect(result).toBe(4); + }); +}); diff --git a/js/js-export/API/__tests__/ToneBlocksAPI.test.js b/js/js-export/API/__tests__/ToneBlocksAPI.test.js new file mode 100644 index 0000000000..ca6564aca4 --- /dev/null +++ b/js/js-export/API/__tests__/ToneBlocksAPI.test.js @@ -0,0 +1,101 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; +const ToneBlocksAPI = require('../ToneBlocksAPI'); +global.MusicBlocks = { BLK: 'mockBlock' }; + +describe('ToneBlocksAPI', () => { + let toneBlocksAPI; + + beforeEach(() => { + toneBlocksAPI = new ToneBlocksAPI(); + toneBlocksAPI.turIndex = 1; + toneBlocksAPI.ENDFLOWCOMMAND = 'end'; + toneBlocksAPI.runCommand = jest.fn(); + }); + + test('setInstrument calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(['piano', mockFlow]); + + const result = await toneBlocksAPI.setInstrument('piano', mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('setInstrument', ['piano', mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('setTimbre', ['piano', toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doVibrato calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([0.5, 2, mockFlow]); + + const result = await toneBlocksAPI.doVibrato(0.5, 2, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doVibrato', [0.5, 2, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doVibrato', [0.5, 2, toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doChorus calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([1.2, 0.3, 0.7, mockFlow]); + + const result = await toneBlocksAPI.doChorus(1.2, 0.3, 0.7, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doChorus', [1.2, 0.3, 0.7, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doChorus', [1.2, 0.3, 0.7, toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doPhaser calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([0.8, 2, 440, mockFlow]); + + const result = await toneBlocksAPI.doPhaser(0.8, 2, 440, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doPhaser', [0.8, 2, 440, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doPhaser', [0.8, 2, 440, toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doTremolo calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([4, 0.5, mockFlow]); + + const result = await toneBlocksAPI.doTremolo(4, 0.5, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doTremolo', [4, 0.5, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doTremolo', [4, 0.5, toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doDistortion calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([0.8, mockFlow]); + + const result = await toneBlocksAPI.doDistortion(0.8, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doDistortion', [0.8, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doDistortion', [0.8, toneBlocksAPI.turIndex]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); + + test('doHarmonic calls runCommand with validated arguments', async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([3, mockFlow]); + + const result = await toneBlocksAPI.doHarmonic(3, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith('doHarmonic', [3, mockFlow]); + expect(toneBlocksAPI.runCommand).toHaveBeenCalledWith('doHarmonic', [3, toneBlocksAPI.turIndex, MusicBlocks.BLK]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(toneBlocksAPI.ENDFLOWCOMMAND); + }); +}); From d121f381832ce5ece9595acef7e81f8128c9fd70 Mon Sep 17 00:00:00 2001 From: mahadevan <135952571+M-DEV-1@users.noreply.github.com> Date: Mon, 30 Dec 2024 19:49:57 +0530 Subject: [PATCH 07/19] Fix Navbar Items Responsiveness for Mobile View (#4197) * formatted all css files, fixed minor spelling errors previously made * added: media queries to handle navbar resizing * fixed: icons visible between 360 and 400 px as well --- css/style.css | 38 +- dist/css/activities.css | 978 +++++++++++++++++++++++++++++++++++++++- dist/css/activity.css | 232 +++++++++- dist/css/keyboard.css | 56 ++- dist/css/style.css | 125 ++++- lib/materialize-iso.css | 42 +- 6 files changed, 1426 insertions(+), 45 deletions(-) diff --git a/css/style.css b/css/style.css index 15efe6ff86..1c6d4193c3 100644 --- a/css/style.css +++ b/css/style.css @@ -1,15 +1,15 @@ -input[type=range] { +input[type="range"] { height: 4px; appearance: none; -webkit-appearance: none; width: 250px; } -input[type=range]:focus { +input[type="range"]:focus { outline: none; } -input[type=range]:not(.pitchSlider)::-webkit-slider-runnable-track { +input[type="range"]:not(.pitchSlider)::-webkit-slider-runnable-track { width: 10px; height: 11px; cursor: pointer; @@ -20,9 +20,9 @@ input[type=range]:not(.pitchSlider)::-webkit-slider-runnable-track { border: 0px solid #010101; } -input[type=range]:not(.pitchSlider)::-webkit-slider-thumb { +input[type="range"]:not(.pitchSlider)::-webkit-slider-thumb { box-shadow: 1px 1px 1px #000031; - border: 1px solid #00001E; + border: 1px solid #00001e; height: 26px; width: 26px; border-radius: 15px; @@ -32,11 +32,11 @@ input[type=range]:not(.pitchSlider)::-webkit-slider-thumb { margin-top: -8px; } -input[type=range]:not(.pitchSlider):focus::-webkit-slider-runnable-track { +input[type="range"]:not(.pitchSlider):focus::-webkit-slider-runnable-track { background: #90c100; } -input[type=range]:not(.pitchSlider)::-moz-range-track { +input[type="range"]:not(.pitchSlider)::-moz-range-track { width: 100%; height: 4px; cursor: pointer; @@ -47,17 +47,17 @@ input[type=range]:not(.pitchSlider)::-moz-range-track { border: 0px solid #010101; } -input[type=range]:not(.pitchSlider)::-moz-range-thumb { +input[type="range"]:not(.pitchSlider)::-moz-range-thumb { box-shadow: 1px 1px 1px #000031; - border: 1px solid #00001E; + border: 1px solid #00001e; height: 26px; width: 26px; border-radius: 15px; - background: #FFFFFF; + background: #ffffff; cursor: pointer; } -input[type=range]::-ms-track { +input[type="range"]::-ms-track { width: 100%; height: 11px; cursor: pointer; @@ -67,35 +67,35 @@ input[type=range]::-ms-track { color: transparent; } -input[type=range]::-ms-fill-lower { +input[type="range"]::-ms-fill-lower { background: #90c100; border: 0px solid #010101; border-radius: 2px; box-shadow: 1px 1px 1px #000000; } -input[type=range]::-ms-fill-upper { +input[type="range"]::-ms-fill-upper { background: #90c100; border: 0px solid #010101; border-radius: 2px; box-shadow: 1px 1px 1px #000000; } -input[type=range]::-ms-thumb { +input[type="range"]::-ms-thumb { margin-top: 1px; box-shadow: 1px 1px 1px #000031; - border: 1px solid #00001E; + border: 1px solid #00001e; height: 26px; width: 26px; border-radius: 15px; - background: #FFFFFF; + background: #ffffff; cursor: pointer; } -input[type=range]:focus::-ms-fill-lower { +input[type="range"]:focus::-ms-fill-lower { background: #90c100; } -input[type=range]:focus::-ms-fill-upper { +input[type="range"]:focus::-ms-fill-upper { background: #90c100; -} \ No newline at end of file +} diff --git a/dist/css/activities.css b/dist/css/activities.css index 9691895b73..5b5257b166 100644 --- a/dist/css/activities.css +++ b/dist/css/activities.css @@ -1 +1,977 @@ -#popdown-palette li,.content li,nav ul{list-style:none}.modal{display:none;position:fixed;z-index:1;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgba(0,0,0,.4)}.modal-content{background-color:#fefefe;margin:15% auto;padding:20px;border:1px solid #888;width:50%}.close{color:#aaa;float:right;font-size:28px;font-weight:700}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer}#search[type=text]{width:400px;box-sizing:border-box;position:absolute;background-color:#fff;background-repeat:no-repeat;padding:6px 10px 6px 20px;-webkit-transition:width .4s ease-in-out;transition:width .4s ease-in-out;font-size:24px;color:#000}#search:focus{border:2px solid #87CEFA}img.icon,nav img{border-radius:100%}.ui-menu{position:relative;background-color:rgba(255,255,255,1);max-width:250px;font-size:24px}#ui-id-1{margin:0;padding:0;-webkit-margin-before:0;-webkit-margin-after:0;-webkit-margin-start:0;-webkit-margin-end:0;-webkit-padding-start:0;list-style-type:none}#ui-id-1 li:before{content:"• ";margin-right:5px;font-size:20px;font-weight:700;margin-left:4px}#ui-id-1 li:hover:before,.ui-state-focus{background-color:#D0D3D4}.scrollSearch{max-height:150px;margin-bottom:10px;overflow-x:auto;overflow-y:auto}#myProgress{width:180px;background-color:#92b5c8;position:absolute}#myBar{width:0%;height:40px;background-color:#fff;line-height:30px}#popdown-palette{display:none;position:absolute;z-index:9999;top:0;left:0;width:60%;max-height:100%;overflow-y:scroll;background:rgba(255,255,255,.85)}.popupMsg,body,body.noScroll{overflow:hidden}#popdown-palette:last-child{margin-bottom:2.5em}#popdown-palette.show{display:block}#popdown-palette.show~.canvasHolder{filter:blur(10px);-webkit-filter:blur(10px)}#popdown-palette ul{display:none}#popdown-palette .palette.show ul{display:block}#popdown-palette h3{border-bottom:1px solid #444;width:50%;padding:0 10%}#popdown-palette h2 span{vertical-align:50%}#popdown-palette h2 img{display:block;float:right}#popdown-palette .palette.show .show-button,.canvasHolder.hide{display:none}#popdown-palette .palette:not(.show) .hide-button{display:none}#popdown-palette .palette:not(.show) .popout-button{display:none}div.back{display:block;position:fixed;height:2.5em;width:100%;top:calc(100% - 2.5em);background-color:#4682B4}div.back h2{margin-top:.25em;border-bottom:none!important;color:#fff}div.back:active{background-color:#000}.canvasHolder{transition:.75s ease all;transform-origin:0 0;position:absolute;top:0;left:0}nav h1,nav ul,nav ul li{display:inline}nav{position:fixed;top:0;left:0;z-index:100;background-color:#8bc34a;height:64px;width:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);font:32px sans;vertical-align:middle;line-height:64px;color:#fff}.top-wrapper,body{font-family:sans-serif}nav .nav-container{padding:0}nav .logo{padding-left:12px}nav h1{font-size:32px;position:relative;top:-12px}nav img{height:48px;width:48px;margin-top:6px}nav imghover{background-color:rgba(255,255,255,.3)}nav imgactive{background-color:rgba(255,255,255,.8)}nav ul{text-align:right}.content li .options,.content li .options input,select{text-align:center}nav ul li{padding-right:12px}.nav-spacer{height:96px}.content{padding:0;margin:0;display:flex;flex-wrap:wrap}#mkbInnerDiv,#pdmInnerDiv,#playbackInnerDiv,#pscInnerDiv,#ptmInnerDiv,#statusInnerDiv,#temperamentInnerDiv,#timbreInnerDiv{margin-left:53px;overflow-x:auto}.content li{display:block;width:23.75%;float:left;padding-left:1%}.content li[current=true] img.thumbnail{opacity:0}@media (max-width:500px){.content li{width:48.5%;padding-left:1%}.canvasHolder.hide{transform:scale(.485)}nav h1{display:none}}@media (max-width:800px) and (min-width:501px){.content li{width:32%;padding-left:1%}.canvasHolder.hide{transform:scale(.32)}}.content li img.thumbnail{background:#96D3F3;width:100%;padding:0}#planet-iframe{width:100vw;height:100vh;background-color:#fff;position:absolute;top:0;left:0}.projectname{word-wrap:break-word}img.icon{width:30px}img.icon:hover{background-color:rgba(139,195,74,.8)}#loading-image-container{z-index:99999}body{background-color:#92b5c8!important;padding:0;margin:0}body.samples-shown{overflow-y:scroll;background:#fff!important}select{background-color:#88e20a;font-weight:700!important;resize:none!important;padding:0!important;border:0!important;width:20px}input.boolean,input.number,input.text{width:100px;font-weight:700!important;padding:0!important;border:0!important;text-align:center;resize:none!important}input.text{background-color:#FF5942!important}input.boolean{background-color:#C96DF3!important}input.number{background-color:#FF5293!important}input.BPMInput,input.dissectNumber,input.musicratio1,input.musicratio2{background-color:#8CC6FF!important;text-align:center;font-size:24px;font-weight:700!important;resize:none!important;padding:0!important;border:0!important;width:100%!important;height:100%!important}table{border-collapse:separate;border-spacing:1px 1px}#canvas{overflow-y:visible}#meterDiv,#modeDiv,#pdmDiv,#playbackDiv,#ptmDiv,#statusDiv{position:absolute;top:20%;left:20%;background:rgba(255,255,255,.85)!important}#meterTableDiv,#modeTableDiv,#pdmTableDiv,#playbackTableDiv,#ptmTableDiv,#statusTableDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)!important;width:680px}#meterButtonsDiv,#mkbButtonsDiv,#modeButtonsDiv,#pdmButtonsDiv,#playbackButtonsDiv,#ptmButtonsDiv,#statusButtonsDiv,#tempoButtonsDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)}#mkbOuterDiv,#pdmOuterDiv,#playbackOuterDiv,#ptmOuterDiv,#statusOuterDiv{position:absolute;left:0;top:0;right:5em;overflow-y:auto;overflow-x:none;background:rgba(255,255,255,.85)}#mkbDiv{position:absolute;top:0;left:0;background:rgba(255,255,255,.85)!important}#mkbTableDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)!important;width:1020px}#tempoDiv{position:absolute;top:20%;left:20%;background:rgba(255,255,255,.85)!important;-webkit-user-select:none}#helpDiv{position:absolute;top:20%;left:20%;width:455px;height:375px;background:#e8e8e8!important;-webkit-user-select:none;border-radius:5px;box-shadow:0 1px 10px #8080808f}#right-arrow{left:410px;background:url(../header-icons/right-arrow.png)}#left-arrow{left:5px;background:url(../header-icons/left-arrow.png)}#left-arrow,#right-arrow{position:absolute;top:195px;background-size:40px;height:40px;width:40px}.hover:hover{cursor:pointer}.top-wrapper{width:100%;position:absolute;top:0;background:#2196F3;display:flex;flex-direction:column;justify-content:center;color:#fff;font-size:1.1em;text-align:center;height:55px}.close-button{position:absolute;font-size:1em;right:410px;width:18px;height:18px;background:url(../header-icons/close.png);background-size:18px;cursor:pointer}.drag-button{position:absolute;right:20px;background:url(../header-icons/move.png);background-size:22px;height:22px;width:22px;cursor:move}#pscOuterDiv,#rulerOuterDiv,#sliderOuterDiv,#temperamentOuterDiv,#timbreOuterDiv{right:5em;overflow-y:auto;overflow-x:none}#pscDiv,#pscTableDiv,#timbreDiv,#timbreTableDiv{background:rgba(255,255,255,.85)!important}#helpDiv h1{text-align:left;padding-left:30px;font-size:1.5em}#helpDiv p:not(:first-child){text-align:left;padding-left:30px;font-size:.9em;line-height:20px}#userEdit input,.circle,.headcol,.labelcol,.popup .popuptext,.rangeslidervalue,input.timbreName{text-align:center}#helpButtonsDiv{position:relative;left:0;top:0;border:0!important}#helpBodyDiv{position:relative;left:45px;border:0!important;overflow-x:hidden;overflow-y:auto;width:365px;height:300px;background:#e8e8e8!important}#pscDiv,#timbreDiv{position:absolute;top:20%;left:20%}#pscTableDiv{position:relative;left:0;top:0;border:0!important;width:680px}#pscButtonsDiv,#timbreButtonsDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)}#pscOuterDiv,#timbreOuterDiv{position:absolute;left:0;top:0;background:rgba(255,255,255,.85)}#timbreTableDiv{position:relative;left:0;top:0;border:0!important;width:590px}input.timbreName{background-color:#8CC6FF!important;font-size:24px;resize:none!important;padding:0!important;border:0!important;width:100%!important;height:100%!important}#temperamentButtonsDiv,#temperamentOuterDiv{background:rgba(255,255,255,.85);left:0;top:0}#temperamentDiv{position:absolute;top:20%;left:20%;background:rgba(255,255,255,.85)!important}#temperamentTableDiv{position:relative;left:0;top:0;border:0!important;background:rgba(204,0,102,0)!important;width:560px}#temperamentButtonsDiv{position:relative;border:0!important}#temperamentOuterDiv{position:absolute}#graph{overflow-y:scroll;height:340px}#userEdit input{height:40px;width:40px;background:#8CC6FF;border:1px solid #000}.popup,.popupMsg{background-color:#fff}.popup{position:absolute;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;height:68px;width:160px;border:1px solid #000}.popup .popuptext{color:#fff;border-radius:6px;position:absolute;z-index:1}.popup .show{visibility:visible;-webkit-animation:fadeIn 1s;animation:fadeIn 1s}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}#download{position:absolute;top:100px;left:200px}#rulerDiv,#sliderDiv{position:absolute;top:20%;left:30%;background:rgba(255,255,255,.85)!important}#rulerTableDiv,#sliderTableDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)!important;width:680px}#rulerButtonsDiv,#sliderButtonsDiv{position:relative;left:0;top:0;border:0!important;background:rgba(255,255,255,.85)}#rulerOuterDiv,#sliderOuterDiv{position:absolute;left:0;top:0;background:rgba(255,255,255,.85)}#rulerInnerDiv{overflow-x:auto!important;margin-left:53px}#sliderInnerDiv{overflow-x:auto}.headcol{position:absolute;left:1px;vertical-align:middle}.labelcol{position:absolute;top:auto;vertical-align:middle}#pitchstaircase,#playPitch{top:20%;border:0!important;background:rgba(255,255,255,.85);-webkit-user-select:none;overflow-y:scroll!important;position:absolute}#pitchstaircase{left:30%}#playPitch{direction:rtl;left:25%}#sliderInCell{position:absolute}#progressBar{width:1%;height:70px;background-color:#4CAF50}.insideDivEnv{margin-top:10px;height:50px;margin-left:40px}.insideDivFilter,.insideDivOsc{margin-top:-30px;height:50px;margin-left:40px}.insideDivEffects,.insideDivSynth{margin-top:-30px;height:50px;margin-left:200px}.btn{background-color:#90c100;margin-top:6px;height:24px;width:60px;border-color:#90c100}.circle{width:40px;height:40px;border-radius:50%;font-size:25px;color:#fff;line-height:40px;background:#000;float:left}.rectangle{border:4px solid green}#wrapperEnv0,#wrapperEnv1,#wrapperEnv2,#wrapperEnv3{height:50px;margin-left:30px}.rangeslidervalue{display:inline-block;position:relative;color:#00f;background-color:#c8C8C8;line-height:20px;border-radius:10px;border-color:green;padding:5px 10px;margin-left:8px}.rangeslidervalue:after{position:absolute;top:8px;left:-7px;width:0;height:0;border-top:7px solid transparent;border-bottom:7px solid transparent;content:''}#selector0,#selector1,.filterselector{margin-top:-50px}#sel0,#sel1,.sel{height:35px;width:150px;margin-left:50px;margin-top:20px}#wrapper0,#wrapper1,#wrapper2,#wrapper3,#wrapper4,#wrapper5,.wrapper{margin-left:170px;height:50px}#s0,#s1,#s2,#s3,#s4,#s5,#sOsc0,#sOsc1,.s{margin-left:-100px;text-shadow:0 2px 3px #555;width:100px;font-weight:700;text-align:center}#s0,#s1,#s2,#s3,#s4,#s5,.s{color:#222}#s0,#sOsc0{margin-top:30px}#sOsc0,#sOsc1{color:#222}#wrapperOsc0,#wrapperOsc1{margin-left:170px;height:50px}#selOsc{margin-top:-50px}#selOsc1{height:35px;width:150px;margin-left:50px;margin-top:20px}#sFx0,#sFx1,#sFx2,#sS0,#sS1{color:#222;text-shadow:0 2px 3px #555;font-weight:700;width:100px;text-align:center;margin-left:60px;margin-top:20px}#effect0,#synth0{margin-left:40px;font-weight:700}#chosen{margin-left:20px;font-style:italic;font-weight:700}.wheelNav{height:350px;width:350px;margin:auto;-moz-transition:ease 1s;-o-transition:ease 1s;-webkit-transition:ease 1s;transition:ease 1s}.wheelNav>svg{width:100%;height:100%}@media (max-width:880px){.wheelNav{height:330px;width:330px}}@media (max-width:680px){.wheelNav{height:310px;width:310px}}@media (max-width:480px){.wheelNav{height:290px;width:290px}}.inactiveLink{pointer-events:none!important;cursor:default!important}.popupMsg{width:1000px;height:30px;position:absolute;top:130px;left:50%;margin-left:-500px;padding-top:2px;border-radius:8px;font-family:Arial,Helvetica,sans-serif;font-size:19px;text-align:center;text-overflow:ellipsis;cursor:pointer;visibility:hidden}#printText{border:2px solid #969696}#errorText{border:2px solid red;background-color:pink}#errorText.show,#printText.show{visibility:visible}#errorTextContent,#printTextContent{display:inline-block;width:940px;vertical-align:7px}.msgCloseIcon{width:28px;height:28px;filter:invert(100%)} \ No newline at end of file +#popdown-palette li, +.content li, +nav ul { + list-style: none; +} +.modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.4); +} +.modal-content { + background-color: #fefefe; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 50%; +} +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: 700; +} +.close:focus, +.close:hover { + color: #000; + text-decoration: none; + cursor: pointer; +} +#search[type="text"] { + width: 400px; + box-sizing: border-box; + position: absolute; + background-color: #fff; + background-repeat: no-repeat; + padding: 6px 10px 6px 20px; + -webkit-transition: width 0.4s ease-in-out; + transition: width 0.4s ease-in-out; + font-size: 24px; + color: #000; +} +#search:focus { + border: 2px solid #87cefa; +} +img.icon, +nav img { + border-radius: 100%; +} +.ui-menu { + position: relative; + background-color: rgba(255, 255, 255, 1); + max-width: 250px; + font-size: 24px; +} +#ui-id-1 { + margin: 0; + padding: 0; + -webkit-margin-before: 0; + -webkit-margin-after: 0; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + -webkit-padding-start: 0; + list-style-type: none; +} +#ui-id-1 li:before { + content: "• "; + margin-right: 5px; + font-size: 20px; + font-weight: 700; + margin-left: 4px; +} +#ui-id-1 li:hover:before, +.ui-state-focus { + background-color: #d0d3d4; +} +.scrollSearch { + max-height: 150px; + margin-bottom: 10px; + overflow-x: auto; + overflow-y: auto; +} +#myProgress { + width: 180px; + background-color: #92b5c8; + position: absolute; +} +#myBar { + width: 0%; + height: 40px; + background-color: #fff; + line-height: 30px; +} +#popdown-palette { + display: none; + position: absolute; + z-index: 9999; + top: 0; + left: 0; + width: 60%; + max-height: 100%; + overflow-y: scroll; + background: rgba(255, 255, 255, 0.85); +} +.popupMsg, +body, +body.noScroll { + overflow: hidden; +} +#popdown-palette:last-child { + margin-bottom: 2.5em; +} +#popdown-palette.show { + display: block; +} +#popdown-palette.show ~ .canvasHolder { + filter: blur(10px); + -webkit-filter: blur(10px); +} +#popdown-palette ul { + display: none; +} +#popdown-palette .palette.show ul { + display: block; +} +#popdown-palette h3 { + border-bottom: 1px solid #444; + width: 50%; + padding: 0 10%; +} +#popdown-palette h2 span { + vertical-align: 50%; +} +#popdown-palette h2 img { + display: block; + float: right; +} +#popdown-palette .palette.show .show-button, +.canvasHolder.hide { + display: none; +} +#popdown-palette .palette:not(.show) .hide-button { + display: none; +} +#popdown-palette .palette:not(.show) .popout-button { + display: none; +} +div.back { + display: block; + position: fixed; + height: 2.5em; + width: 100%; + top: calc(100% - 2.5em); + background-color: #4682b4; +} +div.back h2 { + margin-top: 0.25em; + border-bottom: none !important; + color: #fff; +} +div.back:active { + background-color: #000; +} +.canvasHolder { + transition: 0.75s ease all; + transform-origin: 0 0; + position: absolute; + top: 0; + left: 0; +} +nav h1, +nav ul, +nav ul li { + display: inline; +} +nav { + position: fixed; + top: 0; + left: 0; + z-index: 100; + background-color: #8bc34a; + height: 64px; + width: 100%; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + font: 32px sans; + vertical-align: middle; + line-height: 64px; + color: #fff; +} +.top-wrapper, +body { + font-family: sans-serif; +} +nav .nav-container { + padding: 0; +} +nav .logo { + padding-left: 12px; +} +nav h1 { + font-size: 32px; + position: relative; + top: -12px; +} +nav img { + height: 48px; + width: 48px; + margin-top: 6px; +} +nav imghover { + background-color: rgba(255, 255, 255, 0.3); +} +nav imgactive { + background-color: rgba(255, 255, 255, 0.8); +} +nav ul { + text-align: right; +} +.content li .options, +.content li .options input, +select { + text-align: center; +} +nav ul li { + padding-right: 12px; +} +.nav-spacer { + height: 96px; +} +.content { + padding: 0; + margin: 0; + display: flex; + flex-wrap: wrap; +} +#mkbInnerDiv, +#pdmInnerDiv, +#playbackInnerDiv, +#pscInnerDiv, +#ptmInnerDiv, +#statusInnerDiv, +#temperamentInnerDiv, +#timbreInnerDiv { + margin-left: 53px; + overflow-x: auto; +} +.content li { + display: block; + width: 23.75%; + float: left; + padding-left: 1%; +} +.content li[current="true"] img.thumbnail { + opacity: 0; +} +@media (max-width: 500px) { + .content li { + width: 48.5%; + padding-left: 1%; + } + .canvasHolder.hide { + transform: scale(0.485); + } + nav h1 { + display: none; + } +} +@media (max-width: 800px) and (min-width: 501px) { + .content li { + width: 32%; + padding-left: 1%; + } + .canvasHolder.hide { + transform: scale(0.32); + } +} +.content li img.thumbnail { + background: #96d3f3; + width: 100%; + padding: 0; +} +#planet-iframe { + width: 100vw; + height: 100vh; + background-color: #fff; + position: absolute; + top: 0; + left: 0; +} +.projectname { + word-wrap: break-word; +} +img.icon { + width: 30px; +} +img.icon:hover { + background-color: rgba(139, 195, 74, 0.8); +} +#loading-image-container { + z-index: 99999; +} +body { + background-color: #92b5c8 !important; + padding: 0; + margin: 0; +} +body.samples-shown { + overflow-y: scroll; + background: #fff !important; +} +select { + background-color: #88e20a; + font-weight: 700 !important; + resize: none !important; + padding: 0 !important; + border: 0 !important; + width: 20px; +} +input.boolean, +input.number, +input.text { + width: 100px; + font-weight: 700 !important; + padding: 0 !important; + border: 0 !important; + text-align: center; + resize: none !important; +} +input.text { + background-color: #ff5942 !important; +} +input.boolean { + background-color: #c96df3 !important; +} +input.number { + background-color: #ff5293 !important; +} +input.BPMInput, +input.dissectNumber, +input.musicratio1, +input.musicratio2 { + background-color: #8cc6ff !important; + text-align: center; + font-size: 24px; + font-weight: 700 !important; + resize: none !important; + padding: 0 !important; + border: 0 !important; + width: 100% !important; + height: 100% !important; +} +table { + border-collapse: separate; + border-spacing: 1px 1px; +} +#canvas { + overflow-y: visible; +} +#meterDiv, +#modeDiv, +#pdmDiv, +#playbackDiv, +#ptmDiv, +#statusDiv { + position: absolute; + top: 20%; + left: 20%; + background: rgba(255, 255, 255, 0.85) !important; +} +#meterTableDiv, +#modeTableDiv, +#pdmTableDiv, +#playbackTableDiv, +#ptmTableDiv, +#statusTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85) !important; + width: 680px; +} +#meterButtonsDiv, +#mkbButtonsDiv, +#modeButtonsDiv, +#pdmButtonsDiv, +#playbackButtonsDiv, +#ptmButtonsDiv, +#statusButtonsDiv, +#tempoButtonsDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85); +} +#mkbOuterDiv, +#pdmOuterDiv, +#playbackOuterDiv, +#ptmOuterDiv, +#statusOuterDiv { + position: absolute; + left: 0; + top: 0; + right: 5em; + overflow-y: auto; + overflow-x: none; + background: rgba(255, 255, 255, 0.85); +} +#mkbDiv { + position: absolute; + top: 0; + left: 0; + background: rgba(255, 255, 255, 0.85) !important; +} +#mkbTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85) !important; + width: 1020px; +} +#tempoDiv { + position: absolute; + top: 20%; + left: 20%; + background: rgba(255, 255, 255, 0.85) !important; + -webkit-user-select: none; +} +#helpDiv { + position: absolute; + top: 20%; + left: 20%; + width: 455px; + height: 375px; + background: #e8e8e8 !important; + -webkit-user-select: none; + border-radius: 5px; + box-shadow: 0 1px 10px #8080808f; +} +#right-arrow { + left: 410px; + background: url(../header-icons/right-arrow.png); +} +#left-arrow { + left: 5px; + background: url(../header-icons/left-arrow.png); +} +#left-arrow, +#right-arrow { + position: absolute; + top: 195px; + background-size: 40px; + height: 40px; + width: 40px; +} +.hover:hover { + cursor: pointer; +} +.top-wrapper { + width: 100%; + position: absolute; + top: 0; + background: #2196f3; + display: flex; + flex-direction: column; + justify-content: center; + color: #fff; + font-size: 1.1em; + text-align: center; + height: 55px; +} +.close-button { + position: absolute; + font-size: 1em; + right: 410px; + width: 18px; + height: 18px; + background: url(../header-icons/close.png); + background-size: 18px; + cursor: pointer; +} +.drag-button { + position: absolute; + right: 20px; + background: url(../header-icons/move.png); + background-size: 22px; + height: 22px; + width: 22px; + cursor: move; +} +#pscOuterDiv, +#rulerOuterDiv, +#sliderOuterDiv, +#temperamentOuterDiv, +#timbreOuterDiv { + right: 5em; + overflow-y: auto; + overflow-x: none; +} +#pscDiv, +#pscTableDiv, +#timbreDiv, +#timbreTableDiv { + background: rgba(255, 255, 255, 0.85) !important; +} +#helpDiv h1 { + text-align: left; + padding-left: 30px; + font-size: 1.5em; +} +#helpDiv p:not(:first-child) { + text-align: left; + padding-left: 30px; + font-size: 0.9em; + line-height: 20px; +} +#userEdit input, +.circle, +.headcol, +.labelcol, +.popup .popuptext, +.rangeslidervalue, +input.timbreName { + text-align: center; +} +#helpButtonsDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; +} +#helpBodyDiv { + position: relative; + left: 45px; + border: 0 !important; + overflow-x: hidden; + overflow-y: auto; + width: 365px; + height: 300px; + background: #e8e8e8 !important; +} +#pscDiv, +#timbreDiv { + position: absolute; + top: 20%; + left: 20%; +} +#pscTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + width: 680px; +} +#pscButtonsDiv, +#timbreButtonsDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85); +} +#pscOuterDiv, +#timbreOuterDiv { + position: absolute; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.85); +} +#timbreTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + width: 590px; +} +input.timbreName { + background-color: #8cc6ff !important; + font-size: 24px; + resize: none !important; + padding: 0 !important; + border: 0 !important; + width: 100% !important; + height: 100% !important; +} +#temperamentButtonsDiv, +#temperamentOuterDiv { + background: rgba(255, 255, 255, 0.85); + left: 0; + top: 0; +} +#temperamentDiv { + position: absolute; + top: 20%; + left: 20%; + background: rgba(255, 255, 255, 0.85) !important; +} +#temperamentTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(204, 0, 102, 0) !important; + width: 560px; +} +#temperamentButtonsDiv { + position: relative; + border: 0 !important; +} +#temperamentOuterDiv { + position: absolute; +} +#graph { + overflow-y: scroll; + height: 340px; +} +#userEdit input { + height: 40px; + width: 40px; + background: #8cc6ff; + border: 1px solid #000; +} +.popup, +.popupMsg { + background-color: #fff; +} +.popup { + position: absolute; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + height: 68px; + width: 160px; + border: 1px solid #000; +} +.popup .popuptext { + color: #fff; + border-radius: 6px; + position: absolute; + z-index: 1; +} +.popup .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +#download { + position: absolute; + top: 100px; + left: 200px; +} +#rulerDiv, +#sliderDiv { + position: absolute; + top: 20%; + left: 30%; + background: rgba(255, 255, 255, 0.85) !important; +} +#rulerTableDiv, +#sliderTableDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85) !important; + width: 680px; +} +#rulerButtonsDiv, +#sliderButtonsDiv { + position: relative; + left: 0; + top: 0; + border: 0 !important; + background: rgba(255, 255, 255, 0.85); +} +#rulerOuterDiv, +#sliderOuterDiv { + position: absolute; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.85); +} +#rulerInnerDiv { + overflow-x: auto !important; + margin-left: 53px; +} +#sliderInnerDiv { + overflow-x: auto; +} +.headcol { + position: absolute; + left: 1px; + vertical-align: middle; +} +.labelcol { + position: absolute; + top: auto; + vertical-align: middle; +} +#pitchstaircase, +#playPitch { + top: 20%; + border: 0 !important; + background: rgba(255, 255, 255, 0.85); + -webkit-user-select: none; + overflow-y: scroll !important; + position: absolute; +} +#pitchstaircase { + left: 30%; +} +#playPitch { + direction: rtl; + left: 25%; +} +#sliderInCell { + position: absolute; +} +#progressBar { + width: 1%; + height: 70px; + background-color: #4caf50; +} +.insideDivEnv { + margin-top: 10px; + height: 50px; + margin-left: 40px; +} +.insideDivFilter, +.insideDivOsc { + margin-top: -30px; + height: 50px; + margin-left: 40px; +} +.insideDivEffects, +.insideDivSynth { + margin-top: -30px; + height: 50px; + margin-left: 200px; +} +.btn { + background-color: #90c100; + margin-top: 6px; + height: 24px; + width: 60px; + border-color: #90c100; +} +.circle { + width: 40px; + height: 40px; + border-radius: 50%; + font-size: 25px; + color: #fff; + line-height: 40px; + background: #000; + float: left; +} +.rectangle { + border: 4px solid green; +} +#wrapperEnv0, +#wrapperEnv1, +#wrapperEnv2, +#wrapperEnv3 { + height: 50px; + margin-left: 30px; +} +.rangeslidervalue { + display: inline-block; + position: relative; + color: #00f; + background-color: #c8c8c8; + line-height: 20px; + border-radius: 10px; + border-color: green; + padding: 5px 10px; + margin-left: 8px; +} +.rangeslidervalue:after { + position: absolute; + top: 8px; + left: -7px; + width: 0; + height: 0; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + content: ""; +} +#selector0, +#selector1, +.filterselector { + margin-top: -50px; +} +#sel0, +#sel1, +.sel { + height: 35px; + width: 150px; + margin-left: 50px; + margin-top: 20px; +} +#wrapper0, +#wrapper1, +#wrapper2, +#wrapper3, +#wrapper4, +#wrapper5, +.wrapper { + margin-left: 170px; + height: 50px; +} +#s0, +#s1, +#s2, +#s3, +#s4, +#s5, +#sOsc0, +#sOsc1, +.s { + margin-left: -100px; + text-shadow: 0 2px 3px #555; + width: 100px; + font-weight: 700; + text-align: center; +} +#s0, +#s1, +#s2, +#s3, +#s4, +#s5, +.s { + color: #222; +} +#s0, +#sOsc0 { + margin-top: 30px; +} +#sOsc0, +#sOsc1 { + color: #222; +} +#wrapperOsc0, +#wrapperOsc1 { + margin-left: 170px; + height: 50px; +} +#selOsc { + margin-top: -50px; +} +#selOsc1 { + height: 35px; + width: 150px; + margin-left: 50px; + margin-top: 20px; +} +#sFx0, +#sFx1, +#sFx2, +#sS0, +#sS1 { + color: #222; + text-shadow: 0 2px 3px #555; + font-weight: 700; + width: 100px; + text-align: center; + margin-left: 60px; + margin-top: 20px; +} +#effect0, +#synth0 { + margin-left: 40px; + font-weight: 700; +} +#chosen { + margin-left: 20px; + font-style: italic; + font-weight: 700; +} +.wheelNav { + height: 350px; + width: 350px; + margin: auto; + -moz-transition: ease 1s; + -o-transition: ease 1s; + -webkit-transition: ease 1s; + transition: ease 1s; +} +.wheelNav > svg { + width: 100%; + height: 100%; +} +@media (max-width: 880px) { + .wheelNav { + height: 330px; + width: 330px; + } +} +@media (max-width: 680px) { + .wheelNav { + height: 310px; + width: 310px; + } +} +@media (max-width: 480px) { + .wheelNav { + height: 290px; + width: 290px; + } +} +.inactiveLink { + pointer-events: none !important; + cursor: default !important; +} +.popupMsg { + width: 1000px; + height: 30px; + position: absolute; + top: 130px; + left: 50%; + margin-left: -500px; + padding-top: 2px; + border-radius: 8px; + font-family: Arial, Helvetica, sans-serif; + font-size: 19px; + text-align: center; + text-overflow: ellipsis; + cursor: pointer; + visibility: hidden; +} +#printText { + border: 2px solid #969696; +} +#errorText { + border: 2px solid red; + background-color: pink; +} +#errorText.show, +#printText.show { + visibility: visible; +} +#errorTextContent, +#printTextContent { + display: inline-block; + width: 940px; + vertical-align: 7px; +} +.msgCloseIcon { + width: 28px; + height: 28px; + filter: invert(100%); +} diff --git a/dist/css/activity.css b/dist/css/activity.css index 02ea07f271..7657ec9b2f 100644 --- a/dist/css/activity.css +++ b/dist/css/activity.css @@ -1 +1,231 @@ -#popdown-palette{display:none;position:absolute;z-index:9999;top:0;left:0;width:100%;max-height:100%;overflow-y:scroll;background:hsla(0,0%,100%,.85)}#popdown-palette:last-child{margin-bottom:2.5em}#popdown-palette.show{display:block}#popdown-palette.show~.canvasHolder{filter:blur(10px);-webkit-filter:blur(10px)}#popdown-palette ul{display:none}#popdown-palette .palette.show ul{display:block}#popdown-palette li{list-style:none}#popdown-palette h2{border-bottom:1px solid #444;width:80%;padding:0 10%}#popdown-palette h2 span{vertical-align:60%}#popdown-palette h2 img{display:block;float:right}#popdown-palette .palette.show .show-button,#popdown-palette .palette:not(.show) .hide-button,#popdown-palette .palette:not(.show) .popout-button{display:none}div.back{display:block;position:fixed;height:2.5em;width:100%;top:calc(100% - 2.5em);background-color:#999}div.back h2{margin-top:.25em;border-bottom:none!important;color:#fff}div.back:active{background-color:#000}.canvasHolder{transition:all .75s ease;transform-origin:0 0;position:absolute;top:0;left:0}.canvasHolder.hide{transform:scale(.24);top:117px;left:1%;width:100vw;height:75vw;overflow:hidden;z-index:10;background:#9cf}.canvasHolder.hide canvas{width:100%;height:100%}nav{position:fixed;top:0;left:0;z-index:100;background-color:#8bc34a;height:64px;width:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);font:32px sans;vertical-align:middle;line-height:64px;color:#fff}nav .nav-container{padding:0 12px}nav .logo{padding-left:12px}nav h1{font-size:32px;position:relative;top:-12px;display:inline}nav img{height:48px;width:48px;margin-top:6px;border-radius:100%}nav imghover{background-color:hsla(0,0%,100%,.3)}nav imgactive{background-color:hsla(0,0%,100%,.8)}nav ul{list-style:none;text-align:right;display:inline}nav ul li{dispalay:inline;padding-right:12px;float:right}.nav-spacer{height:48px}.content{padding:0;margin:0}.content li{display:block;list-style:none;width:24%;float:left;padding-left:1%}.content li[current=true] img.thumbnail{opacity:0}@media (max-width:500px){.content li{width:49%;padding-left:1%}.canvasHolder.hide{transform:scale(.49)}nav h1{display:none}}@media (max-width:800px) and (min-width:501px){.content li{width:32%;padding-left:1%}.canvasHolder.hide{transform:scale(.32)}}.content li img.thumbnail{background:#96d3f3;width:100%;padding:0}.content li .options,.content li .options input{text-align:center}.planet-content{color:#727272}.planet-content h2{color:#212121;clear:both}img.icon{border-radius:100%;width:30px}img.icon:hover{background-color:rgba(139,195,74,.8)}#loading-image-container{z-index:99999}body{background-color:#9cf;padding:0;margin:0;font-family:sans-serif;overflow:hidden}body.samples-shown{overflow-y:scroll;background:#fff!important}input.text{background-color:#987aff}input.number,input.text{text-align:center;font-weight:700!important;resize:none!important;padding:0!important;border:0!important;width:100px}input.number{background-color:#f0f!important}.helpDiv{float:right;position:absolute;margin-top:57px;z-index:-1}#canvas{overflow-y:visible} \ No newline at end of file +#popdown-palette { + display: none; + position: absolute; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + max-height: 100%; + overflow-y: scroll; + background: hsla(0, 0%, 100%, 0.85); +} +#popdown-palette:last-child { + margin-bottom: 2.5em; +} +#popdown-palette.show { + display: block; +} +#popdown-palette.show ~ .canvasHolder { + filter: blur(10px); + -webkit-filter: blur(10px); +} +#popdown-palette ul { + display: none; +} +#popdown-palette .palette.show ul { + display: block; +} +#popdown-palette li { + list-style: none; +} +#popdown-palette h2 { + border-bottom: 1px solid #444; + width: 80%; + padding: 0 10%; +} +#popdown-palette h2 span { + vertical-align: 60%; +} +#popdown-palette h2 img { + display: block; + float: right; +} +#popdown-palette .palette.show .show-button, +#popdown-palette .palette:not(.show) .hide-button, +#popdown-palette .palette:not(.show) .popout-button { + display: none; +} +div.back { + display: block; + position: fixed; + height: 2.5em; + width: 100%; + top: calc(100% - 2.5em); + background-color: #999; +} +div.back h2 { + margin-top: 0.25em; + border-bottom: none !important; + color: #fff; +} +div.back:active { + background-color: #000; +} +.canvasHolder { + transition: all 0.75s ease; + transform-origin: 0 0; + position: absolute; + top: 0; + left: 0; +} +.canvasHolder.hide { + transform: scale(0.24); + top: 117px; + left: 1%; + width: 100vw; + height: 75vw; + overflow: hidden; + z-index: 10; + background: #9cf; +} +.canvasHolder.hide canvas { + width: 100%; + height: 100%; +} +nav { + position: fixed; + top: 0; + left: 0; + z-index: 100; + background-color: #8bc34a; + height: 64px; + width: 100%; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + font: 32px sans; + vertical-align: middle; + line-height: 64px; + color: #fff; +} +nav .nav-container { + padding: 0 12px; +} +nav .logo { + padding-left: 12px; +} +nav h1 { + font-size: 32px; + position: relative; + top: -12px; + display: inline; +} +nav img { + height: 48px; + width: 48px; + margin-top: 6px; + border-radius: 100%; +} +nav imghover { + background-color: hsla(0, 0%, 100%, 0.3); +} +nav imgactive { + background-color: hsla(0, 0%, 100%, 0.8); +} +nav ul { + list-style: none; + text-align: right; + display: inline; +} +nav ul li { + display: inline; + padding-right: 12px; + float: right; +} +.nav-spacer { + height: 48px; +} +.content { + padding: 0; + margin: 0; +} +.content li { + display: block; + list-style: none; + width: 24%; + float: left; + padding-left: 1%; +} +.content li[current="true"] img.thumbnail { + opacity: 0; +} +@media (max-width: 500px) { + .content li { + width: 49%; + padding-left: 1%; + } + .canvasHolder.hide { + transform: scale(0.49); + } + nav h1 { + display: none; + } +} +@media (max-width: 800px) and (min-width: 501px) { + .content li { + width: 32%; + padding-left: 1%; + } + .canvasHolder.hide { + transform: scale(0.32); + } +} +.content li img.thumbnail { + background: #96d3f3; + width: 100%; + padding: 0; +} +.content li .options, +.content li .options input { + text-align: center; +} +.planet-content { + color: #727272; +} +.planet-content h2 { + color: #212121; + clear: both; +} +img.icon { + border-radius: 100%; + width: 30px; +} +img.icon:hover { + background-color: rgba(139, 195, 74, 0.8); +} +#loading-image-container { + z-index: 99999; +} +body { + background-color: #9cf; + padding: 0; + margin: 0; + font-family: sans-serif; + overflow: hidden; +} +body.samples-shown { + overflow-y: scroll; + background: #fff !important; +} +input.text { + background-color: #987aff; +} +input.number, +input.text { + text-align: center; + font-weight: 700 !important; + resize: none !important; + padding: 0 !important; + border: 0 !important; + width: 100px; +} +input.number { + background-color: #f0f !important; +} +.helpDiv { + float: right; + position: absolute; + margin-top: 57px; + z-index: -1; +} +#canvas { + overflow-y: visible; +} diff --git a/dist/css/keyboard.css b/dist/css/keyboard.css index a74fd4c757..d95fb1b5d2 100644 --- a/dist/css/keyboard.css +++ b/dist/css/keyboard.css @@ -1 +1,55 @@ -#keyboard{height:135px;overflow-x:scroll;overflow-y:hidden;white-space:nowrap;border:1px solid #000;text-align:center;cursor:pointer;position:relative}table{table-layout:fixed}table.white{top:0;left:0;height:120px;border-spacing:0 0}table.black{position:absolute;border-collapse:separate;border-spacing:20px 0;height:60px;top:17px;left:30px}table.white>tbody>tr{position:relative}table.white>tbody>tr>td{min-width:80px;width:80px;max-width:80px;height:100%;vertical-align:bottom;border:1px solid #000}table.black>tbody>tr>td{min-width:60px;width:60px;max-width:60px;height:100%;vertical-align:bottom;border:1px solid #fff;background-color:#000;color:#fff;z-index:100}select.keySelect{background-color:#fff;display:inline-block;width:50px;border:1px solid #000!important} \ No newline at end of file +#keyboard { + height: 135px; + overflow-x: scroll; + overflow-y: hidden; + white-space: nowrap; + border: 1px solid #000; + text-align: center; + cursor: pointer; + position: relative; +} +table { + table-layout: fixed; +} +table.white { + top: 0; + left: 0; + height: 120px; + border-spacing: 0 0; +} +table.black { + position: absolute; + border-collapse: separate; + border-spacing: 20px 0; + height: 60px; + top: 17px; + left: 30px; +} +table.white > tbody > tr { + position: relative; +} +table.white > tbody > tr > td { + min-width: 80px; + width: 80px; + max-width: 80px; + height: 100%; + vertical-align: bottom; + border: 1px solid #000; +} +table.black > tbody > tr > td { + min-width: 60px; + width: 60px; + max-width: 60px; + height: 100%; + vertical-align: bottom; + border: 1px solid #fff; + background-color: #000; + color: #fff; + z-index: 100; +} +select.keySelect { + background-color: #fff; + display: inline-block; + width: 50px; + border: 1px solid #000 !important; +} diff --git a/dist/css/style.css b/dist/css/style.css index 205b74f4ce..616d33dba2 100644 --- a/dist/css/style.css +++ b/dist/css/style.css @@ -1,19 +1,106 @@ -input[type=range]{height:4px;-webkit-appearance:none;width:250px}input[type=range]:focus{outline:0}input[type=range]:not(.pitchSlider)::-webkit-slider-runnable-track{width:10px;height:11px;cursor:pointer;animation:.2s;box-shadow:1px 1px 1px #000;background:#90c100;border-radius:1px;border:0 solid #010101}input[type=range]:not(.pitchSlider)::-webkit-slider-thumb{box-shadow:1px 1px 1px #000031;border:1px solid #00001E;height:26px;width:26px;border-radius:15px;background:#00f;cursor:pointer;-webkit-appearance:none;margin-top:-8px}input[type=range]:not(.pitchSlider):focus::-webkit-slider-runnable-track{background:#90c100}input[type=range]:not(.pitchSlider)::-moz-range-track{width:100%;height:4px;cursor:pointer;animation:.2s;box-shadow:1px 1px 1px #000;background:#90C100;border-radius:1px;border:0 solid #010101}input[type=range]:not(.pitchSlider)::-moz-range-thumb{box-shadow:1px 1px 1px #000031;border:1px solid #00001E;height:26px;width:26px;border-radius:15px;background:#FFF;cursor:pointer}input[type=range]::-ms-track{width:100%;height:11px;cursor:pointer;animation:.2s;background:0 0;border-color:transparent;color:transparent}input[type=range]::-ms-fill-lower{background:#90c100;border:0 solid #010101;border-radius:2px;box-shadow:1px 1px 1px #000}input[type=range]::-ms-fill-upper{background:#90c100;border:0 solid #010101;border-radius:2px;box-shadow:1px 1px 1px #000}input[type=range]::-ms-thumb{margin-top:1px;box-shadow:1px 1px 1px #000031;border:1px solid #00001E;height:26px;width:26px;border-radius:15px;background:#FFF;cursor:pointer}input[type=range]:focus::-ms-fill-lower{background:#90c100}input[type=range]:focus::-ms-fill-upper{background:#90c100} -#ClearButton{ - right: 100px; - top: 132px; - background-color: white; - border: 2px solid red; - border-radius: 15px; - width: 200px; - height: 40px; - z-index: 100; - visibility: hidden; - display: flex; - justify-content: space-around; - align-items: center; -} -.clearPop{ - position: absolute; - cursor: pointer; -} \ No newline at end of file +input[type="range"] { + height: 4px; + -webkit-appearance: none; + width: 250px; +} +input[type="range"]:focus { + outline: 0; +} +input[type="range"]:not(.pitchSlider)::-webkit-slider-runnable-track { + width: 10px; + height: 11px; + cursor: pointer; + animation: 0.2s; + box-shadow: 1px 1px 1px #000; + background: #90c100; + border-radius: 1px; + border: 0 solid #010101; +} +input[type="range"]:not(.pitchSlider)::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000031; + border: 1px solid #00001e; + height: 26px; + width: 26px; + border-radius: 15px; + background: #00f; + cursor: pointer; + -webkit-appearance: none; + margin-top: -8px; +} +input[type="range"]:not(.pitchSlider):focus::-webkit-slider-runnable-track { + background: #90c100; +} +input[type="range"]:not(.pitchSlider)::-moz-range-track { + width: 100%; + height: 4px; + cursor: pointer; + animation: 0.2s; + box-shadow: 1px 1px 1px #000; + background: #90c100; + border-radius: 1px; + border: 0 solid #010101; +} +input[type="range"]:not(.pitchSlider)::-moz-range-thumb { + box-shadow: 1px 1px 1px #000031; + border: 1px solid #00001e; + height: 26px; + width: 26px; + border-radius: 15px; + background: #fff; + cursor: pointer; +} +input[type="range"]::-ms-track { + width: 100%; + height: 11px; + cursor: pointer; + animation: 0.2s; + background: 0 0; + border-color: transparent; + color: transparent; +} +input[type="range"]::-ms-fill-lower { + background: #90c100; + border: 0 solid #010101; + border-radius: 2px; + box-shadow: 1px 1px 1px #000; +} +input[type="range"]::-ms-fill-upper { + background: #90c100; + border: 0 solid #010101; + border-radius: 2px; + box-shadow: 1px 1px 1px #000; +} +input[type="range"]::-ms-thumb { + margin-top: 1px; + box-shadow: 1px 1px 1px #000031; + border: 1px solid #00001e; + height: 26px; + width: 26px; + border-radius: 15px; + background: #fff; + cursor: pointer; +} +input[type="range"]:focus::-ms-fill-lower { + background: #90c100; +} +input[type="range"]:focus::-ms-fill-upper { + background: #90c100; +} +#ClearButton { + right: 100px; + top: 132px; + background-color: white; + border: 2px solid red; + border-radius: 15px; + width: 200px; + height: 40px; + z-index: 100; + visibility: hidden; + display: flex; + justify-content: space-around; + align-items: center; +} +.clearPop { + position: absolute; + cursor: pointer; +} diff --git a/lib/materialize-iso.css b/lib/materialize-iso.css index 99fd0691b6..c8b25ae2d2 100644 --- a/lib/materialize-iso.css +++ b/lib/materialize-iso.css @@ -2545,7 +2545,7 @@ i.left { } @media only screen and (min-width: 601px) { .materialize-iso .container { - width: 85%; + width: 75%; } } @media only screen and (max-width: 400px) { @@ -3436,12 +3436,35 @@ i.left { } -@media only screen and (max-width: 400px) { +@media only screen and (max-width: 450px) { .materialize-iso .filler, .materialize-iso .logo { display: none; } + + .materialize-iso nav .main i.material-icons { + font-size: 20px; + position: relative; + margin-left: -5px; + margin-right: -5px; + padding: 0px; + } + + .materialize-iso nav .aux i.material-icons { + font-size: 17px; + position: relative; + margin-left: -7.5px; + margin-right: -7.5px; + padding: 0px; + } +} + + +@media only screen and (max-width: 400px) { + .materialize-iso .filler, .materialize-iso .logo { + display: block; + } .materialize-iso nav .main i.material-icons { - font-size: 20px; + font-size: 18px; position: relative; margin-left: -5px; margin-right: -5px; @@ -3449,7 +3472,7 @@ i.left { } .materialize-iso nav .aux i.material-icons { - font-size: 17px; + font-size: 16px; position: relative; margin-left: -7.5px; margin-right: -7.5px; @@ -3457,6 +3480,17 @@ i.left { } } +@media only screen and (min-width: 360px) and (max-width: 400px) { + .materialize-iso nav .main i.material-icons, + .materialize-iso nav .aux i.material-icons { + font-size: 19px; + position: relative; + margin-left: -4px; + margin-right: -4px; + padding: 0; + } +} + .materialize-iso nav .button-collapse { float: left; position: relative; From 5e234d778dc612f68a5a264a86e415157684a54e Mon Sep 17 00:00:00 2001 From: Muhammad Haroon <104259212+haroon10725@users.noreply.github.com> Date: Mon, 30 Dec 2024 19:23:20 +0500 Subject: [PATCH 08/19] update piemenus.js (#4211) --- js/piemenus.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/piemenus.js b/js/piemenus.js index 97d568ed59..1ec5187d27 100644 --- a/js/piemenus.js +++ b/js/piemenus.js @@ -1871,10 +1871,10 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { block._exitWheel.navItems[2].navigateFunction = () => { const cblk = that.connections[0]; if ( - that.value > 9 && + that.value >= 8 && (that.blocks.blockList[cblk].name === "pitch") ) { - that.value = 10; + that.value = 8; } else { that.value += 1; } From 6812208abdc9f907d9e2f11bb096b68124e35b06 Mon Sep 17 00:00:00 2001 From: omsuneri <142336291+omsuneri@users.noreply.github.com> Date: Tue, 31 Dec 2024 07:14:37 +0530 Subject: [PATCH 09/19] optimising the number selector in the note block octave (#4212) * optimising the number selector in the note block octave removing redundancy and optimising code * Removing extra Spaces * Removing extra Spaces * Removing extra Spaces * Removing extra Spaces --- js/piemenus.js | 66 +++++++++----------------------------------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/js/piemenus.js b/js/piemenus.js index 1ec5187d27..c7df75f46b 100644 --- a/js/piemenus.js +++ b/js/piemenus.js @@ -1635,23 +1635,18 @@ const piemenuNoteValue = (block, noteValue) => { const piemenuNumber = (block, wheelValues, selectedValue) => { // input form and wheelNav pie menu for number selection - if (block.blocks.stageClick) { return; } - docById("wheelDiv").style.display = ""; - // the number selector block._numberWheel = new wheelnav("wheelDiv", null, 600, 600); // exit button block._exitWheel = new wheelnav("_exitWheel", block._numberWheel.raphael); - const wheelLabels = []; for (let i = 0; i < wheelValues.length; i++) { wheelLabels.push(wheelValues[i].toString()); } - // spacer wheelLabels.push(null); @@ -1807,25 +1802,23 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { (Math.round(selectorWidth * block.blocks.blockScale) * block.protoblock.scale) / 2 + "px"; // Navigate to a the current number value. let i = wheelValues.indexOf(selectedValue); - if (i === -1) { - i = 0; + if (i === -1 || selectedValue < 1 || selectedValue > 8) { + selectedValue = Math.min(Math.max(selectedValue, 1), 8); + i = wheelValues.indexOf(selectedValue); } - - // In case of float value, navigate to the nearest integer + // In case of float value, navigate to the nearest integer within the range if (selectedValue % 1 !== 0) { - i = wheelValues.indexOf(Math.floor(selectedValue + 0.5)); + selectedValue = Math.min(Math.max(Math.floor(selectedValue + 0.5), 1), 8); + i = wheelValues.indexOf(selectedValue); } - if (i !== -1) { block._numberWheel.navigateWheel(i); } - block.label.style.fontSize = Math.round((20 * block.blocks.blockScale * block.protoblock.scale) / 2) + "px"; block.label.style.display = ""; block.label.focus(); - // Hide the widget when the selection is made. for (let i = 0; i < wheelLabels.length; i++) { block._numberWheel.navItems[i].navigateFunction = () => { @@ -1833,57 +1826,33 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { __exitMenu(); }; } - // Or use the exit wheel... block._exitWheel.navItems[0].navigateFunction = () => { __exitMenu(); }; - block._exitWheel.navItems[1].navigateFunction = () => { const cblk1 = that.connections[0]; - const cblk2 = that.blocks.blockList[cblk1].connections[0]; - - // Check if the number block is connected to a note value and prevent the value to go below zero - if ( - that.value < 1 && - (that.blocks.blockList[cblk1].name === "newnote" || - (cblk2 && that.blocks.blockList[cblk2].name == "newnote")) - ) { - that.value = 0; - } else if (that.value < 2 && - that.blocks.blockList[cblk1].name === "pitch" - ) { - that.value = 1; - } - else { + const cblk2 = that.blocks.blockList[cblk1]?.connections[0]; + // Decrease the value but ensure it does not go below 1 + if (that.value > 1) { that.value -= 1; } - that.text.text = that.value.toString(); - // Make sure text is on top. that.container.setChildIndex(that.text, that.container.children.length - 1); that.updateCache(); - that.label.value = that.value; }; - block._exitWheel.navItems[2].navigateFunction = () => { const cblk = that.connections[0]; - if ( - that.value >= 8 && - (that.blocks.blockList[cblk].name === "pitch") - ) { - that.value = 8; - } else { + // Increase the value but ensure it does not exceed 8 + if (that.value < 8) { that.value += 1; } that.text.text = that.value.toString(); - // Make sure text is on top. that.container.setChildIndex(that.text, that.container.children.length - 1); that.updateCache(); - that.label.value = that.value; }; @@ -1891,9 +1860,7 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { const label = that._numberWheel.navItems[that._numberWheel.selectedNavItemIndex].title; const i = wheelLabels.indexOf(label); const actualPitch = numberToPitch(wheelValues[i] + 3); - const tur = that.activity.turtles.ithTurtle(0); - if ( tur.singer.instrumentNames.length === 0 || !tur.singer.instrumentNames.includes(DEFAULTVOICE) @@ -1902,10 +1869,8 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { that.activity.logo.synth.createDefaultSynth(0); that.activity.logo.synth.loadSynth(0, DEFAULTVOICE); } - that.activity.logo.synth.setMasterVolume(PREVIEWVOLUME); Singer.setSynthVolume(that.activity.logo, 0, DEFAULTVOICE, PREVIEWVOLUME); - actualPitch[0] = actualPitch[0].replace(SHARP, "#").replace(FLAT, "b"); if (!that._triggerLock) { that._triggerLock = true; @@ -1918,7 +1883,6 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { null ); } - setTimeout(() => { that._triggerLock = false; }, 1 / 8); @@ -1930,9 +1894,7 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { const label = that._numberWheel.navItems[that._numberWheel.selectedNavItemIndex].title; const i = wheelLabels.indexOf(label); const actualPitch = frequencyToPitch(wheelValues[i]); - const tur = that.activity.turtles.ithTurtle(0); - if ( tur.singer.instrumentNames.length === 0 || !tur.singer.instrumentNames.includes(DEFAULTVOICE) @@ -1941,10 +1903,8 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { that.activity.logo.synth.createDefaultSynth(0); that.activity.logo.synth.loadSynth(0, DEFAULTVOICE); } - that.activity.logo.synth.setMasterVolume(PREVIEWVOLUME); Singer.setSynthVolume(that.activity.logo, 0, DEFAULTVOICE, PREVIEWVOLUME); - actualPitch[0] = actualPitch[0].replace(SHARP, "#").replace(FLAT, "b"); if (!that._triggerLock) { that._triggerLock = true; @@ -1957,14 +1917,11 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { null ); } - setTimeout(() => { that._triggerLock = false; }, 1 / 8); - __selectionChanged(); }; - // Handler for pitchnumber preview. Block is to ensure that // only pitchnumber block's pie menu gets a sound preview if ( @@ -1975,7 +1932,6 @@ const piemenuNumber = (block, wheelValues, selectedValue) => { block._numberWheel.navItems[i].navigateFunction = __pitchPreviewForNum; } } - // Handler for Hertz preview. Need to also ensure that // only hertz block gets a different sound preview if (block._usePieNumberC1() && block.blocks.blockList[block.connections[0]].name === "hertz") { From f0ac40612ab3a28796748b0b9615f1126093874f Mon Sep 17 00:00:00 2001 From: Nikhil <154296996+BeNikk@users.noreply.github.com> Date: Sat, 4 Jan 2025 03:09:14 +0530 Subject: [PATCH 10/19] Add Tests for RhythmBlocksAPI and DrumBlocksAPI in /js/js-exports/API (#4200) (#4208) * feat:Added api tests for RhythmBlocks and DrumBlocks * exp --- js/js-export/API/DrumBlocksAPI.js | 1 + js/js-export/API/RhythmBlocksAPI.js | 1 + .../API/__tests__/DrumBlocksAPI.test.js | 66 +++++++++ .../API/__tests__/RhythmBlocksAPI.test.js | 129 ++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 js/js-export/API/__tests__/DrumBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/RhythmBlocksAPI.test.js diff --git a/js/js-export/API/DrumBlocksAPI.js b/js/js-export/API/DrumBlocksAPI.js index 8fcc0ce73e..ee3549dce4 100644 --- a/js/js-export/API/DrumBlocksAPI.js +++ b/js/js-export/API/DrumBlocksAPI.js @@ -51,3 +51,4 @@ class DrumBlocksAPI { return this.runCommand("playNoise", [args[0], this.turIndex]); } } +module.exports=DrumBlocksAPI; diff --git a/js/js-export/API/RhythmBlocksAPI.js b/js/js-export/API/RhythmBlocksAPI.js index 1993eccb6e..68dafc2600 100644 --- a/js/js-export/API/RhythmBlocksAPI.js +++ b/js/js-export/API/RhythmBlocksAPI.js @@ -113,3 +113,4 @@ class RhythmBlocksAPI { return this.ENDFLOWCOMMAND; } } +module.exports=RhythmBlocksAPI; diff --git a/js/js-export/API/__tests__/DrumBlocksAPI.test.js b/js/js-export/API/__tests__/DrumBlocksAPI.test.js new file mode 100644 index 0000000000..a51b2b03a8 --- /dev/null +++ b/js/js-export/API/__tests__/DrumBlocksAPI.test.js @@ -0,0 +1,66 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; + +global.JSInterface = JSInterface; +global.MusicBlocks = { + BLK: "mockBlock", +}; + +const DrumBlocksAPI = require("../DrumBlocksAPI"); + +describe("DrumBlocksAPI", () => { + let drumBlocksAPI; + + beforeEach(() => { + drumBlocksAPI = new DrumBlocksAPI(); + drumBlocksAPI.turIndex = 0; + drumBlocksAPI.runCommand = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("playDrum calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["snare"]); + + drumBlocksAPI.playDrum("snare"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("playDrum", ["snare"]); + expect(drumBlocksAPI.runCommand).toHaveBeenCalledWith("playDrum", ["snare", 0, global.MusicBlocks.BLK]); + }); + + test("setDrum calls runCommand and executes flow function", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(["kick", mockFlow]); + + const result = await drumBlocksAPI.setDrum("kick", mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setDrum", ["kick", mockFlow]); + expect(drumBlocksAPI.runCommand).toHaveBeenCalledWith("setDrum", ["kick", 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(drumBlocksAPI.ENDFLOWCOMMAND); + }); + + test("mapPitchToDrum calls runCommand and executes flow function", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue(["tom", mockFlow]); + + const result = await drumBlocksAPI.mapPitchToDrum("tom", mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("mapPitchToDrum", ["tom", mockFlow]); + expect(drumBlocksAPI.runCommand).toHaveBeenCalledWith("mapPitchToDrum", ["tom", 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe(drumBlocksAPI.ENDFLOWCOMMAND); + }); + + test("playNoise calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["white"]); + + drumBlocksAPI.playNoise("white"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("playNoise", ["white"]); + expect(drumBlocksAPI.runCommand).toHaveBeenCalledWith("playNoise", ["white", 0]); + }); +}); diff --git a/js/js-export/API/__tests__/RhythmBlocksAPI.test.js b/js/js-export/API/__tests__/RhythmBlocksAPI.test.js new file mode 100644 index 0000000000..b8eda1f374 --- /dev/null +++ b/js/js-export/API/__tests__/RhythmBlocksAPI.test.js @@ -0,0 +1,129 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; + +global.MusicBlocks = { + BLK: "mockBLK" +}; + +const RhythmBlocksAPI = require("../RhythmBlocksAPI"); + +describe("RhythmBlocksAPI", () => { + let rhythmBlocksAPI; + + beforeEach(() => { + rhythmBlocksAPI = new RhythmBlocksAPI(); + rhythmBlocksAPI.turIndex = 0; + rhythmBlocksAPI.runCommand = jest.fn(); + rhythmBlocksAPI.ENDFLOWCOMMAND = 'END'; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("playNote calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([100, mockFlow]); + + const result = await rhythmBlocksAPI.playNote(100, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("playNote", [100, mockFlow]); + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("playNote", [100, "newnote", 0, "mockBLK"]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("playNoteMillis calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([1000, mockFlow]); + + const result = await rhythmBlocksAPI.playNoteMillis(1000, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("playNoteMillis", [1000, mockFlow]); + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("playNote", [1000, "osctime", 0, "mockBLK"]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("playRest calls runCommand with correct arguments", () => { + rhythmBlocksAPI.playRest(); + + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("playRest", [0]); + }); + + test("dot calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([1, mockFlow]); + + const result = await rhythmBlocksAPI.dot(1, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("dot", [1, mockFlow]); + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("doRhythmicDot", [1, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("tie calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([undefined, mockFlow]); // Changed to match implementation + + const result = await rhythmBlocksAPI.tie(mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("tie", [mockFlow]); + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("doTie", [0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("multiplyNoteValue calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([2, mockFlow]); + + const result = await rhythmBlocksAPI.multiplyNoteValue(2, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("multiplyNoteValue", [2, mockFlow]); + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("multiplyNoteValue", [2, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("swing calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([1, 4, mockFlow]); + + const result = await rhythmBlocksAPI.swing(1, 4, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("multiplyNoteValue", [1, 4, mockFlow]); // Keep original validation method + expect(rhythmBlocksAPI.runCommand).toHaveBeenCalledWith("addSwing", [1, 4, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("END"); + }); + + test("methods handle validation errors correctly", async () => { + JSInterface.validateArgs.mockImplementation(() => { + throw new Error("Invalid arguments"); + }); + + await expect(rhythmBlocksAPI.playNote()).rejects.toThrow("Invalid arguments"); + await expect(rhythmBlocksAPI.playNoteMillis()).rejects.toThrow("Invalid arguments"); + await expect(rhythmBlocksAPI.dot()).rejects.toThrow("Invalid arguments"); + await expect(rhythmBlocksAPI.tie()).rejects.toThrow("Invalid arguments"); + await expect(rhythmBlocksAPI.multiplyNoteValue()).rejects.toThrow("Invalid arguments"); + await expect(rhythmBlocksAPI.swing()).rejects.toThrow("Invalid arguments"); + }); + + test("methods handle command execution errors correctly", async () => { + JSInterface.validateArgs.mockReturnValue([1, jest.fn()]); + rhythmBlocksAPI.runCommand.mockRejectedValue(new Error("Command failed")); // Changed to handle async rejection + + await expect(rhythmBlocksAPI.playNote(1, jest.fn())).rejects.toThrow("Command failed"); + await expect(rhythmBlocksAPI.playNoteMillis(1, jest.fn())).rejects.toThrow("Command failed"); + await expect(rhythmBlocksAPI.playRest()).rejects.toThrow("Command failed"); // Added await + await expect(rhythmBlocksAPI.dot(1, jest.fn())).rejects.toThrow("Command failed"); + await expect(rhythmBlocksAPI.tie(jest.fn())).rejects.toThrow("Command failed"); + await expect(rhythmBlocksAPI.multiplyNoteValue(2, jest.fn())).rejects.toThrow("Command failed"); + await expect(rhythmBlocksAPI.swing(1, 4, jest.fn())).rejects.toThrow("Command failed"); + }); +}); From ba4ec7f3051568e33769daeeffe669921f617076 Mon Sep 17 00:00:00 2001 From: Abhay Agarwal <161469723+Abhay145@users.noreply.github.com> Date: Sat, 4 Jan 2025 03:32:41 +0530 Subject: [PATCH 11/19] Fix: Corrected MIDI pitch note addition bug (#4216) * Fix: Corrected MIDI pitch addition bug * Fix: Corrected MIDI pitch addition bug --- js/widgets/musickeyboard.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/js/widgets/musickeyboard.js b/js/widgets/musickeyboard.js index db1450c688..d65eeff7fa 100644 --- a/js/widgets/musickeyboard.js +++ b/js/widgets/musickeyboard.js @@ -1917,7 +1917,7 @@ function MusicKeyboard(activity) { this._createAddRowPieSubmenu = function () { docById("wheelDivptm").style.display = ""; // docById("wheelDivptm").style.zIndex = "300"; - const pitchLabels = ["do", "re", "mi", "fa", "sol", "la", "ti"]; + const pitchLabels = ["do", "do♯", "re", "re♯", "mi", "fa", "fa♯", "sol", "sol♯", "la", "la♯", "ti"]; const hertzLabels = [262, 294, 327, 348, 392, 436, 490, 523]; const VALUESLABEL = ["pitch", "hertz"]; const VALUES = ["imgsrc: images/chime.svg", "imgsrc: images/synth.svg"]; @@ -2022,7 +2022,10 @@ function MusicKeyboard(activity) { } } - rLabel = pitchLabels[(i + 1) % pitchLabels.length]; + do { + rLabel = pitchLabels[(i + 1) % pitchLabels.length]; + i = (i + 1) % pitchLabels.length; + } while (this.layout.some(note => note.noteName === rLabel)); for (let j = this.layout.length; j > 0; j--) { rArg = this.layout[j - 1].noteOctave; if (isNaN(rArg)) { @@ -2115,6 +2118,11 @@ function MusicKeyboard(activity) { this.displayLayout = this.displayLayout.concat(sortedHertzList); this._createKeyboard(); this._createTable(); + const n = this.layout.length; + const key = this.layout[n - 1]; + this.getElement[key.noteName.toString() + key.noteOctave.toString()] = key.objId; + this.getElement[FIXEDSOLFEGE1[key.noteName.toString()] + "" + key.noteOctave] = + key.objId; //convet solfege to alphabetic. }, 500); } else { // eslint-disable-next-line no-console From 009b300eae2f9e90c763cde829d257a9393e3e8d Mon Sep 17 00:00:00 2001 From: Justin Charles <143245796+justin212407@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:02:27 +0530 Subject: [PATCH 12/19] Added test files for GraphicBlocksAPI, VolumeBlocksAPI, OrnamentBlocksAPI (#4209) Signed-off-by: Justin Charles --- js/js-export/API/GraphicsBlocksAPI.js | 1 + js/js-export/API/OrnamentBlocksAPI.js | 1 + js/js-export/API/VolumeBlocksAPI.js | 1 + .../API/__tests__/GraphicsBlocksAPI.test.js | 148 ++++++++++++++++++ .../API/__tests__/OrnamentBlocksAPI.test.js | 62 ++++++++ .../API/__tests__/VolumeBlocksAPI.test.js | 85 ++++++++++ 6 files changed, 298 insertions(+) create mode 100644 js/js-export/API/__tests__/GraphicsBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/OrnamentBlocksAPI.test.js create mode 100644 js/js-export/API/__tests__/VolumeBlocksAPI.test.js diff --git a/js/js-export/API/GraphicsBlocksAPI.js b/js/js-export/API/GraphicsBlocksAPI.js index 07266f47f7..5ef523d182 100644 --- a/js/js-export/API/GraphicsBlocksAPI.js +++ b/js/js-export/API/GraphicsBlocksAPI.js @@ -86,3 +86,4 @@ class GraphicsBlocksAPI { return this.runCommand("doScrollXY", [args[0], args[1]]); } } +module.exports = GraphicsBlocksAPI; \ No newline at end of file diff --git a/js/js-export/API/OrnamentBlocksAPI.js b/js/js-export/API/OrnamentBlocksAPI.js index 40daca6e0b..1fad1f7468 100644 --- a/js/js-export/API/OrnamentBlocksAPI.js +++ b/js/js-export/API/OrnamentBlocksAPI.js @@ -48,3 +48,4 @@ class OrnamentBlocksAPI { return this.ENDFLOWCOMMAND; } } +module.exports = OrnamentBlocksAPI; \ No newline at end of file diff --git a/js/js-export/API/VolumeBlocksAPI.js b/js/js-export/API/VolumeBlocksAPI.js index cf29bfc7b3..072ff8bea9 100644 --- a/js/js-export/API/VolumeBlocksAPI.js +++ b/js/js-export/API/VolumeBlocksAPI.js @@ -58,3 +58,4 @@ class VolumeBlocksAPI { return Singer.VolumeActions.getSynthVolume(args[0], this.turIndex); } } +module.exports = VolumeBlocksAPI; \ No newline at end of file diff --git a/js/js-export/API/__tests__/GraphicsBlocksAPI.test.js b/js/js-export/API/__tests__/GraphicsBlocksAPI.test.js new file mode 100644 index 0000000000..af16340b04 --- /dev/null +++ b/js/js-export/API/__tests__/GraphicsBlocksAPI.test.js @@ -0,0 +1,148 @@ +const JSInterface = { + validateArgs: jest.fn(), + }; + global.JSInterface = JSInterface; + + global.globalActivity = { + turtles: { + ithTurtle: jest.fn(() => ({ name: "defaultDict" })), + }, + }; + + const GraphicsBlocksAPI = require("../GraphicsBlocksAPI"); + + describe("GraphicsBlocksAPI", () => { + let graphicsBlocksAPI; + + beforeEach(() => { + graphicsBlocksAPI = new GraphicsBlocksAPI(); + graphicsBlocksAPI.turIndex = 0; + graphicsBlocksAPI.runCommand = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("goForward calls runCommand with correct arguments", () => { + const steps = 5; + JSInterface.validateArgs.mockReturnValue([steps]); + + graphicsBlocksAPI.goForward(steps); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("goForward", [steps]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doForward", [steps]); + }); + + test("goBackward calls runCommand with correct arguments", () => { + const steps = 5; + JSInterface.validateArgs.mockReturnValue([steps]); + + graphicsBlocksAPI.goBackward(steps); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("goBackward", [steps]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doForward", [-steps]); + }); + + test("turnRight calls runCommand with correct arguments", () => { + const degrees = 90; + JSInterface.validateArgs.mockReturnValue([degrees]); + + graphicsBlocksAPI.turnRight(degrees); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("turnRight", [degrees]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doRight", [degrees]); + }); + + test("turnLeft calls runCommand with correct arguments", () => { + const degrees = 90; + JSInterface.validateArgs.mockReturnValue([degrees]); + + graphicsBlocksAPI.turnLeft(degrees); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("turnLeft", [degrees]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doRight", [-degrees]); + }); + + test("setXY calls runCommand with correct arguments", () => { + const x = 10; + const y = 20; + JSInterface.validateArgs.mockReturnValue([x, y]); + + graphicsBlocksAPI.setXY(x, y); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setXY", [x, y]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doSetXY", [x, y]); + }); + + test("setHeading calls runCommand with correct arguments", () => { + const degrees = 90; + JSInterface.validateArgs.mockReturnValue([degrees]); + + graphicsBlocksAPI.setHeading(degrees); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setHeading", [degrees]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doSetHeading", [degrees]); + }); + + test("drawArc calls runCommand with correct arguments", () => { + const degrees = 45; + const steps = 10; + JSInterface.validateArgs.mockReturnValue([degrees, steps]); + + graphicsBlocksAPI.drawArc(degrees, steps); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("drawArc", [degrees, steps]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doArc", [degrees, steps]); + }); + + test("drawBezier calls runCommand with correct arguments", () => { + const x = 15; + const y = 25; + JSInterface.validateArgs.mockReturnValue([x, y]); + + graphicsBlocksAPI.drawBezier(x, y); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("drawBezier", [x, y]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doBezier", [x, y]); + }); + + test("setBezierControlPoint1 calls runCommand with correct arguments", () => { + const x = 5; + const y = 10; + JSInterface.validateArgs.mockReturnValue([x, y]); + + graphicsBlocksAPI.setBezierControlPoint1(x, y); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setBezierControlPoint1", [x, y]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("setControlPoint1", [x, y]); + }); + + test("setBezierControlPoint2 calls runCommand with correct arguments", () => { + const x = 10; + const y = 15; + JSInterface.validateArgs.mockReturnValue([x, y]); + + graphicsBlocksAPI.setBezierControlPoint2(x, y); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setBezierControlPoint2", [x, y]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("setControlPoint2", [x, y]); + }); + + test("clear calls runCommand with correct arguments", () => { + graphicsBlocksAPI.clear(); + + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doClear", [true, true, true]); + }); + + test("scrollXY calls runCommand with correct arguments", () => { + const x = 10; + const y = 20; + JSInterface.validateArgs.mockReturnValue([x, y]); + + graphicsBlocksAPI.scrollXY(x, y); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("scrollXY", [x, y]); + expect(graphicsBlocksAPI.runCommand).toHaveBeenCalledWith("doScrollXY", [x, y]); + }); + }); \ No newline at end of file diff --git a/js/js-export/API/__tests__/OrnamentBlocksAPI.test.js b/js/js-export/API/__tests__/OrnamentBlocksAPI.test.js new file mode 100644 index 0000000000..d2034f9d09 --- /dev/null +++ b/js/js-export/API/__tests__/OrnamentBlocksAPI.test.js @@ -0,0 +1,62 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; + +const MusicBlocks = { + BLK: "MusicBlockTestValue", +}; +global.MusicBlocks = MusicBlocks; + +const OrnamentBlocksAPI = require("../OrnamentBlocksAPI"); + +describe("OrnamentBlocksAPI", () => { + let ornamentBlocksAPI; + + beforeEach(() => { + ornamentBlocksAPI = new OrnamentBlocksAPI(); + ornamentBlocksAPI.turIndex = 0; + ornamentBlocksAPI.runCommand = jest.fn(); + ornamentBlocksAPI.ENDFLOWCOMMAND = "endFlow"; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("setStaccato calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([true, mockFlow]); + + const result = await ornamentBlocksAPI.setStaccato(true, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setStaccato", [true, mockFlow]); + expect(ornamentBlocksAPI.runCommand).toHaveBeenCalledWith("setStaccato", [true, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); + + test("setSlur calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([5, mockFlow]); + + const result = await ornamentBlocksAPI.setSlur(5, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setSlur", [5, mockFlow]); + expect(ornamentBlocksAPI.runCommand).toHaveBeenCalledWith("setSlur", [5, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); + + test("doNeighbor calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([2, 3, mockFlow]); + + const result = await ornamentBlocksAPI.doNeighbor(2, 3, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("doNeighbor", [2, 3, mockFlow]); + expect(ornamentBlocksAPI.runCommand).toHaveBeenCalledWith("doNeighbor", [2, 3, 0, "MusicBlockTestValue"]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); +}); diff --git a/js/js-export/API/__tests__/VolumeBlocksAPI.test.js b/js/js-export/API/__tests__/VolumeBlocksAPI.test.js new file mode 100644 index 0000000000..4045c0370b --- /dev/null +++ b/js/js-export/API/__tests__/VolumeBlocksAPI.test.js @@ -0,0 +1,85 @@ +const JSInterface = { + validateArgs: jest.fn(), +}; +global.JSInterface = JSInterface; + +const Singer = { + VolumeActions: { + getSynthVolume: jest.fn(), + }, +}; +global.Singer = Singer; + +const VolumeBlocksAPI = require("../VolumeBlocksAPI"); + +describe("VolumeBlocksAPI", () => { + let volumeBlocksAPI; + + beforeEach(() => { + volumeBlocksAPI = new VolumeBlocksAPI(); + volumeBlocksAPI.turIndex = 0; + volumeBlocksAPI.runCommand = jest.fn().mockResolvedValue("Command executed"); + volumeBlocksAPI.ENDFLOWCOMMAND = "endFlow"; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test("doCrescendo calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([50, mockFlow]); + + const result = await volumeBlocksAPI.doCrescendo(50, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("doCrescendo", [50, mockFlow]); + expect(volumeBlocksAPI.runCommand).toHaveBeenCalledWith("doCrescendo", ["crescendo", 50, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); + + test("doDecrescendo calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([30, mockFlow]); + + const result = await volumeBlocksAPI.doDecrescendo(30, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("doDecrescendo", [30, mockFlow]); + expect(volumeBlocksAPI.runCommand).toHaveBeenCalledWith("doCrescendo", ["decrescendo", 30, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); + + test("setRelativeVolume calls runCommand with correct arguments", async () => { + const mockFlow = jest.fn(); + JSInterface.validateArgs.mockReturnValue([75, mockFlow]); + + const result = await volumeBlocksAPI.setRelativeVolume(75, mockFlow); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setRelativeVolume", [75, mockFlow]); + expect(volumeBlocksAPI.runCommand).toHaveBeenCalledWith("setRelativeVolume", [75, 0]); + expect(mockFlow).toHaveBeenCalled(); + expect(result).toBe("endFlow"); + }); + + test("setSynthVolume calls runCommand with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["synth1", 100]); + + const result = volumeBlocksAPI.setSynthVolume("synth1", 100); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("setSynthVolume", ["synth1", 100]); + expect(volumeBlocksAPI.runCommand).toHaveBeenCalledWith("setSynthVolume", ["synth1", 100, 0]); + expect(result).resolves.toBe("Command executed"); + }); + + test("getSynthVolume calls Singer.VolumeActions.getSynthVolume with correct arguments", () => { + JSInterface.validateArgs.mockReturnValue(["synth1"]); + Singer.VolumeActions.getSynthVolume.mockReturnValue(80); + + const result = volumeBlocksAPI.getSynthVolume("synth1"); + + expect(JSInterface.validateArgs).toHaveBeenCalledWith("getSynthVolume", ["synth1"]); + expect(Singer.VolumeActions.getSynthVolume).toHaveBeenCalledWith("synth1", 0); + expect(result).toBe(80); + }); +}); From 340a1d00b1e205de421f21fda6cb86da8d9ee78d Mon Sep 17 00:00:00 2001 From: Nikhil <154296996+BeNikk@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:03:10 +0530 Subject: [PATCH 13/19] fix: prevent helpfulWheel from appearing on block right-click (#4219) * fix: prevent helpfulWheel from appearing on block right-click * fix:created a general utility function to detect block clicks, updated the right click detection on blocks * removed trailing spaces --- js/activity.js | 10 +++++----- js/blocks.js | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/js/activity.js b/js/activity.js index 80fe79c855..f1967cd59c 100644 --- a/js/activity.js +++ b/js/activity.js @@ -510,11 +510,11 @@ class Activity { (event) => { event.preventDefault(); event.stopPropagation(); - if (!this.beginnerMode) { - if (event.target.id === "myCanvas") { - this._displayHelpfulWheel(event); - } - } + if (this.beginnerMode) return; + if (!this.blocks.isCoordinateOnBlock(event.clientX, event.clientY) && + event.target.id === "myCanvas") { + this._displayHelpfulWheel(event); + } }, false ); diff --git a/js/blocks.js b/js/blocks.js index 3e97110991..121c0db872 100644 --- a/js/blocks.js +++ b/js/blocks.js @@ -7036,5 +7036,25 @@ class Blocks { this.setSelectedBlocks = (blocks) => { this.selectedBlocks = blocks; }; + + /** + * Checks if coordinates intersect with any block + * @public + * @param {number} x - The x coordinate to check + * @param {number} y - The y coordinate to check + * @returns {boolean} True if coordinates intersect with a block + */ + this.isCoordinateOnBlock = function(x, y) { + return this.blockList.some(block => { + if (block.trash) return false; + + const blockX = block.container.x; + const blockY = block.container.y; + return x >= blockX && + x <= blockX + block.width && + y >= blockY && + y <= blockY + block.height; + }); + }; } } From 8ee8bb53fda4c0c7b0c4f04f7cbcd5ac4c706998 Mon Sep 17 00:00:00 2001 From: Diwangshu Kakoty <142284646+Commanderk3@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:08:26 +0530 Subject: [PATCH 14/19] Addition of lyrics through phase maker (#4174) * No clear space * Lyrics row in Phrase Maker * Addition of lyric row in phrase maker widget * update 2 * update 3 * final * formatting fix * fix 2 * final fix * lyrics row fixes * trailling space deleted * lyricsON is global * features added --- js/activity.js | 4 + js/blocks/ExtrasBlocks.js | 2 + js/blocks/WidgetBlocks.js | 1 + js/widgets/phrasemaker.js | 164 ++++++++++++++++++++++++++++++++++---- 4 files changed, 156 insertions(+), 15 deletions(-) diff --git a/js/activity.js b/js/activity.js index f1967cd59c..77a3c5f61f 100644 --- a/js/activity.js +++ b/js/activity.js @@ -269,6 +269,9 @@ class Activity { // Flag to check if the helpful search widget is active or not (for "click" event handler purpose) this.isHelpfulSearchWidgetOn = false; + //Flag to check if any other input box is active or not + this.isInputON = false; + this.beginnerMode = true; try { if (this.storage.beginnerMode === undefined) { @@ -2698,6 +2701,7 @@ class Activity { docById("lilypondModal").style.display === "block" || this.searchWidget.style.visibility === "visible" || this.helpfulSearchWidget.style.visibility === "visible" || + this.isInputON || docById("planet-iframe").style.display === "" || docById("paste").style.visibility === "visible" || docById("wheelDiv").style.display === "" || diff --git a/js/blocks/ExtrasBlocks.js b/js/blocks/ExtrasBlocks.js index 4a61fc96ab..909d117865 100644 --- a/js/blocks/ExtrasBlocks.js +++ b/js/blocks/ExtrasBlocks.js @@ -508,6 +508,8 @@ function setupExtrasBlocks(activity) { logo.oscilloscopeTurtles.indexOf(activity.turtles.turtleList[turtleIndex]) < 0 ) logo.oscilloscopeTurtles.push(activity.turtles.turtleList[turtleIndex]); + } else if (logo.inMatrix) { + logo.phraseMaker.lyricsON = true; } else if (!logo.inStatusMatrix) { if (args.length === 1) { if (args[0] !== null) { diff --git a/js/blocks/WidgetBlocks.js b/js/blocks/WidgetBlocks.js index d1b7f59152..da8971901d 100644 --- a/js/blocks/WidgetBlocks.js +++ b/js/blocks/WidgetBlocks.js @@ -1430,6 +1430,7 @@ function setupWidgetBlocks(activity) { logo.phraseMaker.rowArgs = []; logo.phraseMaker.graphicsBlocks = []; logo.phraseMaker.clearBlocks(); + logo.phraseMaker.lyricsON = false; logo.tupletRhythms = []; logo.tupletParams = []; diff --git a/js/widgets/phrasemaker.js b/js/widgets/phrasemaker.js index 7144eddcc1..7da9b6c7eb 100644 --- a/js/widgets/phrasemaker.js +++ b/js/widgets/phrasemaker.js @@ -250,6 +250,19 @@ class PhraseMaker { this.notesBlockMap = []; this._blockMapHelper = []; this.columnBlocksMap = []; + + /** + * Stores lyrics for each column. + * @type {Array} + * @private + */ + this._lyrics = []; + + /** + * Marks the presence of print block + * @type {boolean} + */ + this.lyricsON = false; } /** @@ -280,7 +293,7 @@ class PhraseMaker { * @type {NodeListOf} */ var windowFrameElements = floatingWindowsDiv.querySelectorAll(".windowFrame"); - + for (var i = 0; i < windowFrameElements.length; i++) { /** @@ -324,7 +337,7 @@ class PhraseMaker { * @type {number} */ var maxHeight = screenHeight * 0.8; - + if (totalWidth > screenWidth || totalHeight > screenHeight) { windowFrame.style.height = Math.min(totalHeight, maxHeight) + "px"; windowFrame.style.width = Math.min(totalWidth, maxWidth) + "px"; @@ -343,7 +356,7 @@ class PhraseMaker { } } } - + /** * Clears block references within the PhraseMaker. * Resets arrays used to track row and column blocks. @@ -503,7 +516,6 @@ class PhraseMaker { this._stopOrCloseClicked = true; this.activity.hideMsgs(); docById("wheelDivptm").style.display = "none"; - widgetWindow.destroy(); }; @@ -625,7 +637,8 @@ class PhraseMaker { drumName = getDrumName(this.rowLabels[i]); // Depending on the row, we choose a different background color. - if ( + if (this.rowLabels[i] === "print") break; + else if ( MATRIXGRAPHICS.indexOf(this.rowLabels[i]) != -1 || MATRIXGRAPHICS2.indexOf(this.rowLabels[i]) != -1 ) { @@ -652,7 +665,8 @@ class PhraseMaker { cell.innerHTML = ""; this._headcols[i] = cell; - if (drumName != null) { + if (this.rowLabels[i] === "print") break; + else if (drumName != null) { cell.innerHTML = '   this._lyrics.length) { + const additionalLength = this.activity.logo.tupletRhythms.length - this._lyrics.length; + this._lyrics = this._lyrics.concat(Array(additionalLength).fill("")); + } + for (let i = 0; i < this.activity.logo.tupletRhythms.length; i++) { + const noteValue = this.activity.logo.tupletRhythms[i][2]; + const inputCell = inputRow.insertCell(); + inputCell.style.height = Math.floor(MATRIXSOLFEHEIGHT * this._cellScale) + 1 + "px"; + inputCell.style.width = this._noteWidth(noteValue) + "px"; + inputCell.style.minWidth = inputCell.style.width; + inputCell.style.maxWidth = inputCell.style.width; + inputCell.style.backgroundColor = "#FF6EA1"; + inputCell.style.fontFamily = "sans-serif"; + inputCell.style.cursor = "default"; + inputCell.style.borderSpacing = "1px 1px"; + inputCell.style.borderCollapse = "collapse"; + inputCell.style.boxSizing = "border-box"; + inputCell.style.padding = "0"; + inputCell.style.borderRadius = "6px"; + inputCell.style.border = "none"; + inputCell.setAttribute("alt", i + "__" + "graphicsblocks2"); + + const lyricsInput = document.createElement("input"); + lyricsInput.type = "text"; + lyricsInput.value = this._lyrics[i]; + + lyricsInput.style.height = inputCell.style.height; + lyricsInput.style.width = "100%"; + lyricsInput.style.minWidth = inputCell.style.minWidth; + lyricsInput.style.maxWidth = inputCell.style.maxWidth; + lyricsInput.style.fontSize = "inherit"; + lyricsInput.style.fontFamily = "sans-serif"; + lyricsInput.style.cursor = "default"; + lyricsInput.style.boxSizing = "border-box"; + lyricsInput.style.padding = "0"; + lyricsInput.style.border = "none"; + lyricsInput.style.borderRadius = "6px"; + lyricsInput.style.backgroundColor = "#FF6EA1"; + + inputCell.appendChild(lyricsInput); + lyricsInput.addEventListener("focus", () => this.activity.isInputON = true); + lyricsInput.addEventListener("blur", () => this.activity.isInputON = false); + lyricsInput.addEventListener("input", (event) => { + this._lyrics[i] = event.target.value; + }); + + }; + lyricsRow.insertCell().appendChild(tempTable); + } + // An extra row for the note and tuplet values ptmTableRow = ptmTable.insertRow(); ptmCell = ptmTableRow.insertCell(); @@ -953,6 +1044,7 @@ class PhraseMaker { tempTable = document.createElement("table"); tempTable.setAttribute("cellpadding", "0px"); this._tupletNoteValueRow = tempTable.insertRow(); + const tempTable2 = tempTable; this._tupletValueRow = tempTable.insertRow(); this._noteValueRow = tempTable.insertRow(); ptmTableRow.insertCell().append(tempTable); @@ -3464,7 +3556,7 @@ class PhraseMaker { this._restartGrid.call(this); } - + /** * Deletes a note from the grid and readjusts the notes accordingly. * @param {number} noteToDivide - The index of the note to delete. @@ -4507,6 +4599,10 @@ class PhraseMaker { * @param {number} noteCounter - The current note index in the playback sequence. */ __playNote(time, noteCounter) { + // Show lyrics while playing notes. + if (this.lyricsON) { + this.activity.textMsg(this._lyrics[noteCounter]); + } // If the widget is closed, stop playing. if (!this.widgetWindow.isVisible()) { return; @@ -4879,7 +4975,16 @@ class PhraseMaker { * @private */ _clear() { - // 'Unclick' every entry in the matrix. + // Reset the `_lyrics` array + this._lyrics = Array(this._lyrics.length).fill(""); + const lyricsRow = document.getElementById("lyricRow"); + if (lyricsRow) { + const inputFields = lyricsRow.querySelectorAll("input[type='text']"); + inputFields.forEach((inputField, index) => { + inputField.value = this._lyrics[index] || ""; + }); + } + // 'Unclick' every entry in the matrix let row, cell; for (let i = 0; i < this.rowLabels.length; i++) { row = this._rows[i]; @@ -4894,6 +4999,7 @@ class PhraseMaker { } } + /** * Saves the current matrix state as an action stack consisting of note and pitch blocks. * @private @@ -5036,7 +5142,7 @@ class PhraseMaker { if (obj === null) { // add a hertz block // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 2; @@ -5061,7 +5167,7 @@ class PhraseMaker { } else if (drumName != null) { // add a playdrum block // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 2; @@ -5086,7 +5192,7 @@ class PhraseMaker { } else if (note[0][j].slice(0, 4) === "http") { // add a playdrum block with URL // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 2; @@ -5111,7 +5217,7 @@ class PhraseMaker { } else if (obj.length > 2) { // add a 2-arg graphics block // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 3; @@ -5143,7 +5249,7 @@ class PhraseMaker { } else if (obj.length > 1) { // add a 1-arg graphics block // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 2; @@ -5168,7 +5274,7 @@ class PhraseMaker { } else { // add a pitch block // The last connection in last pitch block is null. - if (note[0].length === 1 || j === note[0].length - 1) { + if (!this.lyricsON && (note[0].length === 1 || j === note[0].length - 1)) { lastConnection = null; } else { lastConnection = thisBlock + 3; @@ -5348,6 +5454,34 @@ class PhraseMaker { } } } + if (this.lyricsON) { + newStack.push([ + thisBlock, + "print", + 0, + 0, + [previousBlock, thisBlock + 1, null] + ]); + previousBlock = thisBlock; + thisBlock += 1; + if (this._lyrics[i] && this._lyrics !== "") { + newStack.push([ + thisBlock, + ["text", { value: this._lyrics[i] }], + 0, + 0, + [previousBlock] + ]); + } else { + newStack.push([ + thisBlock, + ["text", { value: "..." }], + 0, + 0, + [previousBlock] + ]); + } + } } } From fd71cb8d18645d52d4a762ff066d3248ea313ec9 Mon Sep 17 00:00:00 2001 From: omsuneri <142336291+omsuneri@users.noreply.github.com> Date: Sun, 5 Jan 2025 18:46:25 +0530 Subject: [PATCH 15/19] Adding test for the Turtleactions (#4227) --- js/turtleactions/DictActions.js | 1 + js/turtleactions/OrnamentActions.js | 1 + .../__tests__/DictActions.test.js | 88 +++++++++++++++++++ .../__tests__/OrnamentActions.test.js | 82 +++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 js/turtleactions/__tests__/DictActions.test.js create mode 100644 js/turtleactions/__tests__/OrnamentActions.test.js diff --git a/js/turtleactions/DictActions.js b/js/turtleactions/DictActions.js index 599262e528..894a2b7a30 100644 --- a/js/turtleactions/DictActions.js +++ b/js/turtleactions/DictActions.js @@ -264,3 +264,4 @@ function setupDictActions(activity) { } }; } +module.exports = setupDictActions; \ No newline at end of file diff --git a/js/turtleactions/OrnamentActions.js b/js/turtleactions/OrnamentActions.js index b8d21505e2..d29a783537 100644 --- a/js/turtleactions/OrnamentActions.js +++ b/js/turtleactions/OrnamentActions.js @@ -129,3 +129,4 @@ function setupOrnamentActions(activity) { } }; } +module.exports = setupOrnamentActions; \ No newline at end of file diff --git a/js/turtleactions/__tests__/DictActions.test.js b/js/turtleactions/__tests__/DictActions.test.js new file mode 100644 index 0000000000..1f02417989 --- /dev/null +++ b/js/turtleactions/__tests__/DictActions.test.js @@ -0,0 +1,88 @@ +const setupDictActions = require('../DictActions'); +describe('setupDictActions', () => { + let activity; + let turtle; + let targetTurtle; + + beforeAll(() => { + global.Turtle = { + DictActions: {} + }; + + global._ = jest.fn((key) => key); + }); + + beforeEach(() => { + activity = { + turtles: { + ithTurtle: jest.fn(), + screenX2turtleX: jest.fn(), + screenY2turtleY: jest.fn(), + }, + logo: { + turtleDicts: {} + }, + textMsg: jest.fn() + }; + + turtle = 0; + targetTurtle = { + painter: { + color: 'red', + value: 10, + chroma: 0.5, + pensize: 2, + font: 'Arial', + orientation: 90, + doSetColor: jest.fn(), + doSetValue: jest.fn(), + doSetChroma: jest.fn(), + doSetPensize: jest.fn(), + doSetFont: jest.fn(), + doSetHeading: jest.fn(), + doSetXY: jest.fn() + }, + container: { + x: 100, + y: 200 + }, + singer: { + notesPlayed: [1, 2], + lastNotePlayed: ['C4'], + notePitches: ['C'], + noteOctaves: [4], + keySignature: 'C', + movable: true, + pitchNumberOffset: 0 + } + }; + activity.turtles.ithTurtle.mockReturnValue(targetTurtle); + activity.turtles.screenX2turtleX.mockReturnValue(100); + activity.turtles.screenY2turtleY.mockReturnValue(200); + setupDictActions(activity); + }); + + it('should set the turtle color correctly', () => { + Turtle.DictActions.SetDictValue(0, turtle, 'color', 'blue'); + expect(targetTurtle.painter.doSetColor).toHaveBeenCalledWith('blue'); + }); + + it('should get the turtle color correctly', () => { + const color = Turtle.DictActions._GetDict(0, turtle, 'color'); + expect(color).toBe('red'); + }); + + it('should return error message if dictionary does not exist', () => { + activity.logo.turtleDicts[turtle] = {}; + const result = Turtle.DictActions.getValue('nonexistentDict', 'color', turtle); + expect(result).toBe('Dictionary with this name does not exist'); + }); + + it('should set and get values in the turtle dictionary', () => { + activity.logo.turtleDicts[turtle] = {}; + Turtle.DictActions.setValue('customDict', 'color', 'green', turtle); + expect(activity.logo.turtleDicts[turtle].customDict.color).toBe('green'); + const value = Turtle.DictActions.getValue('customDict', 'color', turtle); + expect(value).toBe('green'); + }); +}); diff --git a/js/turtleactions/__tests__/OrnamentActions.test.js b/js/turtleactions/__tests__/OrnamentActions.test.js new file mode 100644 index 0000000000..49f3c4f92a --- /dev/null +++ b/js/turtleactions/__tests__/OrnamentActions.test.js @@ -0,0 +1,82 @@ +const setupOrnamentActions = require('../OrnamentActions'); +describe('OrnamentActions', () => { + let activity, turtleMock; + + beforeEach(() => { + global.Singer = { + OrnamentActions: null, + }; + + turtleMock = { + singer: { + staccato: [], + justCounting: [], + inNeighbor: [], + neighborStepPitch: [], + neighborNoteValue: [], + }, + }; + + activity = { + turtles: { + ithTurtle: jest.fn(() => turtleMock), + }, + blocks: { + blockList: { 1: {} }, + }, + logo: { + setDispatchBlock: jest.fn(), + setTurtleListener: jest.fn(), + notation: { + notationBeginSlur: jest.fn(), + notationEndSlur: jest.fn(), + }, + }, + }; + + global.MusicBlocks = { isRun: true }; + global.Mouse = { + getMouseFromTurtle: jest.fn(() => ({ + MB: { listeners: [] }, + })), + }; + setupOrnamentActions(activity); + }); + + test('setStaccato sets up staccato properly', () => { + Singer.OrnamentActions.setStaccato(2, 0, 1); + expect(turtleMock.singer.staccato).toContain(1 / 2); + expect(activity.logo.setDispatchBlock).toHaveBeenCalledWith(1, 0, '_staccato_0'); + expect(activity.logo.setTurtleListener).toHaveBeenCalledWith( + 0, + '_staccato_0', + expect.any(Function) + ); + }); + + test('setSlur sets up slur properly', () => { + Singer.OrnamentActions.setSlur(2, 0, 1); + expect(turtleMock.singer.staccato).toContain(-1 / 2); + expect(activity.logo.notation.notationBeginSlur).toHaveBeenCalledWith(0); + expect(activity.logo.setDispatchBlock).toHaveBeenCalledWith(1, 0, '_staccato_0'); + expect(activity.logo.setTurtleListener).toHaveBeenCalledWith( + 0, + '_staccato_0', + expect.any(Function) + ); + }); + + test('doNeighbor sets up neighbor action properly', () => { + Singer.OrnamentActions.doNeighbor(3, 4, 0, 1); + expect(turtleMock.singer.inNeighbor).toContain(1); + expect(turtleMock.singer.neighborStepPitch).toContain(3); + expect(turtleMock.singer.neighborNoteValue).toContain(4); + expect(activity.logo.setDispatchBlock).toHaveBeenCalledWith(1, 0, '_neighbor_0_1'); + expect(activity.logo.setTurtleListener).toHaveBeenCalledWith( + 0, + '_neighbor_0_1', + expect.any(Function) + ); + }); +}); + From dbca10688dcd8a1608c160f57d12f991b994bbf4 Mon Sep 17 00:00:00 2001 From: Mondal <63331895+Mondalgithub@users.noreply.github.com> Date: Sun, 5 Jan 2025 18:51:26 +0530 Subject: [PATCH 16/19] Add click event listener to close helpful wheel when clicking outside (#4224) --- js/activity.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/activity.js b/js/activity.js index 77a3c5f61f..37ca13d0f3 100644 --- a/js/activity.js +++ b/js/activity.js @@ -573,6 +573,15 @@ class Activity { wheel.navItems[i].setTooltip(_(ele.label)); wheel.navItems[i].navigateFunction = () => ele.fn(this); }) + const closeHelpfulWheel = (e) => { + const isClickInside = helpfulWheelDiv.contains(e.target); + if (!isClickInside) { + helpfulWheelDiv.style.display = "none"; + document.removeEventListener("click", closeHelpfulWheel); + } + }; + + document.addEventListener("click", closeHelpfulWheel); } /** From ed3b1897ceebc8384fd0c2801d16db9eaefed7bb Mon Sep 17 00:00:00 2001 From: red-panda3 Date: Sun, 5 Jan 2025 18:56:53 +0530 Subject: [PATCH 17/19] readme update (#4188) --- po/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/README.md b/po/README.md index ee21431f77..769708f33f 100644 --- a/po/README.md +++ b/po/README.md @@ -3,7 +3,7 @@ Internationalization We are using PO files as the basic mechanism for managing translation of Music Blocks. We'd prefer that translators work with the Sugar -Labs [Pootle server](http://translate.sugarlabs.org/projects/MusicBlocks/) and +Labs [Pootle server]( https://weblate.sugarlabs.org) and we will work with you to set up a PO file for your language if one is not presently on the server. Also feel free to make Pull Requests directly to this repository with updates to existing (or new) PO From 9a9088dc2ab2cd738e13e256e9fb59fdea7292b0 Mon Sep 17 00:00:00 2001 From: Tanish Yelgoe <143334319+tanishy7777@users.noreply.github.com> Date: Sun, 5 Jan 2025 18:58:25 +0530 Subject: [PATCH 18/19] Clarify Instructions for Running Local Server in README.md (#4186) * Update README.md for more clarity * Update README.md --- README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8996db07b7..adddee717a 100644 --- a/README.md +++ b/README.md @@ -103,9 +103,11 @@ Linux systems, the `python3` command is not bound to python. You may need to perform a `sudo apt install python-is-python3` on Debian-like distros, or equivalent on others.) -4. After cloning the musicblocks repository, run +4. After cloning the musicblocks repository, you can choose one of two methods to start a local server: using Python or using npm - for _Linux_ and _macOS_: + **Using Python** + + for _Linux_ and _macOS_: ```bash python -c "import os, sys; os.system('python -m SimpleHTTPServer 3000 --bind 127.0.0.1') if sys.version_info.major==2 else os.system('python -m http.server 3000 --bind 127.0.0.1')" @@ -117,17 +119,29 @@ distros, or equivalent on others.) python -c "import os, sys; os.system('python -m SimpleHTTPServer 3000') if sys.version_info.major==2 else os.system('python -m http.server 3000 --bind 127.0.0.1')" ``` - If you have `npm` installed, simply run `npm run serve` for Linux - and macOS, and `npm run winserve` for Windows. + + **Using npm** + + for _Linux_ and _macOS_: + + ```bash + npm run serve + ``` + + for _Windows_: + + ```bash + npm run winserve + ``` **NOTE:** _Make sure you can run either `python` or `py` from your terminal, to launch the Python prompt._ -5. You should see a message `Serving HTTP on 127.0.0.1 port 3000 +6. You should see a message `Serving HTTP on 127.0.0.1 port 3000 (http://127.0.0.1:3000/) ...` since the HTTP Server is set to start listening on port 3000. -6. Open your favorite browser and visit `localhost:3000` or `127.0.0.1:3000`. +7. Open your favorite browser and visit `localhost:3000` or `127.0.0.1:3000`. **NOTE:** _Use `ctrl + c` or `cmd + c` to quit the HTTP Server to avoid `socket.error:[Errno 48]`_. From b020cb8b2af4171b1247b22d990825172f4c0c79 Mon Sep 17 00:00:00 2001 From: Nikhil <154296996+BeNikk@users.noreply.github.com> Date: Mon, 6 Jan 2025 00:24:54 +0530 Subject: [PATCH 19/19] Fix ReferenceError for module.exports in browser environment (#4229) --- js/js-export/API/DictBlocksAPI.js | 5 +- js/js-export/API/DrumBlocksAPI.js | 4 +- js/js-export/API/GraphicsBlocksAPI.js | 4 +- js/js-export/API/IntervalsBlocksAPI.js | 4 +- js/js-export/API/MeterBlocksAPI.js | 5 +- js/js-export/API/OrnamentBlocksAPI.js | 4 +- js/js-export/API/PenBlocksAPI.js | 4 +- js/js-export/API/PitchBlocksAPI.js | 4 +- js/js-export/API/RhythmBlocksAPI.js | 4 +- js/js-export/API/ToneBlocksAPI.js | 4 +- js/js-export/API/VolumeBlocksAPI.js | 4 +- js/utils/mathutils.js | 4 +- js/utils/munsell.js | 4 +- js/utils/musicutils.js | 171 +++++++++++++------------ 14 files changed, 126 insertions(+), 99 deletions(-) diff --git a/js/js-export/API/DictBlocksAPI.js b/js/js-export/API/DictBlocksAPI.js index 899c83b098..5bffeb9263 100644 --- a/js/js-export/API/DictBlocksAPI.js +++ b/js/js-export/API/DictBlocksAPI.js @@ -51,5 +51,6 @@ class DictBlocksAPI { return this.runCommand("getValue", [args[1], args[0], this.turIndex]); } } - -module.exports = DictBlocksAPI; \ No newline at end of file +if (typeof module !== 'undefined' && module.exports) { + module.exports = DictBlocksAPI; +} \ No newline at end of file diff --git a/js/js-export/API/DrumBlocksAPI.js b/js/js-export/API/DrumBlocksAPI.js index ee3549dce4..d92d7c7411 100644 --- a/js/js-export/API/DrumBlocksAPI.js +++ b/js/js-export/API/DrumBlocksAPI.js @@ -51,4 +51,6 @@ class DrumBlocksAPI { return this.runCommand("playNoise", [args[0], this.turIndex]); } } -module.exports=DrumBlocksAPI; +if (typeof module !== 'undefined' && module.exports) { + module.exports=DrumBlocksAPI; +} diff --git a/js/js-export/API/GraphicsBlocksAPI.js b/js/js-export/API/GraphicsBlocksAPI.js index 5ef523d182..5c33fca8cf 100644 --- a/js/js-export/API/GraphicsBlocksAPI.js +++ b/js/js-export/API/GraphicsBlocksAPI.js @@ -86,4 +86,6 @@ class GraphicsBlocksAPI { return this.runCommand("doScrollXY", [args[0], args[1]]); } } -module.exports = GraphicsBlocksAPI; \ No newline at end of file +if (typeof module !== 'undefined' && module.exports) { + module.exports = GraphicsBlocksAPI; +} \ No newline at end of file diff --git a/js/js-export/API/IntervalsBlocksAPI.js b/js/js-export/API/IntervalsBlocksAPI.js index 9ad3d719da..d733f5464b 100644 --- a/js/js-export/API/IntervalsBlocksAPI.js +++ b/js/js-export/API/IntervalsBlocksAPI.js @@ -58,4 +58,6 @@ class IntervalsBlocksAPI { return this.runCommand("setTemperament", [args[0], args[1], args[2]]); } } -module.exports = IntervalsBlocksAPI; +if (typeof module !== 'undefined' && module.exports) { + module.exports = IntervalsBlocksAPI; +} diff --git a/js/js-export/API/MeterBlocksAPI.js b/js/js-export/API/MeterBlocksAPI.js index 66ce847982..df08678d58 100644 --- a/js/js-export/API/MeterBlocksAPI.js +++ b/js/js-export/API/MeterBlocksAPI.js @@ -74,6 +74,7 @@ class MeterBlocksAPI { return Singer.MeterActions.getNotesPlayed(args[0], this.turIndex); } } +if (typeof module !== 'undefined' && module.exports) { + module.exports = MeterBlocksAPI; +} - -module.exports = MeterBlocksAPI; diff --git a/js/js-export/API/OrnamentBlocksAPI.js b/js/js-export/API/OrnamentBlocksAPI.js index 1fad1f7468..bcaa382f3d 100644 --- a/js/js-export/API/OrnamentBlocksAPI.js +++ b/js/js-export/API/OrnamentBlocksAPI.js @@ -48,4 +48,6 @@ class OrnamentBlocksAPI { return this.ENDFLOWCOMMAND; } } -module.exports = OrnamentBlocksAPI; \ No newline at end of file +if (typeof module !== 'undefined' && module.exports) { + module.exports = OrnamentBlocksAPI; +} \ No newline at end of file diff --git a/js/js-export/API/PenBlocksAPI.js b/js/js-export/API/PenBlocksAPI.js index b46cc8676f..5449c936e8 100644 --- a/js/js-export/API/PenBlocksAPI.js +++ b/js/js-export/API/PenBlocksAPI.js @@ -99,4 +99,6 @@ class PenBlocksAPI { return this.runCommand("doSetFont", [args[0]]); } } -module.exports = PenBlocksAPI; +if (typeof module !== 'undefined' && module.exports) { + module.exports = PenBlocksAPI; +} diff --git a/js/js-export/API/PitchBlocksAPI.js b/js/js-export/API/PitchBlocksAPI.js index ea786e2da4..d62d15f836 100644 --- a/js/js-export/API/PitchBlocksAPI.js +++ b/js/js-export/API/PitchBlocksAPI.js @@ -179,4 +179,6 @@ class PitchBlocksAPI { return Singer.PitchActions.numToPitch(args[0], "octave", this.turIndex); } } -module.exports = PitchBlocksAPI; +if (typeof module !== 'undefined' && module.exports) { + module.exports = PitchBlocksAPI; +} diff --git a/js/js-export/API/RhythmBlocksAPI.js b/js/js-export/API/RhythmBlocksAPI.js index 68dafc2600..0dbb1c2275 100644 --- a/js/js-export/API/RhythmBlocksAPI.js +++ b/js/js-export/API/RhythmBlocksAPI.js @@ -113,4 +113,6 @@ class RhythmBlocksAPI { return this.ENDFLOWCOMMAND; } } -module.exports=RhythmBlocksAPI; +if (typeof module !== 'undefined' && module.exports) { + module.exports=RhythmBlocksAPI; +} diff --git a/js/js-export/API/ToneBlocksAPI.js b/js/js-export/API/ToneBlocksAPI.js index f7fe4d420a..8847c685e2 100644 --- a/js/js-export/API/ToneBlocksAPI.js +++ b/js/js-export/API/ToneBlocksAPI.js @@ -129,4 +129,6 @@ class ToneBlocksAPI { return this.ENDFLOWCOMMAND; } } -module.exports = ToneBlocksAPI; \ No newline at end of file +if (typeof module !== 'undefined' && module.exports) { + module.exports = ToneBlocksAPI; +} \ No newline at end of file diff --git a/js/js-export/API/VolumeBlocksAPI.js b/js/js-export/API/VolumeBlocksAPI.js index 072ff8bea9..0e5aa44723 100644 --- a/js/js-export/API/VolumeBlocksAPI.js +++ b/js/js-export/API/VolumeBlocksAPI.js @@ -58,4 +58,6 @@ class VolumeBlocksAPI { return Singer.VolumeActions.getSynthVolume(args[0], this.turIndex); } } -module.exports = VolumeBlocksAPI; \ No newline at end of file +if (typeof module !== 'undefined' && module.exports) { + module.exports = VolumeBlocksAPI; +} \ No newline at end of file diff --git a/js/utils/mathutils.js b/js/utils/mathutils.js index 073bf6924a..7c0a94eea2 100644 --- a/js/utils/mathutils.js +++ b/js/utils/mathutils.js @@ -326,4 +326,6 @@ class MathUtility { } } // Ensure mathutils.js exports the MathUtility class -module.exports = MathUtility; +if (typeof module !== 'undefined' && module.exports) { + module.exports = MathUtility; +} diff --git a/js/utils/munsell.js b/js/utils/munsell.js index 056245929c..2397fd0cfc 100644 --- a/js/utils/munsell.js +++ b/js/utils/munsell.js @@ -6858,7 +6858,9 @@ let searchColors = (r, g, b) => { return nearestColor; }; -module.exports = {interpColor, getMunsellColor, getcolor, searchColors}; +if (typeof module !== 'undefined' && module.exports) { + module.exports = {interpColor, getMunsellColor, getcolor, searchColors}; +} // /** // * @deprecated // * @param {number} r - intensity of red diff --git a/js/utils/musicutils.js b/js/utils/musicutils.js index 1cfd2a0e20..689497b225 100644 --- a/js/utils/musicutils.js +++ b/js/utils/musicutils.js @@ -5887,87 +5887,90 @@ const getPitchInfo = (activity, type, currentNote, tur) => { console.debug("Waiting for note to play"); } }; -module.exports = { - updateTemperaments, - scaleDegreeToPitchMapping, - buildScale, - getNote, - getModeLength, - nthDegreeToPitch - ,getInterval, - _calculate_pitch_number, - _getStepSize, - reducedFraction, - toFraction, - durationToNoteValue, - calcNoteValueToDisplay, - noteToPitchOctave, - pitchToFrequency, - noteIsSolfege, - getSolfege, - splitSolfege, - i18nSolfege, - splitScaleDegree, - getNumNote, - calcOctave, - calcOctaveInterval, - isInt, - convertFromSolfege, - convertFactor, - getPitchInfo, - noteToFrequency, - TEMPERAMENT, - setOctaveRatio, - getOctaveRatio, - TEMPERAMENT, - TEMPERAMENTS, - INITIALTEMPERAMENTS, - PreDefinedTemperaments, - getTemperamentsList, - getTemperament, - getTemperamentKeys, - addTemperamentToList, - deleteTemperamentFromList, - addTemperamentToDictionary, - updateTemperaments, - - DEFAULTINVERT, - DEFAULTMODE, - customMode, - getInvertMode, - getIntervalNumber, - getIntervalDirection, - getIntervalRatio, - - getModeNumbers, - getDrumIndex, - getDrumName, - getDrumSymbol, - getFilterTypes, - getOscillatorTypes, - getDrumIcon, - getDrumSynthName, - getNoiseName, - getNoiseIcon, - getNoiseSynthName, - getVoiceName, - getVoiceIcon, - getVoiceSynthName, - isCustomTemperament, - getTemperamentName, - noteToObj, - frequencyToPitch, - getArticulation, - keySignatureToMode, - getScaleAndHalfSteps, - modeMapper, - getSharpFlatPreference, - getCustomNote, - pitchToNumber, - numberToPitchSharp, - getNumber, - getNoteFromInterval, - numberToPitch, - GetNotesForInterval, - base64Encode -}; +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + updateTemperaments, + scaleDegreeToPitchMapping, + buildScale, + getNote, + getModeLength, + nthDegreeToPitch + ,getInterval, + _calculate_pitch_number, + _getStepSize, + reducedFraction, + toFraction, + durationToNoteValue, + calcNoteValueToDisplay, + noteToPitchOctave, + pitchToFrequency, + noteIsSolfege, + getSolfege, + splitSolfege, + i18nSolfege, + splitScaleDegree, + getNumNote, + calcOctave, + calcOctaveInterval, + isInt, + convertFromSolfege, + convertFactor, + getPitchInfo, + noteToFrequency, + TEMPERAMENT, + setOctaveRatio, + getOctaveRatio, + TEMPERAMENT, + TEMPERAMENTS, + INITIALTEMPERAMENTS, + PreDefinedTemperaments, + getTemperamentsList, + getTemperament, + getTemperamentKeys, + addTemperamentToList, + deleteTemperamentFromList, + addTemperamentToDictionary, + updateTemperaments, + + DEFAULTINVERT, + DEFAULTMODE, + customMode, + getInvertMode, + getIntervalNumber, + getIntervalDirection, + getIntervalRatio, + + getModeNumbers, + getDrumIndex, + getDrumName, + getDrumSymbol, + getFilterTypes, + getOscillatorTypes, + getDrumIcon, + getDrumSynthName, + getNoiseName, + getNoiseIcon, + getNoiseSynthName, + getVoiceName, + getVoiceIcon, + getVoiceSynthName, + isCustomTemperament, + getTemperamentName, + noteToObj, + frequencyToPitch, + getArticulation, + keySignatureToMode, + getScaleAndHalfSteps, + modeMapper, + getSharpFlatPreference, + getCustomNote, + pitchToNumber, + numberToPitchSharp, + getNumber, + getNoteFromInterval, + numberToPitch, + GetNotesForInterval, + base64Encode + }; +} +