fix!: remove MarkerSvg and uses (#8991)

* fix: delete MarkerSvg (marker drawer)

* fix: delete marker and cursor SVG elements

* chore: format

* chore: lint
This commit is contained in:
Rachel Fenichel
2025-05-07 09:28:51 -07:00
committed by GitHub
parent acdad98653
commit bb76d6e12c
16 changed files with 1 additions and 1455 deletions

View File

@@ -50,7 +50,6 @@ import type {IFocusableTree} from './interfaces/i_focusable_tree.js';
import {IIcon} from './interfaces/i_icon.js';
import type {INavigable} from './interfaces/i_navigable.js';
import * as internalConstants from './internal_constants.js';
import {MarkerManager} from './marker_manager.js';
import {Msg} from './msg.js';
import * as renderManagement from './render_management.js';
import {RenderedConnection} from './rendered_connection.js';
@@ -1679,7 +1678,6 @@ export class BlockSvg
this.tightenChildrenEfficiently();
dom.stopTextWidthCache();
this.updateMarkers_();
}
/**
@@ -1699,44 +1697,6 @@ export class BlockSvg
if (this.nextConnection) this.nextConnection.tightenEfficiently();
}
/** Redraw any attached marker or cursor svgs if needed. */
protected updateMarkers_() {
if (this.workspace.keyboardAccessibilityMode && this.pathObject.cursorSvg) {
this.workspace.getCursor()!.draw();
}
if (this.workspace.keyboardAccessibilityMode && this.pathObject.markerSvg) {
// TODO(#4592): Update all markers on the block.
this.workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw();
}
for (const input of this.inputList) {
for (const field of input.fieldRow) {
field.updateMarkers_();
}
}
}
/**
* Add the cursor SVG to this block's SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the block SVG
* group.
* @internal
*/
setCursorSvg(cursorSvg: SVGElement) {
this.pathObject.setCursorSvg(cursorSvg);
}
/**
* Add the marker SVG to this block's SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the block SVG
* group.
* @internal
*/
setMarkerSvg(markerSvg: SVGElement) {
this.pathObject.setMarkerSvg(markerSvg);
}
/**
* Returns a bounding box describing the dimensions of this block
* and any blocks stacked below it.

View File

@@ -31,7 +31,6 @@ import type {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js';
import type {INavigable} from './interfaces/i_navigable.js';
import type {IRegistrable} from './interfaces/i_registrable.js';
import {ISerializable} from './interfaces/i_serializable.js';
import {MarkerManager} from './marker_manager.js';
import type {ConstantProvider} from './renderers/common/constants.js';
import type {KeyboardShortcut} from './shortcut_registry.js';
import * as Tooltip from './tooltip.js';
@@ -113,18 +112,6 @@ export abstract class Field<T = any>
private tooltip: Tooltip.TipInfo | null = null;
protected size_: Size;
/**
* Holds the cursors svg element when the cursor is attached to the field.
* This is null if there is no cursor on the field.
*/
private cursorSvg: SVGElement | null = null;
/**
* Holds the markers svg element when the marker is attached to the field.
* This is null if there is no marker on the field.
*/
private markerSvg: SVGElement | null = null;
/** The rendered field's SVG group element. */
protected fieldGroup_: SVGGElement | null = null;
@@ -1358,64 +1345,6 @@ export abstract class Field<T = any>
return false;
}
/**
* Add the cursor SVG to this fields SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the field group.
* @internal
*/
setCursorSvg(cursorSvg: SVGElement) {
if (!cursorSvg) {
this.cursorSvg = null;
return;
}
if (!this.fieldGroup_) {
throw new Error(`The field group is ${this.fieldGroup_}.`);
}
this.fieldGroup_.appendChild(cursorSvg);
this.cursorSvg = cursorSvg;
}
/**
* Add the marker SVG to this fields SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the field group.
* @internal
*/
setMarkerSvg(markerSvg: SVGElement) {
if (!markerSvg) {
this.markerSvg = null;
return;
}
if (!this.fieldGroup_) {
throw new Error(`The field group is ${this.fieldGroup_}.`);
}
this.fieldGroup_.appendChild(markerSvg);
this.markerSvg = markerSvg;
}
/**
* Redraw any attached marker or cursor svgs if needed.
*
* @internal
*/
updateMarkers_() {
const block = this.getSourceBlock();
if (!block) {
throw new UnattachedFieldError();
}
const workspace = block.workspace as WorkspaceSvg;
if (workspace.keyboardAccessibilityMode && this.cursorSvg) {
workspace.getCursor()!.draw();
}
if (workspace.keyboardAccessibilityMode && this.markerSvg) {
// TODO(#4592): Update all markers on the field.
workspace.getMarker(MarkerManager.LOCAL_MARKER)!.draw();
}
}
/** See IFocusableNode.getFocusableElement. */
getFocusableElement(): HTMLElement | SVGElement {
if (!this.fieldGroup_) {

View File

@@ -348,15 +348,6 @@ export class FlyoutButton
}
}
/**
* Required by IASTNodeLocationSvg, but not used. A marker cannot be set on a
* button. If the 'mark' shortcut is used on a button, its associated callback
* function is triggered.
*/
setMarkerSvg() {
throw new Error('Attempted to set a marker on a button.');
}
/**
* Do something when the button is clicked.
*

View File

@@ -11,18 +11,4 @@ import type {IASTNodeLocation} from './i_ast_node_location.js';
/**
* An AST node location SVG interface.
*/
export interface IASTNodeLocationSvg extends IASTNodeLocation {
/**
* Add the marker SVG to this node's SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the SVG group.
*/
setMarkerSvg(markerSvg: SVGElement | null): void;
/**
* Add the cursor SVG to this node's SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the SVG group.
*/
setCursorSvg(cursorSvg: SVGElement | null): void;
}
export interface IASTNodeLocationSvg extends IASTNodeLocation {}

View File

