text: /**
   * @license
   * Copyright 2019 Google LLC
   * SPDX-License-Identifier: Apache-2.0
   */
  
  /**
   * @fileoverview Object in charge of managing markers and the cursor.
   */
  'use strict';
  
  /**
   * Object in charge of managing markers and the cursor.
   * @class
   */
  goog.module('Blockly.MarkerManager');
  
  /* eslint-disable-next-line no-unused-vars */
  const {Cursor} = goog.requireType('Blockly.Cursor');
  /* eslint-disable-next-line no-unused-vars */
  const {Marker} = goog.requireType('Blockly.Marker');
  /* eslint-disable-next-line no-unused-vars */
  const {WorkspaceSvg} = goog.requireType('Blockly.WorkspaceSvg');
  
  
  /**
   * Class to manage the multiple markers and the cursor on a workspace.
   * @param {!WorkspaceSvg} workspace The workspace for the marker manager.
   * @constructor
   * @alias Blockly.MarkerManager
   * @package
   */
  const MarkerManager = function(workspace) {
    /**
     * The cursor.
     * @type {?Cursor}
     * @private
     */
    this.cursor_ = null;
  
    /**
     * The cursor's SVG element.
     * @type {?SVGElement}
     * @private
     */
    this.cursorSvg_ = null;
  
    /**
     * The map of markers for the workspace.
     * @type {!Object<string, !Marker>}
     * @private
     */
    this.markers_ = Object.create(null);
  
    /**
     * The workspace this marker manager is associated with.
     * @type {!WorkspaceSvg}
     * @private
     */
    this.workspace_ = workspace;
  };
  
  /**
   * The name of the local marker.
   * @type {string}
   * @const
   */
  MarkerManager.LOCAL_MARKER = 'local_marker_1';
  
  /**
   * Register the marker by adding it to the map of markers.
   * @param {string} id A unique identifier for the marker.
   * @param {!Marker} marker The marker to register.
   */
  MarkerManager.prototype.registerMarker = function(id, marker) {
    if (this.markers_[id]) {
      this.unregisterMarker(id);
    }
    marker.setDrawer(
        this.workspace_.getRenderer().makeMarkerDrawer(this.workspace_, marker));
    this.setMarkerSvg(marker.getDrawer().createDom());
    this.markers_[id] = marker;
  };
  
  /**
   * Unregister the marker by removing it from the map of markers.
   * @param {string} id The ID of the marker to unregister.
   */
  MarkerManager.prototype.unregisterMarker = function(id) {
    const marker = this.markers_[id];
    if (marker) {
      marker.dispose();
      delete this.markers_[id];
    } else {
      throw Error(
          'Marker with ID ' + id + ' does not exist. ' +
          'Can only unregister markers that exist.');
    }
  };
  
  /**
   * Get the cursor for the workspace.
   * @return {?Cursor} The cursor for this workspace.
   */
  MarkerManager.prototype.getCursor = function() {
    return this.cursor_;
  };
  
  /**
   * Get a single marker that corresponds to the given ID.
   * @param {string} id A unique identifier for the marker.
   * @return {?Marker} The marker that corresponds to the given ID,
   *     or null if none exists.
   */
  MarkerManager.prototype.getMarker = function(id) {
    return this.markers_[id] || null;
  };
  
  /**
   * Sets the cursor and initializes the drawer for use with keyboard navigation.
   * @param {Cursor} cursor The cursor used to move around this workspace.
   */
  MarkerManager.prototype.setCursor = function(cursor) {
    if (this.cursor_ && this.cursor_.getDrawer()) {
      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(this.cursor_.getDrawer().createDom());
    }
  };
  
  /**
   * Add the cursor SVG to this workspace SVG group.
   * @param {?SVGElement} cursorSvg The SVG root of the cursor to be added to the
   *     workspace SVG group.
   * @package
   */
  MarkerManager.prototype.setCursorSvg = function(cursorSvg) {
    if (!cursorSvg) {
      this.cursorSvg_ = null;
      return;
    }
  
    this.workspace_.getBlockCanvas().appendChild(cursorSvg);
    this.cursorSvg_ = cursorSvg;
  };
  
  /**
   * Add the marker SVG to this workspaces SVG group.
   * @param {?SVGElement} markerSvg The SVG root of the marker to be added to the
   *     workspace SVG group.
   * @package
   */
  MarkerManager.prototype.setMarkerSvg = function(markerSvg) {
    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.
   * @package
   */
  MarkerManager.prototype.updateMarkers = function() {
    if (this.workspace_.keyboardAccessibilityMode && this.cursorSvg_) {
      this.workspace_.getCursor().draw();
    }
  };
  
  /**
   * Dispose of the marker manager.
   * Go through and delete all markers associated with this marker manager.
   * @suppress {checkTypes}
   * @package
   */
  MarkerManager.prototype.dispose = function() {
    const markerIds = Object.keys(this.markers_);
    for (let i = 0, markerId; (markerId = markerIds[i]); i++) {
      this.unregisterMarker(markerId);
    }
    this.markers_ = null;
    if (this.cursor_) {
      this.cursor_.dispose();
      this.cursor_ = null;
    }
  };
  
  exports.MarkerManager = MarkerManager;
  