diff --git a/core/trashcan.ts b/core/trashcan.ts index 5d4d87f58..941850855 100644 --- a/core/trashcan.ts +++ b/core/trashcan.ts @@ -55,7 +55,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, /** * A list of JSON (stored as strings) representing blocks in the trashcan. */ - private readonly contents_: string[] = []; + private readonly contents: string[] = []; /** * The trashcan flyout. @@ -71,28 +71,28 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * The minimum openness of the lid. Used to indicate if the trashcan * contains blocks. */ - private minOpenness_ = 0; + private minOpenness = 0; /** The SVG group containing the trash can. */ - private svgGroup_: SVGElement|null = null; + private svgGroup: SVGElement|null = null; /** The SVG image element of the trash can lid. */ - private svgLid_: SVGElement|null = null; + private svgLid: SVGElement|null = null; /** Task ID of opening/closing animation. */ - private lidTask_: ReturnType|null = null; + private lidTask: ReturnType|null = null; /** Current state of lid opening (0.0 = closed, 1.0 = open). */ - private lidOpen_ = 0; + private lidOpen = 0; /** Left coordinate of the trash can. */ - private left_ = 0; + private left = 0; /** Top coordinate of the trash can. */ - private top_ = 0; + private top = 0; /** Whether this trash can has been initialized. */ - private initialized_ = false; + private initialized = false; /** @param workspace The workspace to sit in. */ constructor(private workspace: WorkspaceSvg) { @@ -133,7 +133,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, registry.Type.FLYOUTS_VERTICAL_TOOLBOX, this.workspace.options, true); this.flyout = new VerticalFlyout!(flyoutWorkspaceOptions); } - this.workspace.addChangeListener(this.onDelete_.bind(this)); + this.workspace.addChangeListener(this.onDelete.bind(this)); } /** @@ -156,11 +156,11 @@ export class Trashcan extends DeleteArea implements IAutoHideable, clip-path="url(#blocklyTrashLidClipPath837493)"> */ - this.svgGroup_ = dom.createSvgElement(Svg.G, {'class': 'blocklyTrash'}); + this.svgGroup = dom.createSvgElement(Svg.G, {'class': 'blocklyTrash'}); let clip; const rnd = String(Math.random()).substring(2); clip = dom.createSvgElement( - Svg.CLIPPATH, {'id': 'blocklyTrashBodyClipPath' + rnd}, this.svgGroup_); + Svg.CLIPPATH, {'id': 'blocklyTrashBodyClipPath' + rnd}, this.svgGroup); dom.createSvgElement( Svg.RECT, {'width': WIDTH, 'height': BODY_HEIGHT, 'y': LID_HEIGHT}, clip); @@ -172,16 +172,16 @@ export class Trashcan extends DeleteArea implements IAutoHideable, 'y': -SPRITE_TOP, 'clip-path': 'url(#blocklyTrashBodyClipPath' + rnd + ')', }, - this.svgGroup_); + this.svgGroup); body.setAttributeNS( dom.XLINK_NS, 'xlink:href', this.workspace.options.pathToMedia + SPRITE.url); clip = dom.createSvgElement( - Svg.CLIPPATH, {'id': 'blocklyTrashLidClipPath' + rnd}, this.svgGroup_); + Svg.CLIPPATH, {'id': 'blocklyTrashLidClipPath' + rnd}, this.svgGroup); dom.createSvgElement( Svg.RECT, {'width': WIDTH, 'height': LID_HEIGHT}, clip); - this.svgLid_ = dom.createSvgElement( + this.svgLid = dom.createSvgElement( Svg.IMAGE, { 'width': SPRITE.width, 'x': -SPRITE_LEFT, @@ -189,8 +189,8 @@ export class Trashcan extends DeleteArea implements IAutoHideable, 'y': -SPRITE_TOP, 'clip-path': 'url(#blocklyTrashLidClipPath' + rnd + ')', }, - this.svgGroup_); - this.svgLid_.setAttributeNS( + this.svgGroup); + this.svgLid.setAttributeNS( dom.XLINK_NS, 'xlink:href', this.workspace.options.pathToMedia + SPRITE.url); @@ -199,13 +199,13 @@ export class Trashcan extends DeleteArea implements IAutoHideable, // Using bindEventWithChecks_ for blocking mousedown causes issue in mobile. // See #4303 browserEvents.bind( - this.svgGroup_, 'pointerdown', this, this.blockMouseDownWhenOpenable_); - browserEvents.bind(this.svgGroup_, 'pointerup', this, this.click); - // Bind to body instead of this.svgGroup_ so that we don't get lid jitters - browserEvents.bind(body, 'pointerover', this, this.mouseOver_); - browserEvents.bind(body, 'pointerout', this, this.mouseOut_); - this.animateLid_(); - return this.svgGroup_; + this.svgGroup, 'pointerdown', this, this.blockMouseDownWhenOpenable); + browserEvents.bind(this.svgGroup, 'pointerup', this, this.click); + // Bind to body instead of this.svgGroup so that we don't get lid jitters + browserEvents.bind(body, 'pointerover', this, this.mouseOver); + browserEvents.bind(body, 'pointerout', this, this.mouseOut); + this.animateLid(); + return this.svgGroup; } /** Initializes the trash can. */ @@ -225,25 +225,21 @@ export class Trashcan extends DeleteArea implements IAutoHideable, ComponentManager.Capability.POSITIONABLE, ], }); - this.initialized_ = true; + this.initialized = true; this.setLidOpen(false); } /** * Dispose of this trash can. * Unlink from all DOM elements to prevent memory leaks. - * - * @suppress {checkTypes} */ dispose() { this.workspace.getComponentManager().removeComponent('trashcan'); - if (this.svgGroup_) { - dom.removeNode(this.svgGroup_); - this.svgGroup_ = null; + if (this.svgGroup) { + dom.removeNode(this.svgGroup); } - this.svgLid_ = null; - if (this.lidTask_) { - clearTimeout(this.lidTask_); + if (this.lidTask) { + clearTimeout(this.lidTask); } } @@ -252,8 +248,8 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * * @returns True if the trashcan has contents. */ - private hasContents_(): boolean { - return !!this.contents_.length; + private hasContents(): boolean { + return !!this.contents.length; } /** @@ -270,7 +266,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, if (this.contentsIsOpen()) { return; } - const contents = this.contents_.map(function(string) { + const contents = this.contents.map(function(string) { return JSON.parse(string); }); // Trashcans with lots of blocks can take a second to render. @@ -280,7 +276,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, this.flyout?.show(contents); blocklyStyle.cursor = ''; }, 10); - this.fireUiEvent_(true); + this.fireUiEvent(true); } /** Closes the trashcan flyout. */ @@ -289,7 +285,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, return; } this.flyout?.hide(); - this.fireUiEvent_(false); + this.fireUiEvent(false); this.workspace.recordDragTargets(); } @@ -312,11 +308,11 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * it will be closed. */ emptyContents() { - if (!this.hasContents_()) { + if (!this.hasContents()) { return; } - this.contents_.length = 0; - this.setMinOpenness_(0); + this.contents.length = 0; + this.setMinOpenness(0); this.closeFlyout(); } @@ -330,7 +326,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, */ position(metrics: UiMetrics, savedPositions: Rect[]) { // Not yet initialized. - if (!this.initialized_) { + if (!this.initialized) { return; } @@ -349,10 +345,10 @@ export class Trashcan extends DeleteArea implements IAutoHideable, const positionRect = uiPosition.bumpPositionRect( startRect, MARGIN_VERTICAL, bumpDirection, savedPositions); - this.top_ = positionRect.top; - this.left_ = positionRect.left; - this.svgGroup_?.setAttribute( - 'transform', 'translate(' + this.left_ + ',' + this.top_ + ')'); + this.top = positionRect.top; + this.left = positionRect.left; + this.svgGroup?.setAttribute( + 'transform', 'translate(' + this.left + ',' + this.top + ')'); } /** @@ -363,9 +359,9 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * ignored by other UI elements. */ getBoundingRectangle(): Rect|null { - const bottom = this.top_ + BODY_HEIGHT + LID_HEIGHT; - const right = this.left_ + WIDTH; - return new Rect(this.top_, bottom, this.left_, right); + const bottom = this.top + BODY_HEIGHT + LID_HEIGHT; + const right = this.left + WIDTH; + return new Rect(this.top, bottom, this.left, right); } /** @@ -376,11 +372,11 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * ignored. */ override getClientRect(): Rect|null { - if (!this.svgGroup_) { + if (!this.svgGroup) { return null; } - const trashRect = this.svgGroup_.getBoundingClientRect(); + const trashRect = this.svgGroup.getBoundingClientRect(); const top = trashRect.top + SPRITE_TOP - MARGIN_HOTSPOT; const bottom = top + LID_HEIGHT + BODY_HEIGHT + 2 * MARGIN_HOTSPOT; const left = trashRect.left + SPRITE_LEFT - MARGIN_HOTSPOT; @@ -427,32 +423,32 @@ export class Trashcan extends DeleteArea implements IAutoHideable, if (this.isLidOpen === state) { return; } - if (this.lidTask_) { - clearTimeout(this.lidTask_); + if (this.lidTask) { + clearTimeout(this.lidTask); } this.isLidOpen = state; - this.animateLid_(); + this.animateLid(); } /** Rotate the lid open or closed by one step. Then wait and recurse. */ - private animateLid_() { + private animateLid() { const frames = ANIMATION_FRAMES; const delta = 1 / (frames + 1); - this.lidOpen_ += this.isLidOpen ? delta : -delta; - this.lidOpen_ = Math.min(Math.max(this.lidOpen_, this.minOpenness_), 1); + this.lidOpen += this.isLidOpen ? delta : -delta; + this.lidOpen = Math.min(Math.max(this.lidOpen, this.minOpenness), 1); - this.setLidAngle_(this.lidOpen_ * MAX_LID_ANGLE); + this.setLidAngle(this.lidOpen * MAX_LID_ANGLE); // Linear interpolation between min and max. - const opacity = OPACITY_MIN + this.lidOpen_ * (OPACITY_MAX - OPACITY_MIN); - if (this.svgGroup_) { - this.svgGroup_.style.opacity = `${opacity}`; + const opacity = OPACITY_MIN + this.lidOpen * (OPACITY_MAX - OPACITY_MIN); + if (this.svgGroup) { + this.svgGroup.style.opacity = `${opacity}`; } - if (this.lidOpen_ > this.minOpenness_ && this.lidOpen_ < 1) { - this.lidTask_ = - setTimeout(this.animateLid_.bind(this), ANIMATION_LENGTH / frames); + if (this.lidOpen > this.minOpenness && this.lidOpen < 1) { + this.lidTask = + setTimeout(this.animateLid.bind(this), ANIMATION_LENGTH / frames); } } @@ -461,11 +457,11 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * * @param lidAngle The angle at which to set the lid. */ - private setLidAngle_(lidAngle: number) { + private setLidAngle(lidAngle: number) { const openAtRight = this.workspace.toolboxPosition === toolbox.Position.RIGHT || this.workspace.horizontalLayout && this.workspace.RTL; - this.svgLid_?.setAttribute( + this.svgLid?.setAttribute( 'transform', 'rotate(' + (openAtRight ? -lidAngle : lidAngle) + ',' + (openAtRight ? 4 : WIDTH - 4) + ',' + (LID_HEIGHT - 2) + ')'); @@ -478,10 +474,10 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * @param newMin The new minimum openness of the lid. Should be between 0 * and 1. */ - private setMinOpenness_(newMin: number) { - this.minOpenness_ = newMin; + private setMinOpenness(newMin: number) { + this.minOpenness = newMin; if (!this.isLidOpen) { - this.setLidAngle_(newMin * MAX_LID_ANGLE); + this.setLidAngle(newMin * MAX_LID_ANGLE); } } @@ -495,7 +491,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, /** Inspect the contents of the trash. */ click() { - if (!this.hasContents_()) { + if (!this.hasContents()) { return; } this.openFlyout(); @@ -506,7 +502,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * * @param trashcanOpen Whether the flyout is opening. */ - private fireUiEvent_(trashcanOpen: boolean) { + private fireUiEvent(trashcanOpen: boolean) { const uiEvent = new (eventUtils.get(eventUtils.TRASHCAN_OPEN))( trashcanOpen, this.workspace.id); eventUtils.fire(uiEvent); @@ -517,8 +513,8 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * * @param e A mouse down event. */ - private blockMouseDownWhenOpenable_(e: PointerEvent) { - if (!this.contentsIsOpen() && this.hasContents_()) { + private blockMouseDownWhenOpenable(e: PointerEvent) { + if (!this.contentsIsOpen() && this.hasContents()) { // Don't start a workspace scroll. e.stopPropagation(); } @@ -527,8 +523,8 @@ export class Trashcan extends DeleteArea implements IAutoHideable, /** * Indicate that the trashcan can be clicked (by opening it) if it has blocks. */ - private mouseOver_() { - if (this.hasContents_()) { + private mouseOver() { + if (this.hasContents()) { this.setLidOpen(true); } } @@ -537,7 +533,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * Close the lid of the trashcan if it was open (Vis. it was indicating it had * blocks). */ - private mouseOut_() { + private mouseOut() { // No need to do a .hasBlocks check here because if it doesn't the trashcan // won't be open in the first place, and setOpen won't run. this.setLidOpen(false); @@ -549,7 +545,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * * @param event Workspace event. */ - private onDelete_(event: Abstract) { + private onDelete(event: Abstract) { if (this.workspace.options.maxTrashcanContents <= 0 || event.type !== eventUtils.BLOCK_DELETE) { return; @@ -560,17 +556,17 @@ export class Trashcan extends DeleteArea implements IAutoHideable, throw new Error('Encountered a delete event without proper oldJson'); } const cleanedJson = - JSON.stringify(this.cleanBlockJson_(deleteEvent.oldJson)); - if (this.contents_.indexOf(cleanedJson) !== -1) { + JSON.stringify(this.cleanBlockJson(deleteEvent.oldJson)); + if (this.contents.indexOf(cleanedJson) !== -1) { return; } - this.contents_.unshift(cleanedJson); - while (this.contents_.length > + this.contents.unshift(cleanedJson); + while (this.contents.length > this.workspace.options.maxTrashcanContents) { - this.contents_.pop(); + this.contents.pop(); } - this.setMinOpenness_(HAS_BLOCKS_LID_ANGLE); + this.setMinOpenness(HAS_BLOCKS_LID_ANGLE); } } @@ -582,7 +578,7 @@ export class Trashcan extends DeleteArea implements IAutoHideable, * @returns A BlockInfo object corresponding to the JSON, cleaned of all * unnecessary attributes. */ - private cleanBlockJson_(json: blocks.State): BlockInfo { + private cleanBlockJson(json: blocks.State): BlockInfo { // Create a deep copy. json = JSON.parse(JSON.stringify(json)) as blocks.State; diff --git a/tests/mocha/comment_deserialization_test.js b/tests/mocha/comment_deserialization_test.js index c8bf0594f..b8df7a365 100644 --- a/tests/mocha/comment_deserialization_test.js +++ b/tests/mocha/comment_deserialization_test.js @@ -71,7 +71,7 @@ suite('Comment Deserialization', function() { this.block.checkAndDelete(); chai.assert.equal(this.workspace.getAllBlocks().length, 0); // Open trashcan. - simulateClick(this.workspace.trashcan.svgGroup_); + simulateClick(this.workspace.trashcan.svgGroup); // Place from trashcan. simulateClick(this.workspace.trashcan.flyout.svgGroup_.querySelector('.blocklyDraggable')); chai.assert.equal(this.workspace.getAllBlocks().length, 1); diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js index 028d8fcdc..ad7102872 100644 --- a/tests/mocha/trashcan_test.js +++ b/tests/mocha/trashcan_test.js @@ -56,11 +56,11 @@ suite("Trashcan", function() { suite("Events", function() { test("Delete", function() { fireDeleteEvent(this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Non-Delete", function() { fireNonDeleteEvent(this.workspace); - chai.assert.equal(this.trashcan.contents_.length, 0); + chai.assert.equal(this.trashcan.contents.length, 0); }); test("Non-Delete w/ oldXml", function() { let xml = Blockly.utils.xml.textToDom( @@ -70,14 +70,14 @@ suite("Trashcan", function() { ); xml = xml.children[0]; fireNonDeleteEvent(this.workspace, xml); - chai.assert.equal(this.trashcan.contents_.length, 0); + chai.assert.equal(this.trashcan.contents.length, 0); }); test("Shadow Delete", function() { fireDeleteEvent(this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 0); + chai.assert.equal(this.trashcan.contents.length, 0); }); test("Click without contents - fires workspace click", function() { - simulateClick(this.trashcan.svgGroup_); + simulateClick(this.trashcan.svgGroup); assertEventNotFired( this.eventsFireStub, Blockly.Events.TrashcanOpen, {type: eventUtils.CLICK}); @@ -87,11 +87,11 @@ suite("Trashcan", function() { }); test("Click with contents - fires trashcanOpen", function() { fireDeleteEvent(this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); // Stub flyout interaction. const showFlyoutStub = sinon.stub(this.trashcan.flyout, "show"); - simulateClick(this.trashcan.svgGroup_); + simulateClick(this.trashcan.svgGroup); sinon.assert.calledOnce(showFlyoutStub); @@ -122,21 +122,21 @@ suite("Trashcan", function() { test("Simple", function() { fireDeleteEvent(this.workspace, ''); fireDeleteEvent(this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Different Coords", function() { fireDeleteEvent( this.workspace, ''); fireDeleteEvent( this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Different IDs", function() { fireDeleteEvent( this.workspace, ''); fireDeleteEvent( this.workspace, ''); - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("No Disabled - Disabled True", function() { fireDeleteEvent( @@ -145,7 +145,7 @@ suite("Trashcan", function() { this.workspace, ''); // Disabled tags get removed because disabled blocks aren't allowed to // be dragged from flyouts. See #2239 and #3243. - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Different Field Values", function() { fireDeleteEvent(this.workspace, @@ -158,7 +158,7 @@ suite("Trashcan", function() { ' dummy_value2' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("No Values - Values", function() { fireDeleteEvent(this.workspace, ''); @@ -169,7 +169,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("Different Value Blocks", function() { fireDeleteEvent(this.workspace, @@ -186,7 +186,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("No Statements - Statements", function() { fireDeleteEvent(this.workspace, ''); @@ -197,7 +197,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("Different Statement Blocks", function() { fireDeleteEvent(this.workspace, @@ -214,7 +214,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("No Next - Next", function() { fireDeleteEvent(this.workspace, ''); @@ -225,7 +225,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("Different Next Blocks", function() { fireDeleteEvent(this.workspace, @@ -242,7 +242,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("No Comment - Comment", function() { fireDeleteEvent(this.workspace, ''); @@ -251,7 +251,7 @@ suite("Trashcan", function() { ' comment_text' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("Different Comment Text", function() { fireDeleteEvent(this.workspace, @@ -264,7 +264,7 @@ suite("Trashcan", function() { ' comment_text2' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); test("Different Comment Size", function() { fireDeleteEvent(this.workspace, @@ -278,7 +278,7 @@ suite("Trashcan", function() { '' ); // h & w tags are removed b/c the blocks appear the same. - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Different Comment Pinned", function() { fireDeleteEvent(this.workspace, @@ -292,7 +292,7 @@ suite("Trashcan", function() { '' ); // pinned tags are removed b/c the blocks appear the same. - chai.assert.equal(this.trashcan.contents_.length, 1); + chai.assert.equal(this.trashcan.contents.length, 1); }); test("Different Mutator", function() { fireDeleteEvent(this.workspace, @@ -305,7 +305,7 @@ suite("Trashcan", function() { ' ' + '' ); - chai.assert.equal(this.trashcan.contents_.length, 2); + chai.assert.equal(this.trashcan.contents.length, 2); }); }); suite("Max Contents", function() { @@ -314,7 +314,7 @@ suite("Trashcan", function() { fireDeleteEvent(this.workspace, '' ); - chai.assert.equal(this.trashcan.contents_.length, 0); + chai.assert.equal(this.trashcan.contents.length, 0); this.workspace.options.maxTrashcanContents = Infinity; }); });