@@ -30,12 +30,8 @@ import {isFocusableNode} from '../interfaces/i_focusable_node.js';
import type {INavigable} from '../interfaces/i_navigable.js';
import * as registry from '../registry.js';
import {RenderedConnection} from '../rendered_connection.js';
import type {MarkerSvg} from '../renderers/common/marker_svg.js';
import type {PathObject} from '../renderers/zelos/path_object.js';
import {Renderer} from '../renderers/zelos/renderer.js';
import * as dom from '../utils/dom.js';
import {WorkspaceSvg} from '../workspace_svg.js';
import {ASTNode} from './ast_node.js';
import {BlockNavigationPolicy} from './block_navigation_policy.js';
import {ConnectionNavigationPolicy} from './connection_navigation_policy.js';
import {FieldNavigationPolicy} from './field_navigation_policy.js';
@@ -574,40 +570,6 @@ export class LineCursor extends Marker {
return super.getCurNode();
}
/**
* Sets the object in charge of drawing the marker.
*
* We want to customize drawing, so rather than directly setting the given
* object, we instead set a wrapper proxy object that passes through all
* method calls and property accesses except for draw(), which it delegates
* to the drawMarker() method in this class.
*
* @param drawer The object ~in charge of drawing the marker.
*/
override setDrawer(drawer: MarkerSvg) {
const altDraw = function (
this: LineCursor,
oldNode: ASTNode | null,
curNode: ASTNode | null,
) {
// Pass the unproxied, raw drawer object so that drawMarker can call its
// `draw()` method without triggering infinite recursion.
this.drawMarker(oldNode, curNode, drawer);
}.bind(this);
super.setDrawer(
new Proxy(drawer, {
get(target: typeof drawer, prop: keyof typeof drawer) {
if (prop === 'draw') {
return altDraw;
}
return target[prop];
},
}),
);
}
/**
* Set the location of the cursor and draw it.
*
@@ -631,124 +593,6 @@ export class LineCursor extends Marker {
}
}
/**
* Draw this cursor's marker.
*
* This is a wrapper around this.drawer.draw (usually implemented by
* MarkerSvg.prototype.draw) that will, if newNode is a BLOCK node,
* instead call `setSelected` to select it (if it's a regular block)
* or `addSelect` (if it's a shadow block, since shadow blocks can't
* be selected) instead of using the normal drawer logic.
*
* TODO(#142): The selection and fake-selection code was originally
* a hack added for testing on October 28 2024, because the default
* drawer (MarkerSvg) behaviour in Zelos was to draw a box around
* the block and all attached child blocks, which was confusing when
* navigating stacks.
*
* Since then we have decided that we probably _do_ in most cases
* want navigating to a block to select the block, but more
* particularly that we want navigation to move _focus_. Replace
* this selection hack with non-hacky changing of focus once that's
* possible.
*
* @param oldNode The previous node.
* @param curNode The current node.
* @param realDrawer The object ~in charge of drawing the marker.
*/
private drawMarker(
oldNode: ASTNode | null,
curNode: ASTNode | null,
realDrawer: MarkerSvg,
) {
// If old node was a block, unselect it or remove fake selection.
if (oldNode?.getType() === ASTNode.types.BLOCK) {
const block = oldNode.getLocation() as BlockSvg;
if (!block.isShadow()) {
// Selection should already be in sync.
} else {
block.removeSelect();
}
}
if (this.isZelos && oldNode && this.isValueInputConnection(oldNode)) {
this.hideAtInput(oldNode);
}
const curNodeType = curNode?.getType();
const isZelosInputConnection =
this.isZelos && curNode && this.isValueInputConnection(curNode);
// If drawing can't be handled locally, just use the drawer.
if (curNodeType !== ASTNode.types.BLOCK && !isZelosInputConnection) {
realDrawer.draw(oldNode, curNode);
return;
}
// Hide any visible marker SVG and instead do some manual rendering.
realDrawer.hide();
if (isZelosInputConnection) {
this.showAtInput(curNode);
} else if (curNode && curNodeType === ASTNode.types.BLOCK) {
const block = curNode.getLocation() as BlockSvg;
if (!block.isShadow()) {
// Selection should already be in sync.
} else {
block.addSelect();
block.getParent()?.removeSelect();
}
}
// Call MarkerSvg.prototype.fireMarkerEvent like
// MarkerSvg.prototype.draw would (even though it's private).
(realDrawer as any)?.fireMarkerEvent?.(oldNode, curNode);
}
/**
* Check whether the node represents a value input connection.
*
* @param node The node to check
* @returns True if the node represents a value input connection.
*/
private isValueInputConnection(node: ASTNode) {
if (node?.getType() !== ASTNode.types.INPUT) return false;
const connection = node.getLocation() as RenderedConnection;
return connection.type === ConnectionType.INPUT_VALUE;
}
/**
* Hide the cursor rendering at the given input node.
*
* @param node The input node to hide.
*/
private hideAtInput(node: ASTNode) {
const inputConnection = node.getLocation() as RenderedConnection;
const sourceBlock = inputConnection.getSourceBlock() as BlockSvg;
const input = inputConnection.getParentInput();
if (input) {
const pathObject = sourceBlock.pathObject as PathObject;
const outlinePath = pathObject.getOutlinePath(input.name);
dom.removeClass(outlinePath, 'inputActiveFocus');
}
}
/**
* Show the cursor rendering at the given input node.
*
* @param node The input node to show.
*/
private showAtInput(node: ASTNode) {
const inputConnection = node.getLocation() as RenderedConnection;
const sourceBlock = inputConnection.getSourceBlock() as BlockSvg;
const input = inputConnection.getParentInput();
if (input) {
const pathObject = sourceBlock.pathObject as PathObject;
const outlinePath = pathObject.getOutlinePath(input.name);
dom.addClass(outlinePath, 'inputActiveFocus');
}
}
/**
* Updates the current node to match the selection.
*

View File

@@ -17,7 +17,6 @@ import {Field} from '../field.js';
import {FlyoutButton} from '../flyout_button.js';
import type {INavigable} from '../interfaces/i_navigable.js';
import {RenderedConnection} from '../rendered_connection.js';
import type {MarkerSvg} from '../renderers/common/marker_svg.js';
import {Coordinate} from '../utils/coordinate.js';
import {WorkspaceSvg} from '../workspace_svg.js';
import {ASTNode} from './ast_node.js';
@@ -33,33 +32,9 @@ export class Marker {
/** The current location of the marker. */
protected curNode: INavigable<any> | null = null;
/**
* The object in charge of drawing the visual representation of the current
* node.
*/
private drawer: MarkerSvg | null = null;
/** The type of the marker. */
type = 'marker';
/**
* Sets the object in charge of drawing the marker.
*
* @param drawer The object in charge of drawing the marker.
*/
setDrawer(drawer: MarkerSvg) {
this.drawer = drawer;
}
/**
* Get the current drawer for the marker.
*
* @returns The object in charge of drawing the marker.
*/
getDrawer(): MarkerSvg | null {
return this.drawer;
}
/**
* Gets the current location of the marker.
*
@@ -75,30 +50,11 @@ export class Marker {
* @param newNode The new location of the marker, or null to remove it.
*/
setCurNode(newNode: INavigable<any> | null) {
const oldNode = this.curNode;
this.curNode = newNode;
this.drawer?.draw(this.toASTNode(oldNode), this.toASTNode(this.curNode));
}
/**
* Redraw the current marker.
*
* @internal
*/
draw() {
const node = this.toASTNode(this.curNode);
this.drawer?.draw(node, node);
}
/** Hide the marker SVG. */
hide() {
this.drawer?.hide();
}
/** Dispose of this marker. */
dispose() {
this.drawer?.dispose();
this.drawer = null;
this.curNode = null;
}

