Skip to content

Commit 6eb73b7

Browse files
committed
Limit Jump to step to be within steps
1 parent 428f6df commit 6eb73b7

File tree

6 files changed

+100
-8
lines changed

6 files changed

+100
-8
lines changed

src/blocks/mrc_jump_to_step.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,19 @@ import {Order} from 'blockly/python';
2525
import {ExtendedPythonGenerator} from '../editor/extended_python_generator';
2626
import {createFieldNonEditableText} from '../fields/FieldNonEditableText';
2727
import {MRC_STYLE_VARIABLES} from '../themes/styles';
28+
import {BLOCK_NAME as MRC_STEPS, StepsBlock} from './mrc_steps'
2829

2930
export const BLOCK_NAME = 'mrc_jump_to_step';
3031

3132
const FIELD_STEP_NAME = 'STEP_NAME';
3233

34+
const WARNING_ID_NOT_IN_STEP = 'not in step';
35+
36+
3337
type JumpToStepBlock = Blockly.Block & Blockly.BlockSvg & JumpToStepMixin;
3438

3539
interface JumpToStepMixin extends JumpToStepMixinType {
40+
mrcHasWarning: boolean,
3641
}
3742

3843
type JumpToStepMixinType = typeof JUMP_TO_STEP_BLOCK;
@@ -50,6 +55,39 @@ const JUMP_TO_STEP_BLOCK = {
5055
this.setStyle(MRC_STYLE_VARIABLES);
5156
this.setTooltip('Jump to the specified step.');
5257
},
58+
/**
59+
* mrcOnMove is called when an EventBlock is moved.
60+
*/
61+
mrcOnMove: function(this: JumpToStepBlock, _reason: string[]): void {
62+
this.checkBlockPlacement();
63+
},
64+
mrcOnAncestorMove: function(this: JumpToStepBlock): void {
65+
this.checkBlockPlacement();
66+
},
67+
checkBlockPlacement: function(this: JumpToStepBlock): void {
68+
const legalStepNames: string[] = [];
69+
70+
const rootBlock: Blockly.Block | null = this.getRootBlock();
71+
if (rootBlock.type === MRC_STEPS) {
72+
// This block is within a class method definition.
73+
const stepsBlock = rootBlock as StepsBlock;
74+
// Add the method's parameter names to legalStepNames.
75+
legalStepNames.push(...stepsBlock.mrcGetStepNames());
76+
}
77+
78+
if (legalStepNames.includes(this.getFieldValue(FIELD_STEP_NAME))) {
79+
// If this blocks's parameter name is in legalParameterNames, it's good.
80+
this.setWarningText(null, WARNING_ID_NOT_IN_STEP);
81+
this.mrcHasWarning = false;
82+
} else {
83+
// Otherwise, add a warning to this block.
84+
if (!this.mrcHasWarning) {
85+
this.setWarningText(Blockly.Msg.JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK, WARNING_ID_NOT_IN_STEP);
86+
this.getIcon(Blockly.icons.IconType.WARNING)!.setBubbleVisible(true);
87+
this.mrcHasWarning = true;
88+
}
89+
}
90+
},
5391
};
5492

