From 82c7aad4e7382f4cabfaed1000bd78725a665f07 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 29 Jul 2024 12:00:52 -0700 Subject: [PATCH] feat: Add a VarTypeChange event. (#8402) * feat: Add a VarTypeChange event. * chore: Update copyright date. * refactor: Inline fields in the constructor. --- core/events/events.ts | 4 + core/events/events_var_type_change.ts | 122 ++++++++++++++++++++++ core/events/utils.ts | 5 + tests/mocha/event_var_type_change_test.js | 43 ++++++++ tests/mocha/index.html | 1 + 5 files changed, 175 insertions(+) create mode 100644 core/events/events_var_type_change.ts create mode 100644 tests/mocha/event_var_type_change_test.js diff --git a/core/events/events.ts b/core/events/events.ts index b31cf7dc7..67c78203f 100644 --- a/core/events/events.ts +++ b/core/events/events.ts @@ -43,6 +43,7 @@ import {VarBase, VarBaseJson} from './events_var_base.js'; import {VarCreate, VarCreateJson} from './events_var_create.js'; import {VarDelete, VarDeleteJson} from './events_var_delete.js'; import {VarRename, VarRenameJson} from './events_var_rename.js'; +import {VarTypeChange, VarTypeChangeJson} from './events_var_type_change.js'; import {ViewportChange, ViewportChangeJson} from './events_viewport.js'; import * as eventUtils from './utils.js'; import {FinishedLoading} from './workspace_events.js'; @@ -105,6 +106,8 @@ export {VarDelete}; export {VarDeleteJson}; export {VarRename}; export {VarRenameJson}; +export {VarTypeChange}; +export {VarTypeChangeJson}; export {ViewportChange}; export {ViewportChangeJson}; @@ -140,6 +143,7 @@ export const UI = eventUtils.UI; export const VAR_CREATE = eventUtils.VAR_CREATE; export const VAR_DELETE = eventUtils.VAR_DELETE; export const VAR_RENAME = eventUtils.VAR_RENAME; +export const VAR_TYPE_CHAGE = eventUtils.VAR_TYPE_CHANGE; export const VIEWPORT_CHANGE = eventUtils.VIEWPORT_CHANGE; // Event utils. diff --git a/core/events/events_var_type_change.ts b/core/events/events_var_type_change.ts new file mode 100644 index 000000000..ab8686620 --- /dev/null +++ b/core/events/events_var_type_change.ts @@ -0,0 +1,122 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Class for a variable type change event. + * + * @class + */ + +import * as registry from '../registry.js'; +import type { + IVariableModel, + IVariableState, +} from '../interfaces/i_variable_model.js'; + +import {VarBase, VarBaseJson} from './events_var_base.js'; +import * as eventUtils from './utils.js'; +import type {Workspace} from '../workspace.js'; + +/** + * Notifies listeners that a variable's type has changed. + */ +export class VarTypeChange extends VarBase { + override type = eventUtils.VAR_TYPE_CHANGE; + + /** + * @param variable The variable whose type changed. Undefined for a blank event. + * @param oldType The old type of the variable. Undefined for a blank event. + * @param newType The new type of the variable. Undefined for a blank event. + */ + constructor( + variable?: IVariableModel, + public oldType?: string, + public newType?: string, + ) { + super(variable); + } + + /** + * Encode the event as JSON. + * + * @returns JSON representation. + */ + override toJson(): VarTypeChangeJson { + const json = super.toJson() as VarTypeChangeJson; + if (!this.oldType || !this.newType) { + throw new Error( + "The variable's types are undefined. Either pass them to " + + 'the constructor, or call fromJson', + ); + } + json['oldType'] = this.oldType; + json['newType'] = this.newType; + return json; + } + + /** + * Deserializes the JSON event. + * + * @param event The event to append new properties to. Should be a subclass + * of VarTypeChange, but we can't specify that due to the fact that + * parameters to static methods in subclasses must be supertypes of + * parameters to static methods in superclasses. + * @internal + */ + static fromJson( + json: VarTypeChangeJson, + workspace: Workspace, + event?: any, + ): VarTypeChange { + const newEvent = super.fromJson( + json, + workspace, + event ?? new VarTypeChange(), + ) as VarTypeChange; + newEvent.oldType = json['oldType']; + newEvent.newType = json['newType']; + return newEvent; + } + + /** + * Run a variable type change event. + * + * @param forward True if run forward, false if run backward (undo). + */ + override run(forward: boolean) { + const workspace = this.getEventWorkspace_(); + if (!this.varId) { + throw new Error( + 'The var ID is undefined. Either pass a variable to ' + + 'the constructor, or call fromJson', + ); + } + if (!this.oldType || !this.newType) { + throw new Error( + "The variable's types are undefined. Either pass them to " + + 'the constructor, or call fromJson', + ); + } + const variable = workspace.getVariableMap().getVariableById(this.varId); + if (!variable) return; + if (forward) { + workspace.getVariableMap().changeVariableType(variable, this.newType); + } else { + workspace.getVariableMap().changeVariableType(variable, this.oldType); + } + } +} + +export interface VarTypeChangeJson extends VarBaseJson { + oldType: string; + newType: string; +} + +registry.register( + registry.Type.EVENT, + eventUtils.VAR_TYPE_CHANGE, + VarTypeChange, +); diff --git a/core/events/utils.ts b/core/events/utils.ts index 2d434594b..dc05b632e 100644 --- a/core/events/utils.ts +++ b/core/events/utils.ts @@ -111,6 +111,11 @@ export const VAR_DELETE = 'var_delete'; */ export const VAR_RENAME = 'var_rename'; +/** + * Name of event that changes a variable's type. + */ +export const VAR_TYPE_CHANGE = 'var_type_change'; + /** * Name of generic event that records a UI change. */ diff --git a/tests/mocha/event_var_type_change_test.js b/tests/mocha/event_var_type_change_test.js new file mode 100644 index 000000000..d19b0421a --- /dev/null +++ b/tests/mocha/event_var_type_change_test.js @@ -0,0 +1,43 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {assert} from '../../node_modules/chai/chai.js'; +import { + sharedTestSetup, + sharedTestTeardown, +} from './test_helpers/setup_teardown.js'; + +suite('Var Type Change Event', function () { + setup(function () { + sharedTestSetup.call(this); + this.workspace = new Blockly.Workspace(); + }); + + teardown(function () { + sharedTestTeardown.call(this); + }); + + suite('Serialization', function () { + test('variable type change events round-trip through JSON', function () { + const varModel = new Blockly.VariableModel( + this.workspace, + 'name', + 'foo', + 'id', + ); + const origEvent = new Blockly.Events.VarTypeChange( + varModel, + 'foo', + 'bar', + ); + + const json = origEvent.toJson(); + const newEvent = new Blockly.Events.fromJson(json, this.workspace); + + assert.deepEqual(newEvent, origEvent); + }); + }); +}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index ff3467907..58a71e0ac 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -76,6 +76,7 @@ import './event_var_create_test.js'; import './event_var_delete_test.js'; import './event_var_rename_test.js'; + import './event_var_type_change_test.js'; import './event_viewport_test.js'; import './extensions_test.js'; import './field_checkbox_test.js';