@@ -21,7 +21,6 @@ import DragConstants from '../lib/drag-constants';
21
21
import defineDynamicBlock from '../lib/define-dynamic-block' ;
22
22
import AddonHooks from '../addons/hooks' ;
23
23
import LoadScratchBlocksHOC from '../lib/tw-load-scratch-blocks-hoc.jsx' ;
24
- import uid from "../lib/uid.js" ;
25
24
26
25
import { connect } from 'react-redux' ;
27
26
import { updateToolbox } from '../reducers/toolbox' ;
@@ -77,7 +76,6 @@ const addFunctionListener = (object, property, callback) => {
77
76
return result ;
78
77
} ;
79
78
} ;
80
- const isObject = ( value ) => value && typeof value === 'object' && ! Array . isArray ( value ) ;
81
79
82
80
const DroppableBlocks = DropAreaHOC ( [
83
81
DragConstants . BACKPACK_CODE
@@ -145,12 +143,10 @@ class Blocks extends React.Component {
145
143
this . ScratchBlocks . recordSoundCallback = this . handleOpenSoundRecorder ;
146
144
147
145
this . state = {
148
- prompt : null ,
149
- customPrompts : [ ] ,
146
+ prompt : null
150
147
} ;
151
148
this . onTargetsUpdate = debounce ( this . onTargetsUpdate , 100 ) ;
152
149
this . toolboxUpdateQueue = [ ] ;
153
- this . customModalRefs = new Map ( ) ;
154
150
}
155
151
componentDidMount ( ) {
156
152
this . props . vm . setCompilerOptions ( {
@@ -240,8 +236,6 @@ class Blocks extends React.Component {
240
236
shouldComponentUpdate ( nextProps , nextState ) {
241
237
return (
242
238
this . state . prompt !== nextState . prompt ||
243
- this . state . customPrompts !== nextState . customPrompts ||
244
- ( nextState . customPrompts && this . state . customPrompts . length !== nextState . customPrompts . length ) ||
245
239
this . props . isVisible !== nextProps . isVisible ||
246
240
this . _renderedToolboxXML !== nextProps . toolboxXML ||
247
241
this . props . extensionLibraryVisible !== nextProps . extensionLibraryVisible ||
@@ -617,49 +611,46 @@ class Blocks extends React.Component {
617
611
p . prompt . showCloudOption = ( optVarType === this . ScratchBlocks . SCALAR_VARIABLE_TYPE ) && this . props . canUseCloud ;
618
612
this . setState ( p ) ;
619
613
}
620
- handleCustomPrompt ( config , styles , enterInfo , closeInfo ) {
621
- return new Promise ( ( resolve , reject ) => {
622
- /* validate arguments */
623
- if ( config && isObject ( config ) ) {
624
- if ( ! config . title ) return reject ( "Custom Modal -- Missing 'title' (string) property in Param 1" ) ;
625
- } else {
626
- return reject ( "Custom Modal -- Param 1 must be an object with at least properties: 'title' (string)" ) ;
627
- }
628
- if ( styles && ! isObject ( styles ) ) {
629
- return reject ( "Custom Modal -- Param 2 must be an object" ) ;
630
- }
631
- if ( styles && ( ! styles . content && ! styles . overlay ) ) {
632
- return reject ( "Custom Modal -- If Param 2 is specified, specify CSS styles within either: 'content' or 'overlay'" ) ;
633
- }
634
- if ( isObject ( enterInfo ) ) {
635
- if ( ! enterInfo . name || ! enterInfo . callback ) return reject ( "Custom Modal -- Missing name/callback property in Param 3" ) ;
636
- if ( enterInfo . callback && typeof enterInfo . callback !== 'function' ) return reject ( "Custom Modal -- callback property in Param 3 must be a function" ) ;
637
- } else {
638
- return reject ( "Custom Modal -- Param 3 must be a object with properties: 'name' (string) and 'callback' (function)" ) ;
639
- }
640
- if ( isObject ( closeInfo ) ) {
641
- if ( ! closeInfo . name || ! closeInfo . callback ) return reject ( "Custom Modal -- Missing name/callback property in Param 4" ) ;
642
- if ( closeInfo . callback && typeof closeInfo . callback !== 'function' ) return reject ( "Custom Modal -- callback property in Param 4 must be a function" ) ;
643
- } else {
644
- return reject ( "Custom Modal -- Param 4 must be a object with properties: 'name' (string) and 'callback' (function)" ) ;
645
- }
614
+ handleCustomPrompt ( title , scale , enterInfo , closeInfo ) {
615
+ const isObject = ( value ) => typeof value === 'object' && ! Array . isArray ( value ) ;
616
+ let needsExit = false ;
617
+ const exitFunc = ( message ) => {
618
+ needsExit = true ;
619
+ console . error ( message ) ;
620
+ } ;
646
621
647
- // create the callback for when the node is created. an HTML element (or modal) with ref={functionHere} will run the function with the HTMLElement as 1st arg
648
- const thisPromptId = uid ( ) ;
649
- this . customModalRefs . set ( thisPromptId , ( node ) => {
650
- resolve ( node ) ;
651
- } )
652
-
653
- // Setting state with this info will cause blocks.jsx to re-render, rendering the modal before any code after setState can run.
654
- // However, the callback & ref are not be usable until slightly later. this is why ref is set to a callback above.
655
- // This is one of many reasons why React is pretty stupid.
656
- this . setState ( {
657
- customPrompts : this . state . customPrompts . concat ( {
658
- id : thisPromptId ,
659
- config, styles, enterInfo, closeInfo
660
- } )
661
- } ) ;
662
- } ) ;
622
+ /* validate arguments */
623
+ if ( isObject ( scale ) ) {
624
+ if ( ! scale . width || ! scale . height ) exitFunc ( "Custom Modal -- Missing width/height number property in Param 2" ) ;
625
+ } else {
626
+ exitFunc ( "Custom Modal -- Param 2 must be a object with 'width' and 'height' number properties" ) ;
627
+ }
628
+ if ( isObject ( enterInfo ) ) {
629
+ if ( ! enterInfo . name || ! enterInfo . callback ) exitFunc ( "Custom Modal -- Missing name/callback property in Param 3" ) ;
630
+ if ( enterInfo . callback && typeof enterInfo . callback !== 'function' ) exitFunc ( "Custom Modal -- callback property in Param 3 must be a function" ) ;
631
+ } else {
632
+ exitFunc ( "Custom Modal -- Param 3 must be a object with properties: 'name' (string) and 'callback' (function)" ) ;
633
+ }
634
+ if ( isObject ( closeInfo ) ) {
635
+ if ( ! closeInfo . name || ! closeInfo . callback ) exitFunc ( "Custom Modal -- Missing name/callback property in Param 4" ) ;
636
+ if ( closeInfo . callback && typeof closeInfo . callback !== 'function' ) exitFunc ( "Custom Modal -- callback property in Param 4 must be a function" ) ;
637
+ } else {
638
+ exitFunc ( "Custom Modal -- Param 4 must be a object with properties: 'name' (string) and 'callback' (function)" ) ;
639
+ }
640
+ if ( needsExit ) return ;
641
+
642
+ this . setState ( { prompt : {
643
+ isCustom : true ,
644
+ title, enterInfo, closeInfo
645
+ } } ) ;
646
+
647
+ const modal = document . querySelector ( `div[class="ReactModalPortal"]` ) ;
648
+ if ( modal ) {
649
+ const inner = modal . firstChild . firstChild ;
650
+ inner . style . width = typeof scale . width === 'number' ? `${ scale . width } px` : scale . width ;
651
+ inner . style . height = typeof scale . height === 'number' ? `${ scale . height } px` : scale . height ;
652
+ return inner . querySelector ( `div[class*="prompt_body_"] div` ) ;
653
+ }
663
654
}
664
655
handleConnectionModalStart ( extensionId ) {
665
656
this . props . onOpenConnectionModal ( extensionId ) ;
@@ -676,28 +667,20 @@ class Blocks extends React.Component {
676
667
* and additional potentially conflicting variable names from the VM
677
668
* to the variable validation prompt callback used in scratch-blocks.
678
669
*/
679
- handlePromptCallback ( input , variableOptions , customPrompt ) {
680
- if ( customPrompt ) {
681
- customPrompt . enterInfo . callback ( ) ;
682
- return this . setState ( {
683
- customPrompts : this . state . customPrompts . filter ( prompt => prompt !== customPrompt )
684
- } ) ;
670
+ handlePromptCallback ( input , variableOptions ) {
671
+ if ( this . state . prompt . isCustom ) {
672
+ this . state . prompt . enterInfo . callback ( ) ;
673
+ this . setState ( { prompt : null } ) ;
674
+ return ;
685
675
}
686
-
687
676
this . state . prompt . callback (
688
677
input ,
689
678
this . props . vm . runtime . getAllVarNamesOfType ( this . state . prompt . varType ) ,
690
679
variableOptions ) ;
691
680
this . handlePromptClose ( ) ;
692
681
}
693
- handlePromptClose ( customPrompt ) {
694
- if ( customPrompt ) {
695
- customPrompt . closeInfo . callback ( ) ;
696
- return this . setState ( {
697
- customPrompts : this . state . customPrompts . filter ( prompt => prompt !== customPrompt )
698
- } ) ;
699
- }
700
-
682
+ handlePromptClose ( ) {
683
+ if ( this . state . prompt . isCustom ) this . state . prompt . closeInfo . callback ( ) ;
701
684
this . setState ( { prompt : null } ) ;
702
685
}
703
686
handleCustomProceduresClose ( data ) {
@@ -753,7 +736,17 @@ class Blocks extends React.Component {
753
736
onDrop = { this . handleDrop }
754
737
{ ...props }
755
738
/>
756
- { this . state . prompt ? (
739
+ { this . state . prompt ? this . state . prompt . isCustom ? (
740
+ < Prompt
741
+ isCustom = { this . state . prompt . isCustom }
742
+ title = { this . state . prompt . title }
743
+ enterTitle = { this . state . prompt . enterInfo . name }
744
+ closeTitle = { this . state . prompt . closeInfo . name }
745
+ vm = { vm }
746
+ onCancel = { this . handlePromptClose }
747
+ onOk = { this . handlePromptCallback }
748
+ />
749
+ ) : (
757
750
< Prompt
758
751
defaultValue = { this . state . prompt . defaultValue }
759
752
isStage = { vm . runtime . getEditingTarget ( ) . isStage }
@@ -767,20 +760,6 @@ class Blocks extends React.Component {
767
760
onOk = { this . handlePromptCallback }
768
761
/>
769
762
) : null }
770
- { this . state . customPrompts . map ( prompt => (
771
- < Prompt
772
- isCustom = { true }
773
- vm = { vm }
774
- customRef = { this . customModalRefs . get ( prompt . id ) }
775
- title = { prompt . config . title }
776
- styleContent = { prompt . styles ? prompt . styles . content : null }
777
- styleOverlay = { prompt . styles ? prompt . styles . overlay : null }
778
- enterTitle = { prompt . enterInfo . name }
779
- closeTitle = { prompt . closeInfo . name }
780
- onCancel = { ( ) => this . handlePromptClose ( prompt ) }
781
- onOk = { ( ) => this . handlePromptCallback ( null , null , prompt ) }
782
- />
783
- ) ) }
784
763
{ extensionLibraryVisible ? (
785
764
< ExtensionLibrary
786
765
vm = { vm }
0 commit comments