diff --git a/core/trashcan.ts b/core/trashcan.ts index 08211bac9dd..e658977a0dc 100644 --- a/core/trashcan.ts +++ b/core/trashcan.ts @@ -14,6 +14,7 @@ // Unused import preserved for side-effects. Remove if unneeded. import * as browserEvents from './browser_events.js'; import {ComponentManager} from './component_manager.js'; +import * as Css from './css.js'; import {DeleteArea} from './delete_area.js'; import type {Abstract} from './events/events_abstract.js'; import './events/events_trashcan_open.js'; @@ -28,7 +29,6 @@ import type {UiMetrics} from './metrics_manager.js'; import * as uiPosition from './positionable_helpers.js'; import * as registry from './registry.js'; import type * as blocks from './serialization/blocks.js'; -import {SPRITE} from './sprites.js'; import * as dom from './utils/dom.js'; import {Rect} from './utils/rect.js'; import {Size} from './utils/size.js'; @@ -150,61 +150,21 @@ export class Trashcan */ 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.svgLid = dom.createSvgElement( + Svg.G, + {'class': 'blocklyTrashLid'}, this.svgGroup, ); - dom.createSvgElement( - Svg.RECT, - {'width': WIDTH, 'height': BODY_HEIGHT, 'y': LID_HEIGHT}, - clip, - ); + this.svgLid.innerHTML = ``; const body = dom.createSvgElement( - Svg.IMAGE, - { - 'width': SPRITE.width, - 'x': -SPRITE_LEFT, - 'height': SPRITE.height, - 'y': -SPRITE_TOP, - 'clip-path': 'url(#blocklyTrashBodyClipPath' + rnd + ')', - }, + Svg.G, + {'class': 'blocklyTrashBody'}, 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, - ); - dom.createSvgElement( - Svg.RECT, - {'width': WIDTH, 'height': LID_HEIGHT}, - clip, - ); - this.svgLid = dom.createSvgElement( - Svg.IMAGE, - { - 'width': SPRITE.width, - 'x': -SPRITE_LEFT, - 'height': SPRITE.height, - 'y': -SPRITE_TOP, - 'clip-path': 'url(#blocklyTrashLidClipPath' + rnd + ')', - }, - this.svgGroup, - ); - this.svgLid.setAttributeNS( - dom.XLINK_NS, - 'xlink:href', - this.workspace.options.pathToMedia + SPRITE.url, - ); + body.innerHTML = ` + + + `; // bindEventWithChecks_ quashes events too aggressively. See: // https://groups.google.com/forum/#!topic/blockly/QF4yB9Wx00s @@ -475,12 +435,6 @@ export class Trashcan 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}`; - } - if (this.lidOpen > this.minOpenness && this.lidOpen < 1) { this.lidTask = setTimeout( this.animateLid.bind(this), @@ -717,14 +671,19 @@ const ANIMATION_LENGTH = 80; /** The number of frames in the animation. */ const ANIMATION_FRAMES = 4; -/** The minimum (resting) opacity of the trashcan and lid. */ -const OPACITY_MIN = 0.4; - -/** The maximum (hovered) opacity of the trashcan and lid. */ -const OPACITY_MAX = 0.8; - /** * The maximum angle the trashcan lid can opens to. At the end of the open * animation the lid will be open to this angle. */ const MAX_LID_ANGLE = 45; + +Css.register(` +.blocklyTrash { + fill: #888; + opacity: 0.4; + transition: opacity .08s linear; +} +.blocklyTrash:hover { + opacity: 0.8; +} +`); diff --git a/core/zoom_controls.ts b/core/zoom_controls.ts index 4f14b73bed6..f7646992144 100644 --- a/core/zoom_controls.ts +++ b/core/zoom_controls.ts @@ -22,7 +22,6 @@ import * as eventUtils from './events/utils.js'; import type {IPositionable} from './interfaces/i_positionable.js'; import type {UiMetrics} from './metrics_manager.js'; import * as uiPosition from './positionable_helpers.js'; -import {SPRITE} from './sprites.js'; import * as Touch from './touch.js'; import * as dom from './utils/dom.js'; import {Rect} from './utils/rect.js'; @@ -102,13 +101,12 @@ export class ZoomControls implements IPositionable { // Each filter/pattern needs a unique ID for the case of multiple Blockly // instances on a page. Browser behaviour becomes undefined otherwise. // https://neil.fraser.name/news/2015/11/01/ - const rnd = String(Math.random()).substring(2); - this.createZoomOutSvg(rnd); - this.createZoomInSvg(rnd); + this.createZoomOutSvg(); + this.createZoomInSvg(); if (this.workspace.isMovable()) { // If we zoom to the center and the workspace isn't movable we could // loose blocks at the edges of the workspace. - this.createZoomResetSvg(rnd); + this.createZoomResetSvg(); } return this.svgGroup; } @@ -238,12 +236,8 @@ export class ZoomControls implements IPositionable { /** * Create the zoom in icon and its event handler. - * - * @param rnd The random string to use as a suffix in the clip path's ID. - * These IDs must be unique in case there are multiple Blockly instances - * on the same page. */ - private createZoomOutSvg(rnd: string) { + private createZoomOutSvg() { /* This markup will be generated and added to the .svgGroup: @@ -259,35 +253,10 @@ export class ZoomControls implements IPositionable { {'class': 'blocklyZoom blocklyZoomOut'}, this.svgGroup, ); - const clip = dom.createSvgElement( - Svg.CLIPPATH, - {'id': 'blocklyZoomoutClipPath' + rnd}, - this.zoomOutGroup, - ); - dom.createSvgElement( - Svg.RECT, - { - 'width': 32, - 'height': 32, - }, - clip, - ); - const zoomoutSvg = dom.createSvgElement( - Svg.IMAGE, - { - 'width': SPRITE.width, - 'height': SPRITE.height, - 'x': -64, - 'y': -92, - 'clip-path': 'url(#blocklyZoomoutClipPath' + rnd + ')', - }, - this.zoomOutGroup, - ); - zoomoutSvg.setAttributeNS( - dom.XLINK_NS, - 'xlink:href', - this.workspace.options.pathToMedia + SPRITE.url, - ); + this.zoomOutGroup.innerHTML = ` + + +`; // Attach listener. this.boundEvents.push( @@ -302,12 +271,8 @@ export class ZoomControls implements IPositionable { /** * Create the zoom out icon and its event handler. - * - * @param rnd The random string to use as a suffix in the clip path's ID. - * These IDs must be unique in case there are multiple Blockly instances - * on the same page. */ - private createZoomInSvg(rnd: string) { + private createZoomInSvg() { /* This markup will be generated and added to the .svgGroup: @@ -323,35 +288,11 @@ export class ZoomControls implements IPositionable { {'class': 'blocklyZoom blocklyZoomIn'}, this.svgGroup, ); - const clip = dom.createSvgElement( - Svg.CLIPPATH, - {'id': 'blocklyZoominClipPath' + rnd}, - this.zoomInGroup, - ); - dom.createSvgElement( - Svg.RECT, - { - 'width': 32, - 'height': 32, - }, - clip, - ); - const zoominSvg = dom.createSvgElement( - Svg.IMAGE, - { - 'width': SPRITE.width, - 'height': SPRITE.height, - 'x': -32, - 'y': -92, - 'clip-path': 'url(#blocklyZoominClipPath' + rnd + ')', - }, - this.zoomInGroup, - ); - zoominSvg.setAttributeNS( - dom.XLINK_NS, - 'xlink:href', - this.workspace.options.pathToMedia + SPRITE.url, - ); + this.zoomInGroup.innerHTML = ` + + + +`; // Attach listener. this.boundEvents.push( @@ -383,12 +324,8 @@ export class ZoomControls implements IPositionable { /** * Create the zoom reset icon and its event handler. - * - * @param rnd The random string to use as a suffix in the clip path's ID. - * These IDs must be unique in case there are multiple Blockly instances - * on the same page. */ - private createZoomResetSvg(rnd: string) { + private createZoomResetSvg() { /* This markup will be generated and added to the .svgGroup: @@ -404,27 +341,14 @@ export class ZoomControls implements IPositionable { {'class': 'blocklyZoom blocklyZoomReset'}, this.svgGroup, ); - const clip = dom.createSvgElement( - Svg.CLIPPATH, - {'id': 'blocklyZoomresetClipPath' + rnd}, - this.zoomResetGroup, - ); - dom.createSvgElement(Svg.RECT, {'width': 32, 'height': 32}, clip); - const zoomresetSvg = dom.createSvgElement( - Svg.IMAGE, - { - 'width': SPRITE.width, - 'height': SPRITE.height, - 'y': -92, - 'clip-path': 'url(#blocklyZoomresetClipPath' + rnd + ')', - }, - this.zoomResetGroup, - ); - zoomresetSvg.setAttributeNS( - dom.XLINK_NS, - 'xlink:href', - this.workspace.options.pathToMedia + SPRITE.url, - ); + this.zoomResetGroup.innerHTML = ` + + + + + + +`; // Attach event listeners. this.boundEvents.push( @@ -479,15 +403,29 @@ export class ZoomControls implements IPositionable { /** CSS for zoom controls. See css.js for use. */ Css.register(` -.blocklyZoom>image, .blocklyZoom>svg>image { +.blocklyZoom { opacity: .4; + pointer-events: bounding-box; } -.blocklyZoom>image:hover, .blocklyZoom>svg>image:hover { +.blocklyZoom:hover { opacity: .6; } -.blocklyZoom>image:active, .blocklyZoom>svg>image:active { +.blocklyZoom:active { opacity: .8; } + +.blocklyZoom>* { + fill:#fff; + fill-opacity:0.005; + stroke:#888; + stroke-width:2; + stroke-linecap:round; +} +.blocklyZoom>circle.center { + fill: #888; + fill-opacity: 1; + stroke-width: 0; +} `);