Files
blockly/core/events/events_block_change.ts
Maribeth Bottorff 037eb59b89 chore: Lint TsDoc. (#6353)
* chore: add linting for tsdoc

* chore: don't require types on return

* chore: remove redundant fileoverview from ts

* chore: change return to returns and add some newlines

* chore: remove license tag

* chore: don't require params/return docs

* chore: remove spurious struct tags

* Revert "chore: change return to returns and add some newlines"

This reverts commit d6d8656a45.

* chore: don't auto-add param names

* chore: disable require-param bc it breaks on this

* return to returns and add line breaks

* chore: configure additional jsdoc rules

* chore: run format

* Revert "chore: remove license tag"

This reverts commit 173455588a.

* chore: allow license tag format

* chore: only require jsdoc on exported items

* chore: add missing jsdoc or silence where needed

* chore: run format

* chore: lint fixes
2022-08-23 14:27:22 -07:00

180 lines
5.2 KiB
TypeScript

/**
* @license
* Copyright 2018 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Class for a block change event.
*
* @class
*/
import * as goog from '../../closure/goog/goog.js';
goog.declareModuleId('Blockly.Events.BlockChange');
import type {Block} from '../block.js';
import type {BlockSvg} from '../block_svg.js';
import * as registry from '../registry.js';
import * as Xml from '../xml.js';
import {BlockBase} from './events_block_base.js';
import * as eventUtils from './utils.js';
/**
* Class for a block change event.
*
* @alias Blockly.Events.BlockChange
*/
export class BlockChange extends BlockBase {
override type: string;
// TODO(b/109816955): remove '!', see go/strict-prop-init-fix.
element!: string;
// TODO(b/109816955): remove '!', see go/strict-prop-init-fix.
name!: string|null;
oldValue: AnyDuringMigration;
newValue: AnyDuringMigration;
/**
* @param opt_block The changed block. Undefined for a blank event.
* @param opt_element One of 'field', 'comment', 'disabled', etc.
* @param opt_name Name of input or field affected, or null.
* @param opt_oldValue Previous value of element.
* @param opt_newValue New value of element.
*/
constructor(
opt_block?: Block, opt_element?: string, opt_name?: string|null,
opt_oldValue?: AnyDuringMigration, opt_newValue?: AnyDuringMigration) {
super(opt_block);
/** Type of this event. */
this.type = eventUtils.BLOCK_CHANGE;
if (!opt_block) {
return; // Blank event to be populated by fromJson.
}
this.element = typeof opt_element === 'undefined' ? '' : opt_element;
this.name = typeof opt_name === 'undefined' ? '' : opt_name;
this.oldValue = typeof opt_oldValue === 'undefined' ? '' : opt_oldValue;
this.newValue = typeof opt_newValue === 'undefined' ? '' : opt_newValue;
}
/**
* Encode the event as JSON.
*
* @returns JSON representation.
*/
override toJson(): AnyDuringMigration {
const json = super.toJson();
json['element'] = this.element;
if (this.name) {
json['name'] = this.name;
}
json['oldValue'] = this.oldValue;
json['newValue'] = this.newValue;
return json;
}
/**
* Decode the JSON event.
*
* @param json JSON representation.
*/
override fromJson(json: AnyDuringMigration) {
super.fromJson(json);
this.element = json['element'];
this.name = json['name'];
this.oldValue = json['oldValue'];
this.newValue = json['newValue'];
}
/**
* Does this event record any change of state?
*
* @returns False if something changed.
*/
override isNull(): boolean {
return this.oldValue === this.newValue;
}
/**
* Run a change event.
*
* @param forward True if run forward, false if run backward (undo).
*/
override run(forward: boolean) {
const workspace = this.getEventWorkspace_();
const block = workspace.getBlockById(this.blockId);
if (!block) {
console.warn('Can\'t change non-existent block: ' + this.blockId);
return;
}
// Assume the block is rendered so that then we can check.
const blockSvg = block as BlockSvg;
if (blockSvg.mutator) {
// Close the mutator (if open) since we don't want to update it.
blockSvg.mutator.setVisible(false);
}
const value = forward ? this.newValue : this.oldValue;
switch (this.element) {
case 'field': {
const field = block.getField(this.name!);
if (field) {
field.setValue(value);
} else {
console.warn('Can\'t set non-existent field: ' + this.name);
}
break;
}
case 'comment':
block.setCommentText(value as string || null);
break;
case 'collapsed':
block.setCollapsed(!!value);
break;
case 'disabled':
block.setEnabled(!value);
break;
case 'inline':
block.setInputsInline(!!value);
break;
case 'mutation': {
const oldState = BlockChange.getExtraBlockState_(block as BlockSvg);
if (block.loadExtraState) {
block.loadExtraState(JSON.parse(value as string || '{}'));
} else if (block.domToMutation) {
block.domToMutation(Xml.textToDom(value as string || '<mutation/>'));
}
eventUtils.fire(
new BlockChange(block, 'mutation', null, oldState, value));
break;
}
default:
console.warn('Unknown change type: ' + this.element);
}
}
// TODO (#5397): Encapsulate this in the BlocklyMutationChange event when
// refactoring change events.
/**
* Returns the extra state of the given block (either as XML or a JSO,
* depending on the block's definition).
*
* @param block The block to get the extra state of.
* @returns A stringified version of the extra state of the given block.
* @internal
*/
static getExtraBlockState_(block: BlockSvg): string {
if (block.saveExtraState) {
const state = block.saveExtraState();
return state ? JSON.stringify(state) : '';
} else if (block.mutationToDom) {
const state = block.mutationToDom();
return state ? Xml.domToText(state) : '';
}
return '';
}
}
registry.register(registry.Type.EVENT, eventUtils.CHANGE, BlockChange);