5593
export const setup = function() {
@@ -60,8 +98,9 @@ export const pythonFromBlock = function(
6098
block: JumpToStepBlock,
6199
_generator: ExtendedPythonGenerator,
62100
) {
63-
// TODO (Alan) : Specify the type here as well
64-
const code = '# TODO: Jump to step ' + block.getFieldValue(FIELD_STEP_NAME) + '\n';
101+
let code = 'self.current_step_index = self.mrc_step_name_to_index["' +
102+
block.getFieldValue(FIELD_STEP_NAME) + '"]\n';
103+
code += 'return\n';
65104

66-
return [code, Order.ATOMIC];
105+
return code;
67106
};

src/blocks/mrc_steps.ts

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@ import {Order} from 'blockly/python';
2424

2525
import { MRC_STYLE_STEPS } from '../themes/styles';
2626
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
27-
import { createStepFieldFlydown } from '../fields/field_flydown';
27+
import { createStepFieldFlydown, FieldFlydown } from '../fields/field_flydown';
2828
import * as stepContainer from './mrc_step_container'
2929

3030
export const BLOCK_NAME = 'mrc_steps';
3131
// const MUTATOR_BLOCK_NAME = 'steps_mutatorarg';
3232

3333

34+
/** Extra state for serialising call_python_* blocks. */
35+
type StepsExtraState = {
36+
/**
37+
* The steps
38+
*/
39+
stepNames: string[],
40+
};
41+
3442
export type StepsBlock = Blockly.Block & StepsMixin & Blockly.BlockSvg;
3543
interface StepsMixin extends StepsMixinType {
3644
mrcStepNames: string[];
@@ -50,6 +58,17 @@ const STEPS = {
5058
this.setMutator(stepContainer.getMutatorIcon(this));
5159
this.updateShape_();
5260
},
61+
saveExtraState: function (this: StepsBlock): StepsExtraState{
62+
return {
63+
stepNames: this.mrcStepNames,
64+
};
65+
},
66+
loadExtraState: function (this: StepsBlock, state: StepsExtraState): void {
67+
if (state && state.stepNames) {
68+
this.mrcStepNames = state.stepNames;
69+
this.updateShape_();
70+
}
71+
},
5372
compose: function (this: StepsBlock, containerBlock: Blockly.Block) {
5473
if (containerBlock.type !== stepContainer.STEP_CONTAINER_BLOCK_NAME) {
5574
throw new Error('compose: containerBlock.type should be ' + stepContainer.STEP_CONTAINER_BLOCK_NAME);
@@ -80,6 +99,30 @@ const STEPS = {
8099
},
81100
mrcOnChange: function(this: StepsBlock): void {
82101

102+
},
103+
mrcUpdateStepName: function(this: StepsBlock, step : number, newName: string) : string {
104+
const otherNames = this.mrcStepNames.filter((_name, index) => index !== step);
105+
let currentName = newName;
106+
107+
// Make name unique if it conflicts
108+
while (otherNames.includes(currentName)) {
109+
// Check if currentName ends with a number
110+
const match = currentName.match(/^(.*?)(\d+)$/);
111+
if (match) {
112+
// If it ends with a number, increment it
113+
const baseName = match[1];
114+
const number = parseInt(match[2], 10);
115+
currentName = baseName + (number + 1);
116+
} else {
117+
// If it doesn't end with a number, append 2
118+
currentName = currentName + '2';
119+
}
120+
}
121+
this.mrcStepNames[step] = currentName;
122+
// TODO: Rename any jump blocks that refer to this step
123+
124+
125+
return currentName;
83126
},
84127
updateShape_: function (this: StepsBlock): void {
85128
// some way of knowing what was there before and what is there now
@@ -91,13 +134,19 @@ const STEPS = {
91134
i++;
92135
}
93136
for (let j = 0; j < this.mrcStepNames.length; j++) {
137+
const fieldFlydown = createStepFieldFlydown(this.mrcStepNames[j], true);
138+
139+
fieldFlydown.setValidator(this.mrcUpdateStepName.bind(this, j));
94140
this.appendValueInput('CONDITION_' + j)
95-
.appendField(createStepFieldFlydown(this.mrcStepNames[j], true))
141+
.appendField(fieldFlydown)
96142
.setCheck('Boolean')
97143
.appendField(Blockly.Msg.REPEAT_UNTIL);
98144
this.appendStatementInput('STEP_' + j);
99145
}
100146
},
147+
mrcGetStepNames: function(this: StepsBlock): string[] {
148+
return this.mrcStepNames;
149+
}
101150
};
102151

103152
export const setup = function () {

src/blocks/tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export function customTokens(t: (key: string) => string): typeof Blockly.Msg {
131131
COMMENT_DEFAULT_TEXT: t('BLOCKLY.COMMENT_DEFAULT_TEXT'),
132132
STEPS: t('BLOCKLY.STEPS'),
133133
REPEAT_UNTIL: t('BLOCKLY.REPEAT_UNTIL'),
134+
JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK: t('BLOCKLY.JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK'),
134135
}
135136
};
136137

src/i18n/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"PARAMETER": "parameter",
125125
"PARAMETERS": "Parameters",
126126
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Parameters can only go in their method's block",
127+
"JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK": "Jump can only go in their step's block",
127128
"EVENT_HANDLER_ALREADY_ON_WORKSPACE": "This event handler is already on the workspace.",
128129
"EVENT_HANDLER_ROBOT_EVENT_NOT_FOUND": "This block is an event handler for an event that no longer exists.",
129130
"EVENT_HANDLER_MECHANISM_EVENT_NOT_FOUND": "This block is an event handler for an event that no longer exists.",

src/i18n/locales/es/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@
125125
"PARAMETER": "parámetro",
126126
"PARAMETERS": "Parámetros",
127127
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "Los parámetros solo pueden ir en el bloque de su método",
128-
"EVENT_HANDLER_ALREADY_ON_WORKSPACE": "Este controlador de eventos ya está en el área de trabajo.",
128+
"JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK": "El salto solo puede ir en el bloque de su paso",
129+
"EVENT_HANDLER_ALREADY_ON_WORKSPACE": "Este controlador de eventos ya está en el espacio de trabajo.",
129130
"EVENT_HANDLER_ROBOT_EVENT_NOT_FOUND": "Este bloque es un controlador de eventos para un evento que ya no existe.",
130131
"EVENT_HANDLER_MECHANISM_EVENT_NOT_FOUND": "Este bloque es un controlador de eventos para un evento que ya no existe.",
131132
"EVENT_HANDLER_MECHANISM_NOT_FOUND": "Este bloque es un controlador de eventos para un evento en un mecanismo que ya no existe.",

src/i18n/locales/he/translation.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@
123123
"WHEN": "כאשר",
124124
"PARAMETER": "פרמטר",
125125
"PARAMETERS": "פרמטרים",
126-
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "פרמטרים יכולים להופיע רק בתוך הבלוק של המתודה שלהם.",
127-
"EVENT_HANDLER_ALREADY_ON_WORKSPACE": "מנהל האירועים הזה כבר נמצא בסביבת העבודה.",
126+
"PARAMETERS_CAN_ONLY_GO_IN_THEIR_METHODS_BLOCK": "פרמטרים יכולים ללכת רק בבלוק השיטה שלהם",
127+
"JUMP_CAN_ONLY_GO_IN_THEIR_STEPS_BLOCK": "קפיצה יכולה ללכת רק בבלוק הצעד שלה",
128+
"EVENT_HANDLER_ALREADY_ON_WORKSPACE": "מטפל אירועים זה כבר נמצא במרחב העבודה.",
128129
"EVENT_HANDLER_ROBOT_EVENT_NOT_FOUND": "הבלוק הזה הוא מנהל אירועים לאירוע שכבר לא קיים.",
129130
"EVENT_HANDLER_MECHANISM_EVENT_NOT_FOUND": "הבלוק הזה הוא מנהל אירועים לאירוע שכבר לא קיים.",
130131
"EVENT_HANDLER_MECHANISM_NOT_FOUND": "הבלוק הזה הוא מנהל אירועים לאירוע במנגנון שכבר לא קיים.",

0 commit comments

Comments
 (0)