View File

@@ -25,15 +25,9 @@ export class MarkerManager {
/** The cursor. */
private cursor: LineCursor | null = null;
/** The cursor's SVG element. */
private cursorSvg: SVGElement | null = null;
/** The map of markers for the workspace. */
private markers = new Map<string, Marker>();
/** The marker's SVG element. */
private markerSvg: SVGElement | null = null;
/**
* @param workspace The workspace for the marker manager.
* @internal
@@ -50,11 +44,6 @@ export class MarkerManager {
if (this.markers.has(id)) {
this.unregisterMarker(id);
}
const drawer = this.workspace
.getRenderer()
.makeMarkerDrawer(this.workspace, marker);
marker.setDrawer(drawer);
this.setMarkerSvg(drawer.createDom());
this.markers.set(id, marker);
}
@@ -105,67 +94,7 @@ export class MarkerManager {
* @param cursor The cursor used to move around this workspace.
*/
setCursor(cursor: LineCursor) {
this.cursor?.getDrawer()?.dispose();
this.cursor = cursor;
if (this.cursor) {
const drawer = this.workspace
.getRenderer()
.makeMarkerDrawer(this.workspace, this.cursor);
this.cursor.setDrawer(drawer);
this.setCursorSvg(drawer.createDom());
}
}
/**
* Add the cursor SVG to this workspace SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the workspace
* SVG group.
* @internal
*/
setCursorSvg(cursorSvg: SVGElement | null) {
if (!cursorSvg) {
this.cursorSvg = null;
return;
}
this.workspace.getBlockCanvas()!.appendChild(cursorSvg);
this.cursorSvg = cursorSvg;
}
/**
* Add the marker SVG to this workspaces SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the workspace
* SVG group.
* @internal
*/
setMarkerSvg(markerSvg: SVGElement | null) {
if (!markerSvg) {
this.markerSvg = null;
return;
}
if (this.workspace.getBlockCanvas()) {
if (this.cursorSvg) {
this.workspace
.getBlockCanvas()!
.insertBefore(markerSvg, this.cursorSvg);
} else {
this.workspace.getBlockCanvas()!.appendChild(markerSvg);
}
}
}
/**
* Redraw the attached cursor SVG if needed.
*
* @internal
*/
updateMarkers() {
if (this.workspace.keyboardAccessibilityMode && this.cursorSvg) {
this.workspace.getCursor()!.draw();
}
}
/**

View File

@@ -33,7 +33,6 @@ import {Types} from '../measurables/types.js';
import {Drawer} from './drawer.js';
import type {IPathObject} from './i_path_object.js';
import {RenderInfo} from './info.js';
import {MarkerSvg} from './marker_svg.js';
import {PathObject} from './path_object.js';
import {Renderer} from './renderer.js';
@@ -94,7 +93,6 @@ export {
InRowSpacer,
IPathObject,
JaggedEdge,
MarkerSvg,
Measurable,
NextConnection,
OutputConnection,

View File

@@ -30,18 +30,6 @@ export interface IPathObject {
/** The primary path of the block. */
style: BlockStyle;
/**
* Holds the cursors SVG element when the cursor is attached to the block.
* This is null if there is no cursor on the block.
*/
cursorSvg: SVGElement | null;
/**
* Holds the markers SVG element when the marker is attached to the block.
* This is null if there is no marker on the block.
*/
markerSvg: SVGElement | null;
/**
* Set the path generated by the renderer onto the respective SVG element.
*
@@ -54,22 +42,6 @@ export interface IPathObject {
*/
flipRTL(): void;
/**
* Add the cursor SVG to this block's SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the block SVG
* group.
*/
setCursorSvg(cursorSvg: SVGElement): void;
/**
* Add the marker SVG to this block's SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the block SVG
* group.
*/
setMarkerSvg(markerSvg: SVGElement): void;
/**
* Set whether the block shows a highlight or not. Block highlighting is
* often used to visually mark blocks currently being executed.

View File

@@ -1,767 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
// Former goog.module ID: Blockly.blockRendering.MarkerSvg
// Unused import preserved for side-effects. Remove if unneeded.
import '../../events/events_marker_move.js';
import type {BlockSvg} from '../../block_svg.js';
import type {Connection} from '../../connection.js';
import {ConnectionType} from '../../connection_type.js';
import {EventType} from '../../events/type.js';
import * as eventUtils from '../../events/utils.js';
import type {Field} from '../../field.js';
import {FlyoutButton} from '../../flyout_button.js';
import type {IASTNodeLocationSvg} from '../../interfaces/i_ast_node_location_svg.js';
import {ASTNode} from '../../keyboard_nav/ast_node.js';
import type {Marker} from '../../keyboard_nav/marker.js';
import type {RenderedConnection} from '../../rendered_connection.js';
import * as dom from '../../utils/dom.js';
import {Svg} from '../../utils/svg.js';
import * as svgPaths from '../../utils/svg_paths.js';
import type {WorkspaceSvg} from '../../workspace_svg.js';
import type {ConstantProvider, Notch, PuzzleTab} from './constants.js';
/** The name of the CSS class for a cursor. */
const CURSOR_CLASS = 'blocklyCursor';
/** The name of the CSS class for a marker. */
const MARKER_CLASS = 'blocklyMarker';
/**
* What we multiply the height by to get the height of the marker.
* Only used for the block and block connections.
*/
const HEIGHT_MULTIPLIER = 3 / 4;
/**
* Class for a marker, containing methods for graphically rendering a marker as
* SVG.
*/
export class MarkerSvg {
/**
* The workspace, field, or block that the marker SVG element should be
* attached to.
*/
protected parent: IASTNodeLocationSvg | null = null;
/** The current SVG element for the marker. */
currentMarkerSvg: SVGElement | null = null;
colour_: string;
/** The root SVG group containing the marker. */
protected markerSvg_: SVGGElement | null = null;
protected svgGroup_: SVGGElement | null = null;
protected markerBlock_: SVGPathElement | null = null;
protected markerInput_: SVGPathElement | null = null;
protected markerSvgLine_: SVGRectElement | null = null;
protected markerSvgRect_: SVGRectElement | null = null;
/** The constants necessary to draw the marker. */
protected constants_: ConstantProvider;
/**
* @param workspace The workspace the marker belongs to.
* @param constants The constants for the renderer.
* @param marker The marker to draw.
*/
constructor(
protected readonly workspace: WorkspaceSvg,
constants: ConstantProvider,
protected readonly marker: Marker,
) {
this.constants_ = constants;
const defaultColour = this.isCursor()
? this.constants_.CURSOR_COLOUR
: this.constants_.MARKER_COLOUR;
/** The colour of the marker. */
this.colour_ = marker.colour || defaultColour;
}
/**
* Return the root node of the SVG or null if none exists.
*
* @returns The root SVG node.
*/
getSvgRoot(): SVGElement | null {
return this.svgGroup_;
}
/**
* Get the marker.
*
* @returns The marker to draw for.
*/
getMarker(): Marker {
return this.marker;
}
/**
* True if the marker should be drawn as a cursor, false otherwise.
* A cursor is drawn as a flashing line. A marker is drawn as a solid line.
*
* @returns True if the marker is a cursor, false otherwise.
*/
isCursor(): boolean {
return this.marker.type === 'cursor';
}
/**
* Create the DOM element for the marker.
*
* @returns The marker controls SVG group.
*/
createDom(): SVGElement {
const className = this.isCursor() ? CURSOR_CLASS : MARKER_CLASS;
this.svgGroup_ = dom.createSvgElement(Svg.G, {'class': className});
this.createDomInternal_();
return this.svgGroup_;
}
/**
* Attaches the SVG root of the marker to the SVG group of the parent.
*
* @param newParent The workspace, field, or block that the marker SVG element
* should be attached to.
*/
protected setParent_(newParent: IASTNodeLocationSvg) {
if (!this.isCursor()) {
if (this.parent) {
this.parent.setMarkerSvg(null);
}
newParent.setMarkerSvg(this.getSvgRoot());
} else {
if (this.parent) {
this.parent.setCursorSvg(null);
}
newParent.setCursorSvg(this.getSvgRoot());
}
this.parent = newParent;
}
/**
* Update the marker.
*
* @param oldNode The previous node the marker was on or null.
* @param curNode The node that we want to draw the marker for.
*/
draw(oldNode: ASTNode | null, curNode: ASTNode | null) {
if (!curNode) {
this.hide();
return;
}
this.constants_ = this.workspace.getRenderer().getConstants();
const defaultColour = this.isCursor()
? this.constants_.CURSOR_COLOUR
: this.constants_.MARKER_COLOUR;
this.colour_ = this.marker.colour || defaultColour;
this.applyColour_(curNode);
this.showAtLocation_(curNode);
this.fireMarkerEvent(oldNode, curNode);
// Ensures the marker will be visible immediately after the move.
const animate = this.currentMarkerSvg!.childNodes[0];
if (
animate !== undefined &&
(animate as SVGAnimationElement).beginElement
) {
(animate as SVGAnimationElement).beginElement();
}
}
/**
* Update the marker's visible state based on the type of curNode..
*
* @param curNode The node that we want to draw the marker for.
*/
protected showAtLocation_(curNode: ASTNode) {
const curNodeAsConnection = curNode.getLocation() as Connection;
const connectionType = curNodeAsConnection.type;
if (curNode.getType() === ASTNode.types.BLOCK) {
this.showWithBlock_(curNode);
} else if (curNode.getType() === ASTNode.types.OUTPUT) {
this.showWithOutput_(curNode);
} else if (connectionType === ConnectionType.INPUT_VALUE) {
this.showWithInput_(curNode);
} else if (connectionType === ConnectionType.NEXT_STATEMENT) {
this.showWithNext_(curNode);
} else if (curNode.getType() === ASTNode.types.PREVIOUS) {
this.showWithPrevious_(curNode);
} else if (curNode.getType() === ASTNode.types.FIELD) {
this.showWithField_(curNode);
} else if (curNode.getType() === ASTNode.types.WORKSPACE) {
this.showWithCoordinates_(curNode);
} else if (curNode.getType() === ASTNode.types.STACK) {
this.showWithStack_(curNode);
} else if (curNode.getType() === ASTNode.types.BUTTON) {
this.showWithButton_(curNode);
}
}
/**************************
* Display
**************************/
/**
* Show the marker as a combination of the previous connection and block,
* the output connection and block, or just the block.
*
* @param curNode The node to draw the marker for.
*/
protected showWithBlockPrevOutput(curNode: ASTNode) {
const block = curNode.getSourceBlock() as BlockSvg;
const width = block.width;
const height = block.height;
const markerHeight = height * HEIGHT_MULTIPLIER;
const markerOffset = this.constants_.CURSOR_BLOCK_PADDING;
if (block.previousConnection) {
const connectionShape = this.constants_.shapeFor(
block.previousConnection,
) as Notch;
this.positionPrevious_(
width,
markerOffset,
markerHeight,
connectionShape,
);
} else if (block.outputConnection) {
const connectionShape = this.constants_.shapeFor(
block.outputConnection,
) as PuzzleTab;
this.positionOutput_(width, height, connectionShape);
} else {
this.positionBlock_(width, markerOffset, markerHeight);
}
this.setParent_(block);
this.showCurrent_();
}
/**
* Position and display the marker for a block.
*
* @param curNode The node to draw the marker for.
*/
protected showWithBlock_(curNode: ASTNode) {
this.showWithBlockPrevOutput(curNode);
}
/**
* Position and display the marker for a previous connection.
*
* @param curNode The node to draw the marker for.
*/
protected showWithPrevious_(curNode: ASTNode) {
this.showWithBlockPrevOutput(curNode);
}
/**
* Position and display the marker for an output connection.
*
* @param curNode The node to draw the marker for.
*/
protected showWithOutput_(curNode: ASTNode) {
this.showWithBlockPrevOutput(curNode);
}
/**
* Position and display the marker for a workspace coordinate.
* This is a horizontal line.
*
* @param curNode The node to draw the marker for.
*/
protected showWithCoordinates_(curNode: ASTNode) {
const wsCoordinate = curNode.getWsCoordinate();
let x = wsCoordinate?.x ?? 0;
const y = wsCoordinate?.y ?? 0;
if (this.workspace.RTL) {
x -= this.constants_.CURSOR_WS_WIDTH;
}
this.positionLine_(x, y, this.constants_.CURSOR_WS_WIDTH);
this.setParent_(this.workspace);
this.showCurrent_();
}
/**
* Position and display the marker for a field.
* This is a box around the field.
*
* @param curNode The node to draw the marker for.
*/
protected showWithField_(curNode: ASTNode) {
const field = curNode.getLocation() as Field;
const width = field.getSize().width;
const height = field.getSize().height;
this.positionRect_(0, 0, width, height);
this.setParent_(field);
this.showCurrent_();
}
/**
* Position and display the marker for an input.
* This is a puzzle piece.
*
* @param curNode The node to draw the marker for.
*/
protected showWithInput_(curNode: ASTNode) {
const connection = curNode.getLocation() as RenderedConnection;
const sourceBlock = connection.getSourceBlock();
this.positionInput_(connection);
this.setParent_(sourceBlock);
this.showCurrent_();
}
/**
* Position and display the marker for a next connection.
* This is a horizontal line.
*
* @param curNode The node to draw the marker for.
*/
protected showWithNext_(curNode: ASTNode) {
const connection = curNode.getLocation() as RenderedConnection;
const targetBlock = connection.getSourceBlock();
let x = 0;
const y = connection.getOffsetInBlock().y;
const width = targetBlock.getHeightWidth().width;
if (this.workspace.RTL) {
x = -width;
}
this.positionLine_(x, y, width);
this.setParent_(targetBlock);
this.showCurrent_();
}
/**
* Position and display the marker for a stack.
* This is a box with extra padding around the entire stack of blocks.
*
* @param curNode The node to draw the marker for.
*/
protected showWithStack_(curNode: ASTNode) {
const block = curNode.getLocation() as BlockSvg;
// Gets the height and width of entire stack.
const heightWidth = block.getHeightWidth();
// Add padding so that being on a stack looks different than being on a
// block.
const width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING;
const height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING;
// Shift the rectangle slightly to upper left so padding is equal on all
// sides.
const xPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
const yPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
let x = xPadding;
const y = yPadding;
if (this.workspace.RTL) {
x = -(width + xPadding);
}
this.positionRect_(x, y, width, height);
this.setParent_(block);
this.showCurrent_();
}
/**
* Position and display the marker for a flyout button.
* This is a box with extra padding around the button.
*
* @param curNode The node to draw the marker for.
*/
protected showWithButton_(curNode: ASTNode) {
const button = curNode.getLocation() as FlyoutButton;
// Gets the height and width of entire stack.
const heightWidth = {height: button.height, width: button.width};
// Add padding so that being on a button looks similar to being on a stack.
const width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING;
const height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING;
// Shift the rectangle slightly to upper left so padding is equal on all
// sides.
const xPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
const yPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
let x = xPadding;
const y = yPadding;
if (this.workspace.RTL) {
x = -(width + xPadding);
}
this.positionRect_(x, y, width, height);
this.setParent_(button);
this.showCurrent_();
}
/** Show the current marker. */
protected showCurrent_() {
this.hide();
if (this.currentMarkerSvg) {
this.currentMarkerSvg.style.display = '';
}
}
/**************************
* Position
**************************/
/**
* Position the marker for a block.
* Displays an outline of the top half of a rectangle around a block.
*
* @param width The width of the block.
* @param markerOffset The extra padding for around the block.
* @param markerHeight The height of the marker.
*/
protected positionBlock_(
width: number,
markerOffset: number,
markerHeight: number,
) {
const markerPath =
svgPaths.moveBy(-markerOffset, markerHeight) +
svgPaths.lineOnAxis('V', -markerOffset) +
svgPaths.lineOnAxis('H', width + markerOffset * 2) +
svgPaths.lineOnAxis('V', markerHeight);
if (!this.markerBlock_) {
throw new Error(
'createDom should be called before positioning the marker',
);
}
this.markerBlock_.setAttribute('d', markerPath);
if (this.workspace.RTL) {
this.flipRtl(this.markerBlock_);
}
this.currentMarkerSvg = this.markerBlock_;
}
/**
* Position the marker for an input connection.
* Displays a filled in puzzle piece.
*
* @param connection The connection to position marker around.
*/
protected positionInput_(connection: RenderedConnection) {
const x = connection.getOffsetInBlock().x;
const y = connection.getOffsetInBlock().y;
const path =
svgPaths.moveTo(0, 0) +
(this.constants_.shapeFor(connection) as PuzzleTab).pathDown;
this.markerInput_!.setAttribute('d', path);
this.markerInput_!.setAttribute(
'transform',
'translate(' +
x +
',' +
y +
')' +
(this.workspace.RTL ? ' scale(-1 1)' : ''),
);
this.currentMarkerSvg = this.markerInput_;
}
/**
* Move and show the marker at the specified coordinate in workspace units.
* Displays a horizontal line.
*
* @param x The new x, in workspace units.
* @param y The new y, in workspace units.
* @param width The new width, in workspace units.
*/
protected positionLine_(x: number, y: number, width: number) {
if (!this.markerSvgLine_) {
throw new Error('createDom should be called before positioning the line');
}
this.markerSvgLine_.setAttribute('x', `${x}`);
this.markerSvgLine_.setAttribute('y', `${y}`);
this.markerSvgLine_.setAttribute('width', `${width}`);
this.currentMarkerSvg = this.markerSvgLine_;
}
/**
* Position the marker for an output connection.
* Displays a puzzle outline and the top and bottom path.
*
* @param width The width of the block.
* @param height The height of the block.
* @param connectionShape The shape object for the connection.
*/
protected positionOutput_(
width: number,
height: number,
connectionShape: PuzzleTab,
) {
if (!this.markerBlock_) {
throw new Error(
'createDom should be called before positioning the output',
);
}
const markerPath =
svgPaths.moveBy(width, 0) +
svgPaths.lineOnAxis('h', -(width - connectionShape.width)) +
svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) +
connectionShape.pathDown +
svgPaths.lineOnAxis('V', height) +
svgPaths.lineOnAxis('H', width);
this.markerBlock_.setAttribute('d', markerPath);
if (this.workspace.RTL) {
this.flipRtl(this.markerBlock_);
}
this.currentMarkerSvg = this.markerBlock_;
}
/**
* Position the marker for a previous connection.
* Displays a half rectangle with a notch in the top to represent the previous
* connection.
*
* @param width The width of the block.
* @param markerOffset The offset of the marker from around the block.
* @param markerHeight The height of the marker.
* @param connectionShape The shape object for the connection.
*/
protected positionPrevious_(
width: number,
markerOffset: number,
markerHeight: number,
connectionShape: Notch,
) {
if (!this.markerBlock_) {
throw new Error(
'createDom should be called before positioning the previous connection marker',
);
}
const markerPath =
svgPaths.moveBy(-markerOffset, markerHeight) +
svgPaths.lineOnAxis('V', -markerOffset) +
svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) +
connectionShape.pathLeft +
svgPaths.lineOnAxis('H', width + markerOffset * 2) +
svgPaths.lineOnAxis('V', markerHeight);
this.markerBlock_.setAttribute('d', markerPath);
if (this.workspace.RTL) {
this.flipRtl(this.markerBlock_);
}
this.currentMarkerSvg = this.markerBlock_;
}
/**
* Move and show the marker at the specified coordinate in workspace units.
* Displays a filled in rectangle.
*
* @param x The new x, in workspace units.
* @param y The new y, in workspace units.
* @param width The new width, in workspace units.
* @param height The new height, in workspace units.
*/
protected positionRect_(x: number, y: number, width: number, height: number) {
if (!this.markerSvgRect_) {
throw new Error('createDom should be called before positioning the rect');
}
this.markerSvgRect_.setAttribute('x', `${x}`);
this.markerSvgRect_.setAttribute('y', `${y}`);
this.markerSvgRect_.setAttribute('width', `${width}`);
this.markerSvgRect_.setAttribute('height', `${height}`);
this.currentMarkerSvg = this.markerSvgRect_;
}
/**
* Flip the SVG paths in RTL.
*
* @param markerSvg The marker that we want to flip.
*/
private flipRtl(markerSvg: SVGElement) {
markerSvg.setAttribute('transform', 'scale(-1 1)');
}
/** Hide the marker. */
hide() {
if (
!this.markerSvgLine_ ||
!this.markerSvgRect_ ||
!this.markerInput_ ||
!this.markerBlock_
) {
throw new Error('createDom should be called before hiding the marker');
}
this.markerSvgLine_.style.display = 'none';
this.markerSvgRect_.style.display = 'none';
this.markerInput_.style.display = 'none';
this.markerBlock_.style.display = 'none';
}
/**
* Fire event for the marker or marker.
*
* @param oldNode The old node the marker used to be on.
* @param curNode The new node the marker is currently on.
*/
protected fireMarkerEvent(oldNode: ASTNode | null, curNode: ASTNode) {
const curBlock = curNode.getSourceBlock();
const event = new (eventUtils.get(EventType.MARKER_MOVE))(
curBlock,
this.isCursor(),
oldNode,
curNode,
);
eventUtils.fire(event);
}
/**
* Get the properties to make a marker blink.
*
* @returns The object holding attributes to make the marker blink.
*/
protected getBlinkProperties_(): {[key: string]: string} {
return {
'attributeType': 'XML',
'attributeName': 'fill',
'dur': '1s',
'values': this.colour_ + ';transparent;transparent;',
'repeatCount': 'indefinite',
};
}
/**
* Create the marker SVG.
*
* @returns The SVG node created.
*/
protected createDomInternal_(): Element {
/* This markup will be generated and added to the .svgGroup_:
<g>
<rect width="100" height="5">
<animate attributeType="XML" attributeName="fill" dur="1s"
values="transparent;transparent;#fff;transparent"
repeatCount="indefinite" />
</rect>
</g>
*/
this.markerSvg_ = dom.createSvgElement(
Svg.G,
{
'width': this.constants_.CURSOR_WS_WIDTH,
'height': this.constants_.WS_CURSOR_HEIGHT,
},
this.svgGroup_,
);
// A horizontal line used to represent a workspace coordinate or next
// connection.
this.markerSvgLine_ = dom.createSvgElement(
Svg.RECT,
{
'width': this.constants_.CURSOR_WS_WIDTH,
'height': this.constants_.WS_CURSOR_HEIGHT,
},
this.markerSvg_,
);
// A filled in rectangle used to represent a stack.
this.markerSvgRect_ = dom.createSvgElement(
Svg.RECT,
{
'class': 'blocklyVerticalMarker',
'rx': 10,
'ry': 10,
},
this.markerSvg_,
);
// A filled in puzzle piece used to represent an input value.
this.markerInput_ = dom.createSvgElement(
Svg.PATH,
{'transform': ''},
this.markerSvg_,
);
// A path used to represent a previous connection and a block, an output
// connection and a block, or a block.
this.markerBlock_ = dom.createSvgElement(
Svg.PATH,
{
'transform': '',
'fill': 'none',
'stroke-width': this.constants_.CURSOR_STROKE_WIDTH,
},
this.markerSvg_,
);
this.hide();
// Markers and stack markers don't blink.
if (this.isCursor()) {
const blinkProperties = this.getBlinkProperties_();
dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerSvgLine_);
dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerInput_);
dom.createSvgElement(
Svg.ANIMATE,
{...blinkProperties, attributeName: 'stroke'},
this.markerBlock_,
);
}
return this.markerSvg_;
}
/**
* Apply the marker's colour.
*
* @param _curNode The node that we want to draw the marker for.
*/
protected applyColour_(_curNode: ASTNode) {
if (
!this.markerSvgLine_ ||
!this.markerSvgRect_ ||
!this.markerInput_ ||
!this.markerBlock_
) {
throw new Error(
'createDom should be called before applying color to the markerj',
);
}
this.markerSvgLine_.setAttribute('fill', this.colour_);
this.markerSvgRect_.setAttribute('stroke', this.colour_);
this.markerInput_.setAttribute('fill', this.colour_);
this.markerBlock_.setAttribute('stroke', this.colour_);
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerSvgLine_.firstElementChild!.setAttribute('values', values);
this.markerInput_.firstElementChild!.setAttribute('values', values);
this.markerBlock_.firstElementChild!.setAttribute('values', values);
}
}
/** Dispose of this marker. */
dispose() {
if (this.svgGroup_) {
dom.removeNode(this.svgGroup_);
}
}
}

