Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 114 additions & 111 deletions blockly_compressed.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion blockly_compressed.js.map

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions core/block_animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ function disconnectUiStep(group: SVGElement, magnitude: number, start: Date) {
skew = `skewX(${val})`;
disconnectPid = setTimeout(disconnectUiStep, 10, group, magnitude, start);
}
group.setAttribute('transform', skew);
(group as AnyDuringMigration).skew_ = skew;
group.setAttribute(
'transform',
(group as AnyDuringMigration).translate_ +
(group as AnyDuringMigration).skew_);
}

/**
Expand All @@ -202,7 +206,9 @@ export function disconnectUiStop() {
if (disconnectPid) {
clearTimeout(disconnectPid);
}
disconnectGroup.setAttribute('transform', '');
const group = disconnectGroup;
(group as AnyDuringMigration).skew_ = '';
group.setAttribute('transform', (group as AnyDuringMigration).translate_);
disconnectGroup = null;
}
}
42 changes: 33 additions & 9 deletions core/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,7 @@ export abstract class Field implements IASTNodeLocationSvg,
* @returns The block containing this field.
* @throws An error if the source block is not defined.
*/
getSourceBlock(): Block {
if (!this.sourceBlock_) {
throw new Error(`The source block is ${this.sourceBlock_}.`);
}
getSourceBlock(): Block|null {
return this.sourceBlock_;
}

Expand Down Expand Up @@ -476,10 +473,11 @@ export abstract class Field implements IASTNodeLocationSvg,
/** Add or remove the UI indicating if this field is editable or not. */
updateEditable() {
const group = this.fieldGroup_;
if (!this.EDITABLE || !group) {
const block = this.getSourceBlock();
if (!this.EDITABLE || !group || !block) {
return;
}
if (this.enabled_ && this.getSourceBlock().isEditable()) {
if (this.enabled_ && block.isEditable()) {
dom.addClass(group, 'blocklyEditableText');
dom.removeClass(group, 'blocklyNonEditableText');
group.style.cursor = this.CURSOR;
Expand Down Expand Up @@ -756,7 +754,7 @@ export abstract class Field implements IASTNodeLocationSvg,
this.textElement_.setAttribute(
'x',
`${
this.getSourceBlock().RTL ?
this.getSourceBlock()?.RTL ?
this.size_.width - contentWidth - xOffset :
xOffset}`);
this.textElement_.setAttribute(
Expand Down Expand Up @@ -819,12 +817,17 @@ export abstract class Field implements IASTNodeLocationSvg,
let scaledWidth;
let scaledHeight;
let xy;
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}

if (!this.borderRect_) {
// Browsers are inconsistent in what they return for a bounding box.
// - Webkit / Blink: fill-box / object bounding box
// - Gecko: stroke-box
const bBox = (this.sourceBlock_ as BlockSvg).getHeightWidth();
const scale = (this.getSourceBlock().workspace as WorkspaceSvg).scale;
const scale = (block.workspace as WorkspaceSvg).scale;
xy = this.getAbsoluteXY_();
scaledWidth = (bBox.width + 1) * scale;
scaledHeight = (bBox.height + 1) * scale;
Expand Down Expand Up @@ -1158,6 +1161,9 @@ export abstract class Field implements IASTNodeLocationSvg,
getParentInput(): Input {
let parentInput = null;
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
const inputs = block.inputList;

for (let idx = 0; idx < block.inputList.length; idx++) {
Expand Down Expand Up @@ -1241,7 +1247,11 @@ export abstract class Field implements IASTNodeLocationSvg,

/** Redraw any attached marker or cursor svgs if needed. */
protected updateMarkers_() {
const workspace = this.getSourceBlock().workspace as WorkspaceSvg;
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
const workspace = block.workspace as WorkspaceSvg;
if (workspace.keyboardAccessibilityMode && this.cursorSvg_) {
workspace.getCursor()!.draw();
}
Expand All @@ -1264,3 +1274,17 @@ export interface FieldConfig {
* in descendants, though they should contain all of Field's prototype methods.
*/
export type FieldProto = Pick<typeof Field, 'prototype'>;

/**
* Represents an error where the field is trying to access its block or
* information about its block before it has actually been attached to said
* block.
*/
export class UnattachedFieldError extends Error {
/** @internal */
constructor() {
super(
'The field has not yet been attached to its input. ' +
'Call appendField to attach it.');
}
}
10 changes: 7 additions & 3 deletions core/field_angle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {BlockSvg} from './block_svg.js';
import * as browserEvents from './browser_events.js';
import * as Css from './css.js';
import * as dropDownDiv from './dropdowndiv.js';
import {Field} from './field.js';
import {Field, UnattachedFieldError} from './field.js';
import * as fieldRegistry from './field_registry.js';
import {FieldTextInputConfig, FieldTextInput} from './field_textinput.js';
import * as dom from './utils/dom.js';
Expand Down Expand Up @@ -430,18 +430,22 @@ export class FieldAngle extends FieldTextInput {
*/
protected override onHtmlInputKeyDown_(e: Event) {
super.onHtmlInputKeyDown_(e);
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}

let multiplier;
// AnyDuringMigration because: Property 'keyCode' does not exist on type
// 'Event'.
if ((e as AnyDuringMigration).keyCode === KeyCodes.LEFT) {
// decrement (increment in RTL)
multiplier = this.getSourceBlock().RTL ? 1 : -1;
multiplier = block.RTL ? 1 : -1;
// AnyDuringMigration because: Property 'keyCode' does not exist on type
// 'Event'.
} else if ((e as AnyDuringMigration).keyCode === KeyCodes.RIGHT) {
// increment (decrement in RTL)
multiplier = this.getSourceBlock().RTL ? -1 : 1;
multiplier = block.RTL ? -1 : 1;
// AnyDuringMigration because: Property 'keyCode' does not exist on type
// 'Event'.
} else if ((e as AnyDuringMigration).keyCode === KeyCodes.DOWN) {
Expand Down
41 changes: 28 additions & 13 deletions core/field_dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ goog.declareModuleId('Blockly.FieldDropdown');

import type {BlockSvg} from './block_svg.js';
import * as dropDownDiv from './dropdowndiv.js';
import {FieldConfig, Field} from './field.js';
import {FieldConfig, Field, UnattachedFieldError} from './field.js';
import * as fieldRegistry from './field_registry.js';
import {Menu} from './menu.js';
import {MenuItem} from './menuitem.js';
Expand Down Expand Up @@ -217,16 +217,16 @@ export class FieldDropdown extends Field {
protected shouldAddBorderRect_(): boolean {
return !this.getConstants()!.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW ||
this.getConstants()!.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW &&
!this.getSourceBlock().isShadow();
!this.getSourceBlock()?.isShadow();
}

/** Create a tspan based arrow. */
protected createTextArrow_() {
this.arrow_ = dom.createSvgElement(Svg.TSPAN, {}, this.textElement_);
this.arrow_!.appendChild(document.createTextNode(
this.getSourceBlock().RTL ? FieldDropdown.ARROW_CHAR + ' ' :
' ' + FieldDropdown.ARROW_CHAR));
if (this.getSourceBlock().RTL) {
this.getSourceBlock()?.RTL ? FieldDropdown.ARROW_CHAR + ' ' :
' ' + FieldDropdown.ARROW_CHAR));
if (this.getSourceBlock()?.RTL) {
// AnyDuringMigration because: Argument of type 'SVGTSpanElement | null'
// is not assignable to parameter of type 'Node'.
this.getTextElement().insertBefore(
Expand Down Expand Up @@ -258,6 +258,10 @@ export class FieldDropdown extends Field {
* undefined if triggered programmatically.
*/
protected override showEditor_(opt_e?: Event) {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
this.dropdownCreate_();
// AnyDuringMigration because: Property 'clientX' does not exist on type
// 'Event'.
Expand All @@ -279,11 +283,10 @@ export class FieldDropdown extends Field {
dom.addClass(menuElement, 'blocklyDropdownMenu');

if (this.getConstants()!.FIELD_DROPDOWN_COLOURED_DIV) {
const primaryColour = this.getSourceBlock().isShadow() ?
this.getSourceBlock().getParent()!.getColour() :
this.getSourceBlock().getColour();
const borderColour = this.getSourceBlock().isShadow() ?
(this.getSourceBlock().getParent() as BlockSvg).style.colourTertiary :
const primaryColour =
block.isShadow() ? block.getParent()!.getColour() : block.getColour();
const borderColour = block.isShadow() ?
(block.getParent() as BlockSvg).style.colourTertiary :
(this.sourceBlock_ as BlockSvg).style.colourTertiary;
if (!borderColour) {
throw new Error(
Expand All @@ -308,6 +311,10 @@ export class FieldDropdown extends Field {

/** Create the dropdown editor. */
private dropdownCreate_() {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
const menu = new Menu();
menu.setRole(aria.Role.LISTBOX);
this.menu_ = menu;
Expand All @@ -326,7 +333,7 @@ export class FieldDropdown extends Field {
}
const menuItem = new MenuItem(content, value);
menuItem.setRole(aria.Role.OPTION);
menuItem.setRightToLeft(this.getSourceBlock().RTL);
menuItem.setRightToLeft(block.RTL);
menuItem.setCheckable(true);
menu.addChild(menuItem);
menuItem.setChecked(value === this.value_);
Expand Down Expand Up @@ -552,6 +559,10 @@ export class FieldDropdown extends Field {
* @param imageJson Selected option that must be an image.
*/
private renderSelectedImage_(imageJson: ImageProperties) {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
this.imageElement_!.style.display = '';
this.imageElement_!.setAttributeNS(
dom.XLINK_NS, 'xlink:href', imageJson.src);
Expand Down Expand Up @@ -590,7 +601,7 @@ export class FieldDropdown extends Field {
this.size_.height = height;

let arrowX = 0;
if (this.getSourceBlock().RTL) {
if (block.RTL) {
const imageX = xPadding + arrowWidth;
this.imageElement_!.setAttribute('x', imageX.toString());
} else {
Expand Down Expand Up @@ -646,12 +657,16 @@ export class FieldDropdown extends Field {
if (!this.svgArrow_) {
return 0;
}
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
const hasBorder = !!this.borderRect_;
const xPadding =
hasBorder ? this.getConstants()!.FIELD_BORDER_RECT_X_PADDING : 0;
const textPadding = this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_PADDING;
const svgArrowSize = this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_SIZE;
const arrowX = this.getSourceBlock().RTL ? xPadding : x + textPadding;
const arrowX = block.RTL ? xPadding : x + textPadding;
this.svgArrow_.setAttribute(
'transform', 'translate(' + arrowX + ',' + y + ')');
return svgArrowSize + textPadding;
Expand Down
14 changes: 11 additions & 3 deletions core/field_multilineinput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.FieldMultilineInput');

import * as Css from './css.js';
import {Field} from './field.js';
import {Field, UnattachedFieldError} from './field.js';
import * as fieldRegistry from './field_registry.js';
import {FieldTextInputConfig, FieldTextInput} from './field_textinput.js';
import * as aria from './utils/aria.js';
Expand Down Expand Up @@ -163,6 +163,10 @@ export class FieldMultilineInput extends FieldTextInput {
* @returns Currently displayed text.
*/
protected override getDisplayText_(): string {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
let textLines = this.getText();
if (!textLines) {
// Prevent the field from disappearing if empty.
Expand All @@ -189,7 +193,7 @@ export class FieldMultilineInput extends FieldTextInput {
textLines += '\n';
}
}
if (this.getSourceBlock().RTL) {
if (block.RTL) {
// The SVG is LTR, force value to be RTL.
textLines += '\u200F';
}
Expand All @@ -212,6 +216,10 @@ export class FieldMultilineInput extends FieldTextInput {

/** Updates the text of the textElement. */
protected override render_() {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
// Remove all text group children.
let currentChild;
while (currentChild = this.textGroup_.firstChild) {
Expand Down Expand Up @@ -248,7 +256,7 @@ export class FieldMultilineInput extends FieldTextInput {
this.updateSize_();

if (this.isBeingEdited_) {
if (this.getSourceBlock().RTL) {
if (block.RTL) {
// in RTL, we need to let the browser reflow before resizing
// in order to get the correct bounding box of the borderRect
// avoiding issue #2777.
Expand Down
Loading