@@ -522,69 +522,78 @@ class SoundEditor extends React.Component {
522
522
{ name : "Cancel" , callback : ( ) => audio . close ( ) } ,
523
523
) ;
524
524
525
- menu . setAttribute ( "style" , "margin: 0 10px 15px 10px;position: relative;display: flex;justify-content: flex-end;flex-direction: row;height: calc(100% - (3.125em + 2.125em + 16px));align-items: center;" ) ;
526
- menu . append ( pitchDiv , volumeDiv ) ;
527
-
528
- const previewButton = document . createElement ( "button" ) ;
529
- previewButton . style = "border-radius: 1000px;padding: 5px;width: 45px;height: 45px;margin-right: 10px;border-style: none;background: #00c3ff;" ;
530
- previewButton . innerHTML = `<img draggable="false" style="max-width: 100%;max-height: 100%" src="${ playURI } ">` ;
531
- menu . append ( previewButton ) ;
532
-
533
- // preview functionality
534
- // create an audio buffer using the selection
535
- const properBuffer = audio . createBuffer ( 1 , bufferSelection . samples . length , bufferSelection . sampleRate ) ;
536
- properBuffer . getChannelData ( 0 ) . set ( bufferSelection . samples ) ;
537
-
538
- let bufferSource , audioPlaying = false ;
539
- function play ( ) {
540
- bufferSource = audio . createBufferSource ( ) ;
541
- bufferSource . connect ( gainNode ) ;
542
- bufferSource . buffer = properBuffer ;
543
- bufferSource . start ( 0 ) ;
544
- bufferSource . detune . value = pitchParts [ 1 ] . value * 10 ;
545
- previewButton . innerHTML = `<img draggable="false" style="max-width: 100%;max-height: 100%" src="${ stopURI } ">` ;
546
- audioPlaying = true ;
547
- bufferSource . onended = ( ) => {
548
- previewButton . firstChild . src = playURI ;
525
+ const modalHandler = ( ) => {
526
+ menu . setAttribute ( "style" , "margin: 0 10px 15px 10px;position: relative;display: flex;justify-content: flex-end;flex-direction: row;height: calc(100% - (3.125em + 2.125em + 16px));align-items: center;" ) ;
527
+ menu . append ( pitchDiv , volumeDiv ) ;
528
+
529
+ const previewButton = document . createElement ( "button" ) ;
530
+ previewButton . style = "border-radius: 1000px;padding: 5px;width: 45px;height: 45px;margin-right: 10px;border-style: none;background: #00c3ff;" ;
531
+ previewButton . innerHTML = `<img draggable="false" style="max-width: 100%;max-height: 100%" src="${ playURI } ">` ;
532
+ menu . append ( previewButton ) ;
533
+
534
+ // preview functionality
535
+ // create an audio buffer using the selection
536
+ const properBuffer = audio . createBuffer ( 1 , bufferSelection . samples . length , bufferSelection . sampleRate ) ;
537
+ properBuffer . getChannelData ( 0 ) . set ( bufferSelection . samples ) ;
538
+
539
+ let bufferSource , audioPlaying = false ;
540
+ function play ( ) {
541
+ bufferSource = audio . createBufferSource ( ) ;
542
+ bufferSource . connect ( gainNode ) ;
543
+ bufferSource . buffer = properBuffer ;
544
+ bufferSource . start ( 0 ) ;
545
+ bufferSource . detune . value = pitchParts [ 1 ] . value * 10 ;
546
+ previewButton . innerHTML = `<img draggable="false" style="max-width: 100%;max-height: 100%" src="${ stopURI } ">` ;
547
+ audioPlaying = true ;
548
+ bufferSource . onended = ( ) => {
549
+ previewButton . firstChild . src = playURI ;
550
+ audioPlaying = false ;
551
+ }
552
+ }
553
+ function stop ( ) {
554
+ bufferSource . stop ( ) ;
555
+ previewButton . firstChild . src = stopURI ;
549
556
audioPlaying = false ;
550
557
}
551
- }
552
- function stop ( ) {
553
- bufferSource . stop ( ) ;
554
- previewButton . firstChild . src = stopURI ;
555
- audioPlaying = false ;
556
- }
557
- previewButton . onclick = ( ) => {
558
- if ( audioPlaying ) stop ( ) ;
559
- else play ( ) ;
560
- }
558
+ previewButton . onclick = ( ) => {
559
+ if ( audioPlaying ) stop ( ) ;
560
+ else play ( ) ;
561
+ }
561
562
562
- // slider/number updates
563
- const pSlider = pitchParts [ 1 ] ;
564
- const pNumber = pitchParts [ 2 ] ;
565
- pSlider . onchange = ( updateValue ) => {
566
- if ( updateValue !== false ) pNumber . value = Number ( pSlider . value ) ;
567
- if ( bufferSource ) bufferSource . detune . value = pSlider . value * 10 ;
568
- }
569
- pSlider . oninput = pSlider . onchange ;
570
- pNumber . onchange = ( ) => {
571
- pSlider . value = pNumber . value ;
572
- pSlider . onchange ( false ) ;
573
- } ;
574
- pNumber . oninput = pNumber . onchange ;
563
+ // slider/number updates
564
+ const pSlider = pitchParts [ 1 ] ;
565
+ const pNumber = pitchParts [ 2 ] ;
566
+ pSlider . onchange = ( updateValue ) => {
567
+ if ( updateValue !== false ) pNumber . value = Number ( pSlider . value ) ;
568
+ if ( bufferSource ) bufferSource . detune . value = pSlider . value * 10 ;
569
+ }
570
+ pSlider . oninput = pSlider . onchange ;
571
+ pNumber . onchange = ( ) => {
572
+ pSlider . value = pNumber . value ;
573
+ pSlider . onchange ( false ) ;
574
+ } ;
575
+ pNumber . oninput = pNumber . onchange ;
575
576
576
- const vSlider = volumeParts [ 1 ] ;
577
- const vNumber = volumeParts [ 2 ] ;
578
- vSlider . onchange = ( updateValue ) => {
579
- gainNode . gain . value = vSlider . value ;
580
- if ( updateValue !== false ) vNumber . value = Number ( vSlider . value ) * 100 ;
581
- }
582
- vSlider . oninput = vSlider . onchange ;
583
- vNumber . onchange = ( ) => {
584
- vSlider . value = vNumber . value / 100 ;
585
- vSlider . onchange ( false ) ;
577
+ const vSlider = volumeParts [ 1 ] ;
578
+ const vNumber = volumeParts [ 2 ] ;
579
+ vSlider . onchange = ( updateValue ) => {
580
+ gainNode . gain . value = vSlider . value ;
581
+ if ( updateValue !== false ) vNumber . value = Number ( vSlider . value ) * 100 ;
582
+ }
583
+ vSlider . oninput = vSlider . onchange ;
584
+ vNumber . onchange = ( ) => {
585
+ vSlider . value = vNumber . value / 100 ;
586
+ vSlider . onchange ( false ) ;
587
+ } ;
588
+ vNumber . oninput = vNumber . onchange ;
586
589
} ;
587
- vNumber . oninput = vNumber . onchange ;
590
+
591
+ // account for weird react timing issue
592
+ if ( menu ) modalHandler ( ) ;
593
+ else queueMicrotask ( ( ) => {
594
+ menu = document . querySelector ( `div[class="ReactModalPortal"] div[class*="prompt_body_"] div` ) ;
595
+ modalHandler ( ) ;
596
+ } ) ;
588
597
}
589
598
590
599
handleFormatMenu ( ) {
@@ -617,7 +626,7 @@ class SoundEditor extends React.Component {
617
626
] ;
618
627
let selectedSampleRate = this . props . sampleRate ;
619
628
let selectedForceRate = false ;
620
- const menu = window . ScratchBlocks . customPrompt (
629
+ let menu = window . ScratchBlocks . customPrompt (
621
630
"Format Sound" , { width : 350 , height : "auto" } ,
622
631
{
623
632
name : "Apply" , callback : ( ) => {
@@ -629,50 +638,59 @@ class SoundEditor extends React.Component {
629
638
{ name : "Cancel" , callback : ( ) => { } } ,
630
639
) ;
631
640
632
- menu . style . marginBottom = "15px" ;
633
- const rateTitle = genTitle ( "New Sample Rate:" ) ;
634
-
635
- const rateSelector = document . createElement ( "select" ) ;
636
- rateSelector . style = "border-radius: 5px;text-align: center;margin-left: 10px;width: 50%;" ;
637
- for ( const rate of sampleRates ) {
638
- const option = document . createElement ( "option" ) ;
639
- option . value = rate ;
640
- option . textContent = rate ;
641
- rateSelector . append ( option ) ;
642
- }
643
- rateSelector . selectedIndex = sampleRates . indexOf ( this . props . sampleRate ) ;
644
- rateSelector . onchange = ( ) => {
645
- selectedSampleRate = rateSelector . value ;
641
+ const modalHandler = ( ) => {
642
+ menu . style . marginBottom = "15px" ;
643
+ const rateTitle = genTitle ( "New Sample Rate:" ) ;
644
+
645
+ const rateSelector = document . createElement ( "select" ) ;
646
+ rateSelector . style = "border-radius: 5px;text-align: center;margin-left: 10px;width: 50%;" ;
647
+ for ( const rate of sampleRates ) {
648
+ const option = document . createElement ( "option" ) ;
649
+ option . value = rate ;
650
+ option . textContent = rate ;
651
+ rateSelector . append ( option ) ;
652
+ }
653
+ rateSelector . selectedIndex = sampleRates . indexOf ( this . props . sampleRate ) ;
654
+ rateSelector . onchange = ( ) => {
655
+ selectedSampleRate = rateSelector . value ;
656
+ } ;
657
+ rateTitle . appendChild ( rateSelector ) ;
658
+
659
+ const warningDiv = document . createElement ( "div" ) ;
660
+ warningDiv . style . marginBottom = "15px" ;
661
+ const warning = document . createElement ( "i" ) ;
662
+ warning . textContent = "Choosing a higher sample rate than the current rate will not make the existing audio higher quality" ;
663
+ warning . style = "font-size:13px;opacity:0.5;" ;
664
+ warningDiv . appendChild ( warning ) ;
665
+
666
+ const warningDiv2 = warning . cloneNode ( true ) ;
667
+ warningDiv2 . textContent = "If 'whole sound' is selected, all added audio will use the new sample rate" ;
668
+
669
+ const applicatorDiv = document . createElement ( "div" ) ;
670
+ applicatorDiv . append (
671
+ genCheckableLabel ( "this selection" , "0" , true ) ,
672
+ genCheckableLabel ( "whole sound" , "1" , false )
673
+ ) ;
674
+ applicatorDiv . addEventListener ( "click" , ( e ) => {
675
+ const div = e . target . closest ( `div[class="check-outer"]` ) ;
676
+ if ( ! div ) return ;
677
+
678
+ for ( const checkable of Array . from ( div . parentNode . children ) ) {
679
+ checkable . firstChild . checked = false ;
680
+ }
681
+ div . firstChild . checked = true ;
682
+ selectedForceRate = div . id == "1" ;
683
+ e . stopPropagation ( ) ;
684
+ } ) ;
685
+ menu . append ( rateTitle , warningDiv , genTitle ( "Apply to:" ) , applicatorDiv , warningDiv2 ) ;
646
686
} ;
647
- rateTitle . appendChild ( rateSelector ) ;
648
-
649
- const warningDiv = document . createElement ( "div" ) ;
650
- warningDiv . style . marginBottom = "15px" ;
651
- const warning = document . createElement ( "i" ) ;
652
- warning . textContent = "Choosing a higher sample rate than the current rate will not make the existing audio higher quality" ;
653
- warning . style = "font-size:13px;opacity:0.5;" ;
654
- warningDiv . appendChild ( warning ) ;
655
-
656
- const warningDiv2 = warning . cloneNode ( true ) ;
657
- warningDiv2 . textContent = "If 'whole sound' is selected, all added audio will use the new sample rate" ;
658
-
659
- const applicatorDiv = document . createElement ( "div" ) ;
660
- applicatorDiv . append (
661
- genCheckableLabel ( "this selection" , "0" , true ) ,
662
- genCheckableLabel ( "whole sound" , "1" , false )
663
- ) ;
664
- applicatorDiv . addEventListener ( "click" , ( e ) => {
665
- const div = e . target . closest ( `div[class="check-outer"]` ) ;
666
- if ( ! div ) return ;
667
687
668
- for ( const checkable of Array . from ( div . parentNode . children ) ) {
669
- checkable . firstChild . checked = false ;
670
- }
671
- div . firstChild . checked = true ;
672
- selectedForceRate = div . id == "1" ;
673
- e . stopPropagation ( ) ;
688
+ // account for weird react timing issue
689
+ if ( menu ) modalHandler ( ) ;
690
+ else queueMicrotask ( ( ) => {
691
+ menu = document . querySelector ( `div[class="ReactModalPortal"] div[class*="prompt_body_"] div` ) ;
692
+ modalHandler ( ) ;
674
693
} ) ;
675
- menu . append ( rateTitle , warningDiv , genTitle ( "Apply to:" ) , applicatorDiv , warningDiv2 ) ;
676
694
}
677
695
render ( ) {
678
696
const { effectTypes } = AudioEffects ;
0 commit comments