@@ -25,10 +25,11 @@ import {Order} from 'blockly/python';
2525
2626import { Editor } from '../editor/editor' ;
2727import { ExtendedPythonGenerator } from '../editor/extended_python_generator' ;
28- import { createFieldNonEditableText } from '../fields/FieldNonEditableText' ;
2928import { MRC_STYLE_VARIABLES } from '../themes/styles' ;
3029import { BLOCK_NAME as MRC_CLASS_METHOD_DEF , ClassMethodDefBlock } from './mrc_class_method_def' ;
3130import { BLOCK_NAME as MRC_EVENT_HANDLER , EventHandlerBlock } from './mrc_event_handler' ;
31+ import { findConnectedBlocksOfType } from './utils/find_connected_blocks' ;
32+ import { CustomDropdownWithoutValidation } from '../fields/FieldDropdown' ;
3233
3334
3435export const BLOCK_NAME = 'mrc_get_parameter' ;
@@ -70,11 +71,60 @@ const GET_PARAMETER_BLOCK = {
7071 this . mrcHasWarning = false ;
7172
7273 this . setStyle ( MRC_STYLE_VARIABLES ) ;
74+
75+ const blockRef = this ;
76+ // Use a dummy initial option - it will be replaced when setValue is called
77+ const dropdown : Blockly . Field = new CustomDropdownWithoutValidation (
78+ function ( ) {
79+ // This function will be called to regenerate options when dropdown opens
80+ return blockRef . getParameterOptions ( ) ;
81+ }
82+ ) ;
83+
84+ dropdown . setValidator ( this . validateParameterSelection . bind ( this ) ) ;
85+
7386 this . appendDummyInput ( )
7487 . appendField ( Blockly . Msg . PARAMETER )
75- . appendField ( createFieldNonEditableText ( '' ) , FIELD_PARAMETER_NAME ) ;
88+ . appendField ( dropdown , FIELD_PARAMETER_NAME ) ;
7689 this . setOutput ( true , this . mrcParameterType ) ;
7790 } ,
91+ getParameterOptions : function ( this : GetParameterBlock ) : [ string , string ] [ ] {
92+ const existingParameterNames : string [ ] = [ ] ;
93+
94+ const rootBlock : Blockly . Block | null = this . getRootBlock ( ) ;
95+ if ( rootBlock && rootBlock . type === MRC_CLASS_METHOD_DEF ) {
96+ const classMethodDefBlock = rootBlock as ClassMethodDefBlock ;
97+ existingParameterNames . push ( ...classMethodDefBlock . mrcGetParameterNames ( ) ) ;
98+ } else if ( rootBlock && rootBlock . type === MRC_EVENT_HANDLER ) {
99+ const eventHandlerBlock = rootBlock as EventHandlerBlock ;
100+ existingParameterNames . push ( ...eventHandlerBlock . mrcGetParameterNames ( ) ) ;
101+ }
102+
103+ // Get the field to check its value
104+ const field = this . getField ( FIELD_PARAMETER_NAME ) as Blockly . FieldDropdown | null ;
105+ const currentValue = field ?. getValue ( ) ;
106+
107+ // Always include the current field value if it exists and isn't already in the list
108+ if ( currentValue && ! existingParameterNames . includes ( currentValue ) ) {
109+ existingParameterNames . unshift ( currentValue ) ;
110+ }
111+
112+ if ( existingParameterNames . length === 0 ) {
113+ return [ [ Blockly . Msg . NO_PARAMETERS , '' ] ] ;
114+ }
115+
116+ return existingParameterNames . map ( name => [ name , name ] ) ;
117+ } ,
118+ validateParameterSelection : function ( this : GetParameterBlock , newValue : string ) : string {
119+ // Clear any previous warnings
120+ this . setWarningText ( null , WARNING_ID_NOT_IN_METHOD ) ;
121+ this . mrcHasWarning = false ;
122+
123+ // Options will be regenerated automatically on next dropdown open
124+ // via the function passed to the CustomParameterDropdown constructor
125+
126+ return newValue ;
127+ } ,
78128 setNameAndType : function ( this : GetParameterBlock , name : string , type : string ) : void {
79129 this . setFieldValue ( name , FIELD_PARAMETER_NAME ) ;
80130 this . mrcParameterType = type ;
@@ -105,21 +155,58 @@ const GET_PARAMETER_BLOCK = {
105155 legalParameterNames . push ( ...eventHandlerBlock . mrcGetParameterNames ( ) ) ;
106156 }
107157
108- if ( legalParameterNames . includes ( this . getFieldValue ( FIELD_PARAMETER_NAME ) ) ) {
158+ const currentParameterName = this . getFieldValue ( FIELD_PARAMETER_NAME ) ;
159+
160+ if ( legalParameterNames . includes ( currentParameterName ) ) {
109161 // If this blocks's parameter name is in legalParameterNames, it's good.
110162 this . setWarningText ( null , WARNING_ID_NOT_IN_METHOD ) ;
111163 this . mrcHasWarning = false ;
112164 } else {
113165 // Otherwise, add a warning to this block.
114166 if ( ! this . mrcHasWarning ) {
115- this . setWarningText ( Blockly . Msg . PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK , WARNING_ID_NOT_IN_METHOD ) ;
167+ // Provide a more specific message depending on the situation
168+ let warningMessage : string ;
169+ if ( rootBlock . type === MRC_CLASS_METHOD_DEF || rootBlock . type === MRC_EVENT_HANDLER ) {
170+ // We're in a method/handler but the parameter doesn't exist
171+ if ( currentParameterName && currentParameterName !== '' ) {
172+ const messageTemplate = rootBlock . type === MRC_CLASS_METHOD_DEF
173+ ? Blockly . Msg . PARAMETER_DOES_NOT_EXIST_IN_METHOD
174+ : Blockly . Msg . PARAMETER_DOES_NOT_EXIST_IN_EVENT_HANDLER ;
175+ warningMessage = messageTemplate . replace ( '%1' , currentParameterName ) ;
176+ } else {
177+ warningMessage = Blockly . Msg . NO_PARAMETER_SELECTED ;
178+ }
179+ } else {
180+ // We're not even in a method/handler
181+ warningMessage = Blockly . Msg . PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK ;
182+ }
183+
184+ this . setWarningText ( warningMessage , WARNING_ID_NOT_IN_METHOD ) ;
116185 this . getIcon ( Blockly . icons . IconType . WARNING ) ! . setBubbleVisible ( true ) ;
117186 this . mrcHasWarning = true ;
118187 }
119188 }
120189 } ,
190+ /**
191+ * Called to recheck parameter validity. Used when method parameters change.
192+ */
193+ mrcCheckParameter : function ( this : GetParameterBlock ) : void {
194+ this . checkBlockPlacement ( ) ;
195+ } ,
121196} ;
122197
198+ /*
199+ * Rechecks all Get Parameter blocks connected to the target block.
200+ */
201+ export function checkParameterBlocks ( targetBlock : Blockly . Block | null ) : void {
202+ if ( targetBlock ) {
203+ findConnectedBlocksOfType ( targetBlock , BLOCK_NAME ) . forEach ( ( block ) => {
204+ const getParameterBlock = block as GetParameterBlock ;
205+ getParameterBlock . mrcCheckParameter ( ) ;
206+ } ) ;
207+ }
208+ }
209+
123210export const setup = function ( ) {
124211 Blockly . Blocks [ BLOCK_NAME ] = GET_PARAMETER_BLOCK ;
125212} ;
0 commit comments