scratch-blocks 2.1.5 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +58 -14
- package/dist/main.mjs +1 -1
- package/dist/types/src/block_reporting.d.ts.map +1 -1
- package/dist/types/src/blocks/procedures.d.ts +2 -2
- package/dist/types/src/blocks/procedures.d.ts.map +1 -1
- package/dist/types/src/checkable_continuous_flyout.d.ts +6 -3
- package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
- package/dist/types/src/checkbox_bubble.d.ts +7 -7
- package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
- package/dist/types/src/colours.d.ts.map +1 -1
- package/dist/types/src/context_menu_items.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_base.d.ts +1 -1
- package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_end.d.ts +1 -1
- package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_outside.d.ts +1 -1
- package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
- package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
- package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
- package/dist/types/src/fields/field_note.d.ts +6 -4
- package/dist/types/src/fields/field_note.d.ts.map +1 -1
- package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
- package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
- package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_variable.d.ts +1 -0
- package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
- package/dist/types/src/flyout_checkbox_icon.d.ts +5 -5
- package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
- package/dist/types/src/glows.d.ts.map +1 -1
- package/dist/types/src/procedures.d.ts +4 -4
- package/dist/types/src/procedures.d.ts.map +1 -1
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts +2 -2
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/cat_face.d.ts +1 -1
- package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/constants.d.ts.map +1 -1
- package/dist/types/src/renderer/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/render_info.d.ts.map +1 -1
- package/dist/types/src/scratch_blocks_utils.d.ts +22 -0
- package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_bubble.d.ts +4 -4
- package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_category.d.ts +3 -1
- package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_toolbox.d.ts +2 -1
- package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label.d.ts +3 -3
- package/dist/types/src/status_indicator_label.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/variables.d.ts +1 -1
- package/dist/types/src/variables.d.ts.map +1 -1
- package/dist/types/src/workspace_block_lookup.d.ts +4 -0
- package/dist/types/src/workspace_block_lookup.d.ts.map +1 -0
- package/eslint.config.mjs +21 -28
- package/package.json +1 -1
- package/src/block_reporting.ts +5 -5
- package/src/blocks/control.ts +5 -5
- package/src/blocks/event.ts +1 -1
- package/src/blocks/motion.ts +2 -2
- package/src/blocks/procedures.ts +162 -69
- package/src/blocks/sensing.ts +0 -1
- package/src/blocks/vertical_extensions.ts +11 -8
- package/src/checkable_continuous_flyout.ts +45 -12
- package/src/checkbox_bubble.ts +7 -7
- package/src/colours.ts +4 -2
- package/src/context_menu_items.ts +41 -16
- package/src/data_category.ts +11 -3
- package/src/events/events_block_comment_base.ts +5 -1
- package/src/events/events_block_comment_change.ts +5 -1
- package/src/events/events_block_comment_collapse.ts +6 -2
- package/src/events/events_block_comment_create.ts +5 -1
- package/src/events/events_block_comment_move.ts +6 -2
- package/src/events/events_block_comment_resize.ts +6 -2
- package/src/events/events_block_drag_end.ts +5 -1
- package/src/events/events_block_drag_outside.ts +5 -1
- package/src/events/events_scratch_variable_create.ts +5 -1
- package/src/fields/field_colour_slider.ts +3 -5
- package/src/fields/field_matrix.ts +33 -17
- package/src/fields/field_note.ts +56 -20
- package/src/fields/field_textinput_removable.ts +13 -4
- package/src/fields/field_variable_getter.ts +20 -6
- package/src/fields/field_vertical_separator.ts +5 -1
- package/src/fields/scratch_field_angle.ts +32 -21
- package/src/fields/scratch_field_dropdown.ts +6 -2
- package/src/fields/scratch_field_number.ts +22 -13
- package/src/fields/scratch_field_variable.ts +26 -12
- package/src/flyout_checkbox_icon.ts +9 -5
- package/src/glows.ts +5 -5
- package/src/index.ts +18 -6
- package/src/procedures.ts +92 -42
- package/src/recyclable_block_flyout_inflater.ts +5 -4
- package/src/renderer/cat/cat_face.ts +1 -1
- package/src/renderer/cat/drawer.ts +4 -1
- package/src/renderer/constants.ts +19 -14
- package/src/renderer/drawer.ts +2 -1
- package/src/renderer/render_info.ts +12 -9
- package/src/renderer/renderer.ts +1 -1
- package/src/scratch_blocks_utils.ts +0 -2
- package/src/scratch_c_block_wrap.ts +37 -21
- package/src/scratch_comment_bubble.ts +30 -19
- package/src/scratch_comment_icon.ts +9 -12
- package/src/scratch_continuous_category.ts +20 -11
- package/src/scratch_continuous_toolbox.ts +12 -3
- package/src/scratch_dragger.ts +2 -2
- package/src/scratch_variable_map.ts +1 -1
- package/src/status_indicator_label.ts +13 -9
- package/src/status_indicator_label_flyout_inflater.ts +2 -1
- package/src/variables.ts +21 -14
- package/src/workspace_block_lookup.ts +14 -0
- package/src/xml.ts +1 -1
- package/types/continuous-toolbox.d.ts +0 -1
|
@@ -210,7 +210,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
210
210
|
this.arrow_.setAttributeNS(
|
|
211
211
|
'http://www.w3.org/1999/xlink',
|
|
212
212
|
'xlink:href',
|
|
213
|
-
this.getConstants()
|
|
213
|
+
this.getConstants()?.FIELD_DROPDOWN_SVG_ARROW_DATAURI ?? '',
|
|
214
214
|
)
|
|
215
215
|
this.arrow_.style.cursor = 'default'
|
|
216
216
|
}
|
|
@@ -241,7 +241,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
241
241
|
} else if (this.borderRect_) {
|
|
242
242
|
this.borderRect_.setAttribute(
|
|
243
243
|
'fill',
|
|
244
|
-
'colourQuaternary' in style ?
|
|
244
|
+
'colourQuaternary' in style ? String(style.colourQuaternary) : style.colourTertiary,
|
|
245
245
|
)
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -299,17 +299,22 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
299
299
|
|
|
300
300
|
Blockly.DropDownDiv.showPositionedByBlock(this, sourceBlock, this.dropdownDispose_.bind(this))
|
|
301
301
|
|
|
302
|
-
this.matrixTouchWrapper_ = Blockly.browserEvents.bind(
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
this.matrixTouchWrapper_ = Blockly.browserEvents.bind(
|
|
303
|
+
this.matrixStage_,
|
|
304
|
+
'mousedown',
|
|
305
|
+
this,
|
|
306
|
+
this.onMouseDown.bind(this),
|
|
307
|
+
)
|
|
308
|
+
this.clearButtonWrapper_ = Blockly.browserEvents.bind(clearButton, 'click', this, this.clearMatrix_.bind(this))
|
|
309
|
+
this.fillButtonWrapper_ = Blockly.browserEvents.bind(fillButton, 'click', this, this.fillMatrix_.bind(this))
|
|
305
310
|
|
|
306
311
|
// Update the matrix for the current value
|
|
307
312
|
this.updateMatrix_()
|
|
308
313
|
}
|
|
309
314
|
|
|
310
315
|
dropdownDispose_() {
|
|
311
|
-
const sourceBlock = this.getSourceBlock()
|
|
312
|
-
if (sourceBlock
|
|
316
|
+
const sourceBlock = this.getSourceBlock()
|
|
317
|
+
if (sourceBlock?.isShadow()) {
|
|
313
318
|
sourceBlock.setStyle(this.originalStyle)
|
|
314
319
|
}
|
|
315
320
|
this.updateMatrix_()
|
|
@@ -355,10 +360,12 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
355
360
|
* Redraw the matrix with the current value.
|
|
356
361
|
*/
|
|
357
362
|
private updateMatrix_() {
|
|
358
|
-
const matrix = this.getValue()
|
|
359
|
-
|
|
363
|
+
const matrix = this.getValue()
|
|
364
|
+
if (!matrix) return
|
|
365
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg | null
|
|
366
|
+
if (!sourceBlock) return
|
|
360
367
|
for (let i = 0; i < matrix.length; i++) {
|
|
361
|
-
if (matrix[i] === LEDState.OFF) {
|
|
368
|
+
if ((matrix[i] as LEDState) === LEDState.OFF) {
|
|
362
369
|
this.fillMatrixNode_(this.ledButtons_, i, sourceBlock.getColourTertiary())
|
|
363
370
|
this.fillMatrixNode_(this.ledThumbNodes_, i, sourceBlock.getColourSecondary())
|
|
364
371
|
} else {
|
|
@@ -393,13 +400,14 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
393
400
|
* @param fill The fill colour in '#rrggbb' format.
|
|
394
401
|
*/
|
|
395
402
|
fillMatrixNode_(node: SVGElement[], index: number, fill: string) {
|
|
396
|
-
if (!node
|
|
403
|
+
if (!node[index] || !fill) return
|
|
397
404
|
node[index].setAttribute('fill', fill)
|
|
398
405
|
}
|
|
399
406
|
|
|
400
407
|
setLEDNode_(led: number, state: LEDState) {
|
|
401
408
|
if (led < 0 || led > 24) return
|
|
402
|
-
const oldMatrix = this.getValue()
|
|
409
|
+
const oldMatrix = this.getValue()
|
|
410
|
+
if (!oldMatrix) return
|
|
403
411
|
const newMatrix = oldMatrix.substr(0, led) + state + oldMatrix.substr(led + 1)
|
|
404
412
|
this.setValue(newMatrix)
|
|
405
413
|
}
|
|
@@ -416,7 +424,9 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
416
424
|
|
|
417
425
|
toggleLEDNode_(led: number) {
|
|
418
426
|
if (led < 0 || led > 24) return
|
|
419
|
-
|
|
427
|
+
const value = this.getValue()
|
|
428
|
+
if (!value) return
|
|
429
|
+
if ((value.charAt(led) as LEDState) === LEDState.OFF) {
|
|
420
430
|
this.setLEDNode_(led, LEDState.ON)
|
|
421
431
|
} else {
|
|
422
432
|
this.setLEDNode_(led, LEDState.OFF)
|
|
@@ -428,11 +438,17 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
428
438
|
* @param e Mouse event.
|
|
429
439
|
*/
|
|
430
440
|
onMouseDown(e: PointerEvent) {
|
|
431
|
-
this.matrixMoveWrapper_ = Blockly.browserEvents.bind(
|
|
432
|
-
|
|
441
|
+
this.matrixMoveWrapper_ = Blockly.browserEvents.bind(
|
|
442
|
+
document.body,
|
|
443
|
+
'mousemove',
|
|
444
|
+
this,
|
|
445
|
+
this.onMouseMove.bind(this),
|
|
446
|
+
)
|
|
447
|
+
this.matrixReleaseWrapper_ = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp.bind(this))
|
|
433
448
|
const ledHit = this.checkForLED_(e)
|
|
434
449
|
if (ledHit > -1) {
|
|
435
|
-
|
|
450
|
+
const value = this.getValue()
|
|
451
|
+
if (value && (value.charAt(ledHit) as LEDState) === LEDState.OFF) {
|
|
436
452
|
this.paintStyle_ = PaintStyle.FILL
|
|
437
453
|
} else {
|
|
438
454
|
this.paintStyle_ = PaintStyle.CLEAR
|
|
@@ -470,7 +486,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
470
486
|
if (led < 0) return
|
|
471
487
|
if (this.paintStyle_ === PaintStyle.CLEAR) {
|
|
472
488
|
this.clearLEDNode_(led)
|
|
473
|
-
} else
|
|
489
|
+
} else {
|
|
474
490
|
this.fillLEDNode_(led)
|
|
475
491
|
}
|
|
476
492
|
}
|
package/src/fields/field_note.ts
CHANGED
|
@@ -284,6 +284,12 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
284
284
|
*/
|
|
285
285
|
showEditor_(event: PointerEvent, quietInput = false) {
|
|
286
286
|
super.showEditor_(event, quietInput, false)
|
|
287
|
+
const parentBlock = this.getSourceBlock()?.getParent() as Blockly.BlockSvg | undefined
|
|
288
|
+
if (!parentBlock) {
|
|
289
|
+
throw new Error('[field_note] Missing parent block for note field editor')
|
|
290
|
+
}
|
|
291
|
+
const parentColour = parentBlock.getColour()
|
|
292
|
+
const parentTertiary = parentBlock.getColourTertiary()
|
|
287
293
|
|
|
288
294
|
// Build the SVG DOM.
|
|
289
295
|
const div = Blockly.DropDownDiv.getContentDiv()
|
|
@@ -314,9 +320,21 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
314
320
|
// Add three piano octaves, so we can animate moving up or down an octave.
|
|
315
321
|
// Only the middle octave gets bound to events.
|
|
316
322
|
this.keySVGs_ = []
|
|
317
|
-
this.addPianoOctave_(
|
|
318
|
-
|
|
319
|
-
|
|
323
|
+
this.addPianoOctave_(
|
|
324
|
+
-this.fieldEditorWidth_ + FieldNote.EDGE_PADDING,
|
|
325
|
+
whiteKeyGroup,
|
|
326
|
+
blackKeyGroup,
|
|
327
|
+
null,
|
|
328
|
+
parentBlock,
|
|
329
|
+
)
|
|
330
|
+
this.addPianoOctave_(0, whiteKeyGroup, blackKeyGroup, this.keySVGs_, parentBlock)
|
|
331
|
+
this.addPianoOctave_(
|
|
332
|
+
this.fieldEditorWidth_ - FieldNote.EDGE_PADDING,
|
|
333
|
+
whiteKeyGroup,
|
|
334
|
+
blackKeyGroup,
|
|
335
|
+
null,
|
|
336
|
+
parentBlock,
|
|
337
|
+
)
|
|
320
338
|
|
|
321
339
|
// Note name indicator at the top of the field
|
|
322
340
|
this.noteNameText_ = Blockly.utils.dom.createSvgElement(
|
|
@@ -341,7 +359,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
341
359
|
Blockly.utils.dom.createSvgElement(
|
|
342
360
|
'line',
|
|
343
361
|
{
|
|
344
|
-
stroke:
|
|
362
|
+
stroke: parentTertiary,
|
|
345
363
|
x1: 0,
|
|
346
364
|
y1: FieldNote.TOP_MENU_HEIGHT,
|
|
347
365
|
x2: this.fieldEditorWidth_,
|
|
@@ -365,11 +383,12 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
365
383
|
)
|
|
366
384
|
|
|
367
385
|
// Octave buttons
|
|
368
|
-
const octaveDownButton = this.addOctaveButton_(0, true, svg)
|
|
386
|
+
const octaveDownButton = this.addOctaveButton_(0, true, svg, parentBlock)
|
|
369
387
|
const octaveUpButton = this.addOctaveButton_(
|
|
370
388
|
this.fieldEditorWidth_ + FieldNote.INSET * 2 - FieldNote.OCTAVE_BUTTON_SIZE,
|
|
371
389
|
false,
|
|
372
390
|
svg,
|
|
391
|
+
parentBlock,
|
|
373
392
|
)
|
|
374
393
|
|
|
375
394
|
this.octaveDownMouseDownWrapper_ = Blockly.browserEvents.bind(octaveDownButton, 'mousedown', this, () => {
|
|
@@ -379,8 +398,9 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
379
398
|
this.changeOctaveBy_(1)
|
|
380
399
|
})
|
|
381
400
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg
|
|
382
|
-
Blockly.
|
|
383
|
-
Blockly.DropDownDiv.
|
|
401
|
+
const dropdownAnchor = this as unknown as Blockly.Field<string | null>
|
|
402
|
+
Blockly.DropDownDiv.setColour(parentColour, parentTertiary)
|
|
403
|
+
Blockly.DropDownDiv.showPositionedByBlock(dropdownAnchor, sourceBlock)
|
|
384
404
|
|
|
385
405
|
this.updateSelection_()
|
|
386
406
|
}
|
|
@@ -391,14 +411,17 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
391
411
|
* @param whiteKeyGroup The group for all white piano keys.
|
|
392
412
|
* @param blackKeyGroup The group for all black piano keys.
|
|
393
413
|
* @param keySVGarray An array containing all the key SVGs.
|
|
414
|
+
* @param parentBlock The validated parent block providing styling.
|
|
394
415
|
*/
|
|
395
416
|
private addPianoOctave_(
|
|
396
417
|
x: number,
|
|
397
418
|
whiteKeyGroup: SVGElement,
|
|
398
419
|
blackKeyGroup: SVGElement,
|
|
399
420
|
keySVGarray: SVGElement[] | null,
|
|
421
|
+
parentBlock: Blockly.BlockSvg,
|
|
400
422
|
) {
|
|
401
423
|
let xIncrement, width, height, fill, stroke, group
|
|
424
|
+
const parentTertiary = parentBlock.getColourTertiary()
|
|
402
425
|
x += FieldNote.EDGE_PADDING / 2
|
|
403
426
|
const y = FieldNote.TOP_MENU_HEIGHT
|
|
404
427
|
for (let i = 0; i < FieldNote.KEY_INFO.length; i++) {
|
|
@@ -417,7 +440,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
417
440
|
width = FieldNote.WHITE_KEY_WIDTH
|
|
418
441
|
height = FieldNote.WHITE_KEY_HEIGHT
|
|
419
442
|
fill = FieldNote.WHITE_KEY_COLOR
|
|
420
|
-
stroke =
|
|
443
|
+
stroke = parentTertiary
|
|
421
444
|
group = whiteKeyGroup
|
|
422
445
|
}
|
|
423
446
|
const attr = {
|
|
@@ -435,8 +458,18 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
435
458
|
keySVG.setAttribute('data-name', `${FieldNote.KEY_INFO[i].name}`)
|
|
436
459
|
keySVG.setAttribute('data-isBlack', `${FieldNote.KEY_INFO[i].isBlack}`)
|
|
437
460
|
|
|
438
|
-
this.mouseDownWrappers_[i] = Blockly.browserEvents.bind(
|
|
439
|
-
|
|
461
|
+
this.mouseDownWrappers_[i] = Blockly.browserEvents.bind(
|
|
462
|
+
keySVG,
|
|
463
|
+
'mousedown',
|
|
464
|
+
this,
|
|
465
|
+
this.onMouseDownOnKey_.bind(this),
|
|
466
|
+
)
|
|
467
|
+
this.mouseEnterWrappers_[i] = Blockly.browserEvents.bind(
|
|
468
|
+
keySVG,
|
|
469
|
+
'mouseenter',
|
|
470
|
+
this,
|
|
471
|
+
this.onMouseEnter_.bind(this),
|
|
472
|
+
)
|
|
440
473
|
}
|
|
441
474
|
}
|
|
442
475
|
}
|
|
@@ -502,10 +535,12 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
502
535
|
* @param x The x position of the button.
|
|
503
536
|
* @param flipped If true, the icon should be flipped.
|
|
504
537
|
* @param svg The svg element to add the buttons to.
|
|
538
|
+
* @param parentBlock The validated parent block providing styling.
|
|
505
539
|
* @returns A group containing the button SVG elements.
|
|
506
540
|
*/
|
|
507
|
-
private addOctaveButton_(x: number, flipped: boolean, svg: SVGElement): SVGElement {
|
|
541
|
+
private addOctaveButton_(x: number, flipped: boolean, svg: SVGElement, parentBlock: Blockly.BlockSvg): SVGElement {
|
|
508
542
|
const group = Blockly.utils.dom.createSvgElement('g', {}, svg)
|
|
543
|
+
const parentTertiary = parentBlock.getColourTertiary()
|
|
509
544
|
const imageSize = FieldNote.OCTAVE_BUTTON_SIZE
|
|
510
545
|
const arrow = Blockly.utils.dom.createSvgElement(
|
|
511
546
|
'image',
|
|
@@ -525,7 +560,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
525
560
|
Blockly.utils.dom.createSvgElement(
|
|
526
561
|
'line',
|
|
527
562
|
{
|
|
528
|
-
stroke:
|
|
563
|
+
stroke: parentTertiary,
|
|
529
564
|
x1: x - FieldNote.INSET,
|
|
530
565
|
y1: 0,
|
|
531
566
|
x2: x - FieldNote.INSET,
|
|
@@ -588,7 +623,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
588
623
|
*/
|
|
589
624
|
private onMouseDownOnKey_(e: PointerEvent) {
|
|
590
625
|
this.mouseIsDown_ = true
|
|
591
|
-
this.mouseUpWrapper_ = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp_)
|
|
626
|
+
this.mouseUpWrapper_ = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp_.bind(this))
|
|
592
627
|
this.selectNoteWithMouseEvent_(e)
|
|
593
628
|
}
|
|
594
629
|
|
|
@@ -628,18 +663,19 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
628
663
|
* Play a note, by calling the externally overriden play note function.
|
|
629
664
|
*/
|
|
630
665
|
private playNoteInternal_() {
|
|
631
|
-
|
|
632
|
-
|
|
666
|
+
const noteNum = this.getValue()
|
|
667
|
+
if (FieldNote.playNote_ && noteNum !== null) {
|
|
668
|
+
FieldNote.playNote_(Number(noteNum), 'Music')
|
|
633
669
|
}
|
|
634
670
|
}
|
|
635
671
|
|
|
636
672
|
/**
|
|
637
673
|
* Function to play a musical note corresponding to the key selected.
|
|
638
674
|
* Overridden externally.
|
|
639
|
-
* @param
|
|
640
|
-
* @param
|
|
675
|
+
* @param _noteNum the MIDI note number to play.
|
|
676
|
+
* @param _id An id to select a scratch extension to play the note.
|
|
641
677
|
*/
|
|
642
|
-
static playNote_ = function (
|
|
678
|
+
static playNote_: ((noteNum: number, id: string) => void) | null = function (_noteNum: number, _id: string) {
|
|
643
679
|
return
|
|
644
680
|
}
|
|
645
681
|
|
|
@@ -739,7 +775,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
739
775
|
this.noteNameText_.textContent = noteName + ' (' + Math.floor(noteNum) + ')'
|
|
740
776
|
}
|
|
741
777
|
// Update the low and high C note names
|
|
742
|
-
const lowCNum =
|
|
778
|
+
const lowCNum = this.displayedOctave_ * 12
|
|
743
779
|
if (this.lowCText_) this.lowCText_.textContent = 'C(' + lowCNum + ')'
|
|
744
780
|
if (this.highCText_) this.highCText_.textContent = 'C(' + (lowCNum + 12) + ')'
|
|
745
781
|
}
|
|
@@ -750,7 +786,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
750
786
|
* @param text The user's text.
|
|
751
787
|
* @returns A string representing a valid note number, or null if invalid.
|
|
752
788
|
*/
|
|
753
|
-
doClassValidation_(text: string): string | null {
|
|
789
|
+
doClassValidation_(text: string | null): string | null {
|
|
754
790
|
if (text === null) {
|
|
755
791
|
return null
|
|
756
792
|
}
|
|
@@ -35,19 +35,28 @@ export class FieldTextInputRemovable extends Blockly.FieldTextInput {
|
|
|
35
35
|
showEditor_() {
|
|
36
36
|
// Wait for our parent block to render so we can examine its metrics to
|
|
37
37
|
// calculate rounded corners on the editor as needed.
|
|
38
|
-
Blockly.renderManagement.finishQueuedRenders().then(() => {
|
|
38
|
+
void Blockly.renderManagement.finishQueuedRenders().then(() => {
|
|
39
39
|
super.showEditor_()
|
|
40
40
|
|
|
41
|
-
const div = Blockly.WidgetDiv.getDiv()
|
|
41
|
+
const div = Blockly.WidgetDiv.getDiv()
|
|
42
|
+
if (!div) {
|
|
43
|
+
console.error('[field_textinput_removable] Missing WidgetDiv for removable text input')
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
if (!this.sourceBlock_) {
|
|
47
|
+
console.error('[field_textinput_removable] Missing source block for removable text input')
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
42
51
|
div.className += ' removableTextInput'
|
|
43
52
|
const removeButton = document.createElement('img')
|
|
44
53
|
removeButton.className = 'blocklyTextRemoveIcon'
|
|
45
|
-
removeButton.setAttribute('src', this.sourceBlock_
|
|
54
|
+
removeButton.setAttribute('src', this.sourceBlock_.workspace.options.pathToMedia + 'icons/remove.svg')
|
|
46
55
|
this.removeButtonMouseWrapper_ = Blockly.browserEvents.bind(
|
|
47
56
|
removeButton,
|
|
48
57
|
'mousedown',
|
|
49
58
|
this,
|
|
50
|
-
this.removeCallback_,
|
|
59
|
+
this.removeCallback_.bind(this),
|
|
51
60
|
)
|
|
52
61
|
div.appendChild(removeButton)
|
|
53
62
|
})
|
|
@@ -70,8 +70,13 @@ class FieldVariableGetter extends Blockly.FieldLabel {
|
|
|
70
70
|
*/
|
|
71
71
|
doValueUpdate_(newVariableId: string) {
|
|
72
72
|
super.doValueUpdate_(newVariableId)
|
|
73
|
-
const
|
|
74
|
-
|
|
73
|
+
const sourceBlock = this.getSourceBlock()
|
|
74
|
+
if (!sourceBlock) {
|
|
75
|
+
console.error('[field_variable_getter] Missing source block in doValueUpdate_')
|
|
76
|
+
this.variable = null
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
this.variable = Blockly.Variables.getVariable(sourceBlock.workspace, newVariableId)
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
/**
|
|
@@ -92,13 +97,22 @@ class FieldVariableGetter extends Blockly.FieldLabel {
|
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
fromXml(element: Element) {
|
|
95
|
-
|
|
100
|
+
const id = element.getAttribute('id')
|
|
101
|
+
if (!id) {
|
|
102
|
+
console.error('[field_variable_getter] Missing variable id in XML')
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
this.setValue(id)
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
toXml(element: Element): Element {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
if (!this.variable) {
|
|
110
|
+
console.error('[field_variable_getter] Missing variable in toXml')
|
|
111
|
+
return element
|
|
112
|
+
}
|
|
113
|
+
element.setAttribute('id', this.variable.getId())
|
|
114
|
+
element.setAttribute('variabletype', this.variable.getType())
|
|
115
|
+
element.textContent = this.variable.getName()
|
|
102
116
|
return element
|
|
103
117
|
}
|
|
104
118
|
}
|
|
@@ -73,7 +73,11 @@ class FieldVerticalSeparator extends Blockly.Field {
|
|
|
73
73
|
* @package
|
|
74
74
|
*/
|
|
75
75
|
setLineHeight(newHeight: number) {
|
|
76
|
-
this.lineElement
|
|
76
|
+
if (!this.lineElement) {
|
|
77
|
+
console.error('[field_vertical_separator] Missing lineElement in setLineHeight')
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
this.lineElement.setAttribute('y2', `${newHeight}`)
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
/**
|
|
@@ -47,17 +47,17 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
47
47
|
/**
|
|
48
48
|
* Opaque identifier used to unbind event listener in dispose().
|
|
49
49
|
*/
|
|
50
|
-
private mouseDownWrapper_
|
|
50
|
+
private mouseDownWrapper_?: Blockly.browserEvents.Data
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Opaque identifier used to unbind event listener in dispose().
|
|
54
54
|
*/
|
|
55
|
-
private mouseMoveWrapper
|
|
55
|
+
private mouseMoveWrapper?: Blockly.browserEvents.Data
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Opaque identifier used to unbind event listener in dispose().
|
|
59
59
|
*/
|
|
60
|
-
private mouseUpWrapper
|
|
60
|
+
private mouseUpWrapper?: Blockly.browserEvents.Data
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Round angles to the nearest 15 degrees when using mouse.
|
|
@@ -164,6 +164,14 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
164
164
|
Blockly.DropDownDiv.hideWithoutAnimation()
|
|
165
165
|
Blockly.DropDownDiv.clearContent()
|
|
166
166
|
const div = Blockly.DropDownDiv.getContentDiv()
|
|
167
|
+
const sourceBlock = this.getSourceBlock()
|
|
168
|
+
if (!(sourceBlock instanceof Blockly.BlockSvg)) {
|
|
169
|
+
throw new Error('[scratch_field_angle] Missing source BlockSvg for showEditor_')
|
|
170
|
+
}
|
|
171
|
+
const parentBlock = sourceBlock.getParent()
|
|
172
|
+
if (!parentBlock) {
|
|
173
|
+
throw new Error('[scratch_field_angle] Missing parent block for showEditor_')
|
|
174
|
+
}
|
|
167
175
|
// Build the SVG DOM.
|
|
168
176
|
const svg = Blockly.utils.dom.createSvgElement(
|
|
169
177
|
'svg',
|
|
@@ -183,8 +191,8 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
183
191
|
cx: this.HALF,
|
|
184
192
|
cy: this.HALF,
|
|
185
193
|
r: this.RADIUS,
|
|
186
|
-
fill:
|
|
187
|
-
stroke:
|
|
194
|
+
fill: parentBlock.getColourSecondary(),
|
|
195
|
+
stroke: parentBlock.getColourTertiary(),
|
|
188
196
|
class: 'blocklyAngleCircle',
|
|
189
197
|
},
|
|
190
198
|
svg,
|
|
@@ -268,13 +276,10 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
268
276
|
Blockly.getMainWorkspace().options.pathToMedia + this.ARROW_SVG_PATH,
|
|
269
277
|
)
|
|
270
278
|
|
|
271
|
-
Blockly.DropDownDiv.setColour(
|
|
272
|
-
|
|
273
|
-
(this.getSourceBlock()!.getParent() as Blockly.BlockSvg).getColourTertiary(),
|
|
274
|
-
)
|
|
275
|
-
Blockly.DropDownDiv.showPositionedByBlock(this, this.getSourceBlock() as Blockly.BlockSvg)
|
|
279
|
+
Blockly.DropDownDiv.setColour(parentBlock.getColour(), parentBlock.getColourTertiary())
|
|
280
|
+
Blockly.DropDownDiv.showPositionedByBlock(this as Blockly.Field<string | number | null>, sourceBlock)
|
|
276
281
|
|
|
277
|
-
this.mouseDownWrapper_ = Blockly.browserEvents.bind(this.handle, 'mousedown', this, this.onMouseDown)
|
|
282
|
+
this.mouseDownWrapper_ = Blockly.browserEvents.bind(this.handle, 'mousedown', this, this.onMouseDown.bind(this))
|
|
278
283
|
|
|
279
284
|
this.updateGraph()
|
|
280
285
|
}
|
|
@@ -283,16 +288,20 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
283
288
|
* Set the angle to match the mouse's position.
|
|
284
289
|
*/
|
|
285
290
|
onMouseDown() {
|
|
286
|
-
this.mouseMoveWrapper = Blockly.browserEvents.bind(document.body, 'mousemove', this, this.onMouseMove)
|
|
287
|
-
this.mouseUpWrapper = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp)
|
|
291
|
+
this.mouseMoveWrapper = Blockly.browserEvents.bind(document.body, 'mousemove', this, this.onMouseMove.bind(this))
|
|
292
|
+
this.mouseUpWrapper = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp.bind(this))
|
|
288
293
|
}
|
|
289
294
|
|
|
290
295
|
/**
|
|
291
296
|
* Set the angle to match the mouse's position.
|
|
292
297
|
*/
|
|
293
298
|
onMouseUp() {
|
|
294
|
-
|
|
295
|
-
|
|
299
|
+
if (this.mouseMoveWrapper) {
|
|
300
|
+
Blockly.browserEvents.unbind(this.mouseMoveWrapper)
|
|
301
|
+
}
|
|
302
|
+
if (this.mouseUpWrapper) {
|
|
303
|
+
Blockly.browserEvents.unbind(this.mouseUpWrapper)
|
|
304
|
+
}
|
|
296
305
|
}
|
|
297
306
|
|
|
298
307
|
/**
|
|
@@ -301,7 +310,9 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
301
310
|
*/
|
|
302
311
|
onMouseMove(e: PointerEvent) {
|
|
303
312
|
e.preventDefault()
|
|
304
|
-
const
|
|
313
|
+
const ownerSvg = this.gauge?.ownerSVGElement
|
|
314
|
+
if (!ownerSvg) return
|
|
315
|
+
const bBox = ownerSvg.getBoundingClientRect()
|
|
305
316
|
const dx = e.clientX - bBox.left - this.HALF
|
|
306
317
|
const dy = e.clientY - bBox.top - this.HALF
|
|
307
318
|
let angle = Math.atan(-dy / dx)
|
|
@@ -383,12 +394,12 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
383
394
|
} else {
|
|
384
395
|
imageRotation = -angleDegrees
|
|
385
396
|
}
|
|
386
|
-
this.arrow
|
|
397
|
+
this.arrow?.setAttribute('transform', 'rotate(' + imageRotation + ')')
|
|
387
398
|
}
|
|
388
399
|
this.gauge.setAttribute('d', path.join(''))
|
|
389
|
-
this.line
|
|
390
|
-
this.line
|
|
391
|
-
this.handle
|
|
400
|
+
this.line?.setAttribute('x2', `${x2}`)
|
|
401
|
+
this.line?.setAttribute('y2', `${y2}`)
|
|
402
|
+
this.handle?.setAttribute('transform', 'translate(' + x2 + ',' + y2 + ')')
|
|
392
403
|
}
|
|
393
404
|
|
|
394
405
|
/**
|
|
@@ -396,7 +407,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
396
407
|
* @param text The user's text.
|
|
397
408
|
* @returns A string representing a valid angle, or null if invalid.
|
|
398
409
|
*/
|
|
399
|
-
doClassValidation_(text: string): number | null {
|
|
410
|
+
doClassValidation_(text: string | null): number | null {
|
|
400
411
|
if (text === null) {
|
|
401
412
|
return null
|
|
402
413
|
}
|
|
@@ -17,14 +17,18 @@ class ScratchFieldDropdown extends Blockly.FieldDropdown {
|
|
|
17
17
|
} else if (this.borderRect_) {
|
|
18
18
|
this.borderRect_.setAttribute(
|
|
19
19
|
'fill',
|
|
20
|
-
'colourQuaternary' in style ?
|
|
20
|
+
'colourQuaternary' in style ? String(style.colourQuaternary) : style.colourTertiary,
|
|
21
21
|
)
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
dropdownDispose_() {
|
|
26
26
|
super.dropdownDispose_()
|
|
27
|
-
const sourceBlock = this.getSourceBlock()
|
|
27
|
+
const sourceBlock = this.getSourceBlock()
|
|
28
|
+
if (!sourceBlock) {
|
|
29
|
+
console.error('[scratch_field_dropdown] Missing source block in dropdownDispose_')
|
|
30
|
+
return
|
|
31
|
+
}
|
|
28
32
|
if (sourceBlock.isShadow()) {
|
|
29
33
|
sourceBlock.setStyle(this.originalStyle)
|
|
30
34
|
}
|
|
@@ -110,14 +110,14 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
110
110
|
* appropriate.
|
|
111
111
|
* @param e The triggering pointer event.
|
|
112
112
|
*/
|
|
113
|
-
showEditor_(e
|
|
113
|
+
showEditor_(e?: PointerEvent) {
|
|
114
114
|
// Do not focus on mobile devices so we can show the num-pad
|
|
115
115
|
const showNumPad = e?.pointerType === 'touch'
|
|
116
116
|
super.showEditor_(e, showNumPad)
|
|
117
117
|
|
|
118
118
|
// Show a numeric keypad in the drop-down on touch
|
|
119
119
|
if (showNumPad) {
|
|
120
|
-
this.htmlInput_
|
|
120
|
+
this.htmlInput_?.select()
|
|
121
121
|
this.showNumPad_()
|
|
122
122
|
}
|
|
123
123
|
}
|
|
@@ -148,7 +148,10 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
148
148
|
|
|
149
149
|
// Set colour and size of drop-down
|
|
150
150
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg
|
|
151
|
-
|
|
151
|
+
const parentBlock = sourceBlock.getParent()
|
|
152
|
+
if (parentBlock) {
|
|
153
|
+
Blockly.DropDownDiv.setColour(parentBlock.getColour(), sourceBlock.getColourTertiary())
|
|
154
|
+
}
|
|
152
155
|
contentDiv.style.width = ScratchFieldNumber.DROPDOWN_WIDTH + 'px'
|
|
153
156
|
|
|
154
157
|
this.position_()
|
|
@@ -176,7 +179,7 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
176
179
|
Blockly.DropDownDiv.setBoundsElement(sourceBlock.workspace.getParentSvg().parentElement)
|
|
177
180
|
Blockly.DropDownDiv.show(
|
|
178
181
|
this,
|
|
179
|
-
|
|
182
|
+
sourceBlock.RTL,
|
|
180
183
|
primaryX,
|
|
181
184
|
primaryY,
|
|
182
185
|
secondaryX,
|
|
@@ -193,8 +196,9 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
193
196
|
*/
|
|
194
197
|
private addButtons_(contentDiv: Element) {
|
|
195
198
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg
|
|
196
|
-
const
|
|
197
|
-
const
|
|
199
|
+
const parent = sourceBlock.getParent()
|
|
200
|
+
const buttonColour = parent?.getColour() ?? sourceBlock.getColour()
|
|
201
|
+
const buttonBorderColour = parent?.getColourTertiary() ?? sourceBlock.getColourTertiary()
|
|
198
202
|
|
|
199
203
|
// Add numeric keypad buttons
|
|
200
204
|
const buttons = ScratchFieldNumber.NUMPAD_BUTTONS
|
|
@@ -248,10 +252,12 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
248
252
|
// String of the button (e.g., '7')
|
|
249
253
|
const spliceValue = (e.target as HTMLElement).innerText
|
|
250
254
|
// Old value of the text field
|
|
251
|
-
const
|
|
255
|
+
const htmlInput = this.htmlInput_
|
|
256
|
+
if (!htmlInput) return
|
|
257
|
+
const oldValue = htmlInput.value
|
|
252
258
|
// Determine the selected portion of the text field
|
|
253
|
-
const selectionStart =
|
|
254
|
-
const selectionEnd =
|
|
259
|
+
const selectionStart = htmlInput.selectionStart ?? 0
|
|
260
|
+
const selectionEnd = htmlInput.selectionEnd ?? 0
|
|
255
261
|
|
|
256
262
|
// Splice in the new value
|
|
257
263
|
const newValue = oldValue.slice(0, selectionStart) + spliceValue + oldValue.slice(selectionEnd)
|
|
@@ -273,10 +279,12 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
273
279
|
*/
|
|
274
280
|
numPadEraseButtonTouch(e: PointerEvent) {
|
|
275
281
|
// Old value of the text field
|
|
276
|
-
const
|
|
282
|
+
const htmlInput = this.htmlInput_
|
|
283
|
+
if (!htmlInput) return
|
|
284
|
+
const oldValue = htmlInput.value
|
|
277
285
|
// Determine what is selected to erase (if anything)
|
|
278
|
-
let selectionStart =
|
|
279
|
-
const selectionEnd =
|
|
286
|
+
let selectionStart = htmlInput.selectionStart ?? 0
|
|
287
|
+
const selectionEnd = htmlInput.selectionEnd ?? 0
|
|
280
288
|
|
|
281
289
|
// If selection is zero-length, shift start to the left 1 character
|
|
282
290
|
if (selectionStart == selectionEnd) {
|
|
@@ -303,7 +311,8 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
303
311
|
private updateDisplay_(newValue: string, newSelection: number) {
|
|
304
312
|
this.setEditorValue_(newValue)
|
|
305
313
|
// Resize and scroll the text field appropriately
|
|
306
|
-
const htmlInput = this.htmlInput_
|
|
314
|
+
const htmlInput = this.htmlInput_
|
|
315
|
+
if (!htmlInput) return
|
|
307
316
|
htmlInput.setSelectionRange(newSelection, newSelection)
|
|
308
317
|
htmlInput.scrollLeft = htmlInput.scrollWidth
|
|
309
318
|
}
|