View File

@@ -24,18 +24,6 @@ export class PathObject implements IPathObject {
svgRoot: SVGElement;
svgPath: SVGElement;
/**
* Holds the cursors svg element when the cursor is attached to the block.
* This is null if there is no cursor on the block.
*/
cursorSvg: SVGElement | null = null;
/**
* Holds the markers svg element when the marker is attached to the block.
* This is null if there is no marker on the block.
*/
markerSvg: SVGElement | null = null;
constants: ConstantProvider;
style: BlockStyle;
@@ -86,42 +74,6 @@ export class PathObject implements IPathObject {
this.svgPath.setAttribute('transform', 'scale(-1 1)');
}
/**
* Add the cursor SVG to this block's SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the block SVG
* group.
*/
setCursorSvg(cursorSvg: SVGElement) {
if (!cursorSvg) {
this.cursorSvg = null;
return;
}
this.svgRoot.appendChild(cursorSvg);
this.cursorSvg = cursorSvg;
}
/**
* Add the marker SVG to this block's SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the block SVG
* group.
*/
setMarkerSvg(markerSvg: SVGElement) {
if (!markerSvg) {
this.markerSvg = null;
return;
}
if (this.cursorSvg) {
this.svgRoot.insertBefore(markerSvg, this.cursorSvg);
} else {
this.svgRoot.appendChild(markerSvg);
}
this.markerSvg = markerSvg;
}
/**
* Apply the stored colours to the block's path, taking into account whether
* the paths belong to a shadow block.

View File

@@ -11,14 +11,11 @@ import type {BlockSvg} from '../../block_svg.js';
import {Connection} from '../../connection.js';
import {ConnectionType} from '../../connection_type.js';
import type {IRegistrable} from '../../interfaces/i_registrable.js';
import type {Marker} from '../../keyboard_nav/marker.js';
import type {BlockStyle, Theme} from '../../theme.js';
import type {WorkspaceSvg} from '../../workspace_svg.js';
import {ConstantProvider} from './constants.js';
import {Drawer} from './drawer.js';
import type {IPathObject} from './i_path_object.js';
import {RenderInfo} from './info.js';
import {MarkerSvg} from './marker_svg.js';
import {PathObject} from './path_object.js';
/**
@@ -167,17 +164,6 @@ export class Renderer implements IRegistrable {
return new Drawer(block, info);
}
/**
* Create a new instance of the renderer's marker drawer.
*
* @param workspace The workspace the marker belongs to.
* @param marker The marker.
* @returns The object in charge of drawing the marker.
*/
makeMarkerDrawer(workspace: WorkspaceSvg, marker: Marker): MarkerSvg {
return new MarkerSvg(workspace, this.getConstants(), marker);
}
/**
* Create a new instance of a renderer path object.
*

View File

@@ -1,144 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
// Former goog.module ID: Blockly.zelos.MarkerSvg
import type {BlockSvg} from '../../block_svg.js';
import type {ASTNode} from '../../keyboard_nav/ast_node.js';
import type {Marker} from '../../keyboard_nav/marker.js';
import type {RenderedConnection} from '../../rendered_connection.js';
import * as dom from '../../utils/dom.js';
import {Svg} from '../../utils/svg.js';
import type {WorkspaceSvg} from '../../workspace_svg.js';
import type {ConstantProvider as BaseConstantProvider} from '../common/constants.js';
import {MarkerSvg as BaseMarkerSvg} from '../common/marker_svg.js';
import type {ConstantProvider as ZelosConstantProvider} from './constants.js';
/**
* Class to draw a marker.
*/
export class MarkerSvg extends BaseMarkerSvg {
// TODO(b/109816955): remove '!', see go/strict-prop-init-fix.
constants_!: ZelosConstantProvider;
private markerCircle: SVGCircleElement | null = null;
/**
* @param workspace The workspace the marker belongs to.
* @param constants The constants for the renderer.
* @param marker The marker to draw.
*/
constructor(
workspace: WorkspaceSvg,
constants: BaseConstantProvider,
marker: Marker,
) {
super(workspace, constants, marker);
}
/**
* Position and display the marker for an input or an output connection.
*
* @param curNode The node to draw the marker for.
*/
private showWithInputOutput(curNode: ASTNode) {
const block = curNode.getSourceBlock() as BlockSvg;
const connection = curNode.getLocation() as RenderedConnection;
const offsetInBlock = connection.getOffsetInBlock();
this.positionCircle(offsetInBlock.x, offsetInBlock.y);
this.setParent_(block);
this.showCurrent_();
}
override showWithOutput_(curNode: ASTNode) {
this.showWithInputOutput(curNode);
}
override showWithInput_(curNode: ASTNode) {
this.showWithInputOutput(curNode);
}
/**
* Draw a rectangle around the block.
*
* @param curNode The current node of the marker.
*/
override showWithBlock_(curNode: ASTNode) {
const block = curNode.getLocation() as BlockSvg;
// Gets the height and width of entire stack.
const heightWidth = block.getHeightWidth();
// Add padding so that being on a stack looks different than being on a
// block.
this.positionRect_(0, 0, heightWidth.width, heightWidth.height);
this.setParent_(block);
this.showCurrent_();
}
/**
* Position the circle we use for input and output connections.
*
* @param x The x position of the circle.
* @param y The y position of the circle.
*/
private positionCircle(x: number, y: number) {
this.markerCircle?.setAttribute('cx', `${x}`);
this.markerCircle?.setAttribute('cy', `${y}`);
this.currentMarkerSvg = this.markerCircle;
}
override hide() {
super.hide();
if (this.markerCircle) {
this.markerCircle.style.display = 'none';
}
}
override createDomInternal_() {
/* clang-format off */
/* This markup will be generated and added to the .svgGroup_:
<g>
<rect width="100" height="5">
<animate attributeType="XML" attributeName="fill" dur="1s"
values="transparent;transparent;#fff;transparent" repeatCount="indefinite" />
</rect>
</g>
*/
/* clang-format on */
super.createDomInternal_();
this.markerCircle = dom.createSvgElement(
Svg.CIRCLE,
{
'r': this.constants_.CURSOR_RADIUS,
'stroke-width': this.constants_.CURSOR_STROKE_WIDTH,
},
this.markerSvg_,
);
this.hide();
// Markers and stack cursors don't blink.
if (this.isCursor()) {
const blinkProperties = this.getBlinkProperties_();
dom.createSvgElement(Svg.ANIMATE, blinkProperties, this.markerCircle!);
}
return this.markerSvg_!;
}
override applyColour_(curNode: ASTNode) {
super.applyColour_(curNode);
this.markerCircle?.setAttribute('fill', this.colour_);
this.markerCircle?.setAttribute('stroke', this.colour_);
if (this.isCursor()) {
const values = this.colour_ + ';transparent;transparent;';
this.markerCircle?.firstElementChild!.setAttribute('values', values);
}
}
}

View File

@@ -7,16 +7,13 @@
// Former goog.module ID: Blockly.zelos.Renderer
import type {BlockSvg} from '../../block_svg.js';
import type {Marker} from '../../keyboard_nav/marker.js';
import type {BlockStyle} from '../../theme.js';
import type {WorkspaceSvg} from '../../workspace_svg.js';
import * as blockRendering from '../common/block_rendering.js';
import type {RenderInfo as BaseRenderInfo} from '../common/info.js';
import {Renderer as BaseRenderer} from '../common/renderer.js';
import {ConstantProvider} from './constants.js';
import {Drawer} from './drawer.js';
import {RenderInfo} from './info.js';
import {MarkerSvg} from './marker_svg.js';
import {PathObject} from './path_object.js';
/**
@@ -69,20 +66,6 @@ export class Renderer extends BaseRenderer {
return new Drawer(block, info as RenderInfo);
}
/**
* Create a new instance of the renderer's cursor drawer.
*
* @param workspace The workspace the cursor belongs to.
* @param marker The marker.
* @returns The object in charge of drawing the marker.
*/
override makeMarkerDrawer(
workspace: WorkspaceSvg,
marker: Marker,
): MarkerSvg {
return new MarkerSvg(workspace, this.getConstants(), marker);
}
/**
* Create a new instance of a renderer path object.
*

View File

@@ -11,7 +11,6 @@
import {ConstantProvider} from './constants.js';
import {Drawer} from './drawer.js';
import {RenderInfo} from './info.js';
import {MarkerSvg} from './marker_svg.js';
import {BottomRow} from './measurables/bottom_row.js';
import {StatementInput} from './measurables/inputs.js';
import {RightConnectionShape} from './measurables/row_elements.js';
@@ -23,7 +22,6 @@ export {
BottomRow,
ConstantProvider,
Drawer,
MarkerSvg,
PathObject,
Renderer,
RenderInfo,

View File

@@ -64,7 +64,6 @@ import {Navigator} from './navigator.js';
import {Options} from './options.js';
import * as Procedures from './procedures.js';
import * as registry from './registry.js';
import * as renderManagement from './render_management.js';
import * as blockRendering from './renderers/common/block_rendering.js';
import type {Renderer} from './renderers/common/renderer.js';
import type {ScrollbarPair} from './scrollbar_pair.js';
@@ -474,28 +473,6 @@ export class WorkspaceSvg
return this.componentManager;
}
/**
* Add the cursor SVG to this workspaces SVG group.
*
* @param cursorSvg The SVG root of the cursor to be added to the workspace
* SVG group.
* @internal
*/
setCursorSvg(cursorSvg: SVGElement) {
this.markerManager.setCursorSvg(cursorSvg);
}
/**
* Add the marker SVG to this workspaces SVG group.
*
* @param markerSvg The SVG root of the marker to be added to the workspace
* SVG group.
* @internal
*/
setMarkerSvg(markerSvg: SVGElement) {
this.markerManager.setMarkerSvg(markerSvg);
}
/**
* Get the marker with the given ID.
*
@@ -1340,10 +1317,6 @@ export class WorkspaceSvg
.flatMap((block) => block.getDescendants(false))
.filter((block) => block.isInsertionMarker())
.forEach((block) => block.queueRender());
renderManagement
.finishQueuedRenders()
.then(() => void this.markerManager.updateMarkers());
}
/**