mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-06-05 17:34:55 -04:00
611 lines
19 KiB
JavaScript
611 lines
19 KiB
JavaScript
/**
|
|
* @license
|
|
* Visual Blocks Editor
|
|
*
|
|
* Copyright 2017 Google Inc.
|
|
* https://developers.google.com/blockly/
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Object representing a code comment on a rendered workspace.
|
|
* @author fenichel@google.com (Rachel Fenichel)
|
|
*/
|
|
'use strict';
|
|
|
|
goog.provide('Blockly.WorkspaceCommentSvg');
|
|
|
|
goog.require('Blockly.Events.CommentCreate');
|
|
goog.require('Blockly.Events.CommentDelete');
|
|
goog.require('Blockly.Events.CommentMove');
|
|
goog.require('Blockly.WorkspaceComment');
|
|
|
|
|
|
/**
|
|
* Class for a workspace comment's SVG representation.
|
|
* @param {!Blockly.Workspace} workspace The block's workspace.
|
|
* @param {string} content The content of this workspace comment.
|
|
* @param {number} height Height of the comment.
|
|
* @param {number} width Width of the comment.
|
|
* @param {boolean} minimized Whether this comment is minimized.
|
|
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
|
|
* create a new ID.
|
|
* @extends {Blockly.WorkspaceComment}
|
|
* @constructor
|
|
*/
|
|
Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, minimized,
|
|
opt_id) {
|
|
// Create core elements for the block.
|
|
/**
|
|
* @type {SVGElement}
|
|
* @private
|
|
*/
|
|
this.svgGroup_ = Blockly.utils.createSvgElement(
|
|
'g', {}, null);
|
|
this.svgGroup_.translate_ = '';
|
|
|
|
this.svgRect_ = Blockly.utils.createSvgElement(
|
|
'rect',
|
|
{
|
|
'class': 'scratchCommentRect scratchWorkspaceCommentBorder',
|
|
'x': 0,
|
|
'y': 0,
|
|
'rx': 4 * Blockly.WorkspaceCommentSvg.BORDER_WIDTH,
|
|
'ry': 4 * Blockly.WorkspaceCommentSvg.BORDER_WIDTH
|
|
});
|
|
this.svgGroup_.appendChild(this.svgRect_);
|
|
|
|
|
|
/**
|
|
* Whether the comment is rendered onscreen and is a part of the DOM.
|
|
* @type {boolean}
|
|
* @private
|
|
*/
|
|
this.rendered_ = false;
|
|
|
|
/**
|
|
* Whether to move the comment to the drag surface when it is dragged.
|
|
* True if it should move, false if it should be translated directly.
|
|
* @type {boolean}
|
|
* @private
|
|
*/
|
|
this.useDragSurface_ =
|
|
Blockly.utils.is3dSupported() && !!workspace.blockDragSurface_;
|
|
|
|
Blockly.WorkspaceCommentSvg.superClass_.constructor.call(this,
|
|
workspace, content, height, width, minimized, opt_id);
|
|
|
|
this.render();
|
|
}; goog.inherits(Blockly.WorkspaceCommentSvg, Blockly.WorkspaceComment);
|
|
|
|
/**
|
|
* The width and height to use to size a workspace comment when it is first
|
|
* added, before it has been edited by the user.
|
|
* @type {number}
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.DEFAULT_SIZE = 200;
|
|
|
|
/**
|
|
* Dispose of this comment.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.dispose = function() {
|
|
if (!this.workspace) {
|
|
// The comment has already been deleted.
|
|
return;
|
|
}
|
|
// If this comment is being deleted, unlink the mouse events.
|
|
if (Blockly.selected == this) {
|
|
this.unselect();
|
|
this.workspace.cancelCurrentGesture();
|
|
}
|
|
|
|
if (Blockly.Events.isEnabled()) {
|
|
Blockly.Events.fire(new Blockly.Events.CommentDelete(this));
|
|
}
|
|
|
|
goog.dom.removeNode(this.svgGroup_);
|
|
// Sever JavaScript to DOM connections.
|
|
this.svgGroup_ = null;
|
|
this.svgRect_ = null;
|
|
// Dispose of any rendered components
|
|
this.disposeInternal_();
|
|
|
|
Blockly.Events.disable();
|
|
Blockly.WorkspaceCommentSvg.superClass_.dispose.call(this);
|
|
Blockly.Events.enable();
|
|
};
|
|
|
|
/**
|
|
* Create and initialize the SVG representation of a workspace comment.
|
|
* May be called more than once.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.initSvg = function() {
|
|
goog.asserts.assert(this.workspace.rendered, 'Workspace is headless.');
|
|
if (!this.workspace.options.readOnly && !this.eventsInit_) {
|
|
Blockly.bindEventWithChecks_(
|
|
this.svgRectTarget_, 'mousedown', this, this.pathMouseDown_);
|
|
Blockly.bindEventWithChecks_(
|
|
this.svgHandleTarget_, 'mousedown', this, this.pathMouseDown_);
|
|
}
|
|
this.eventsInit_ = true;
|
|
|
|
this.updateMovable();
|
|
if (!this.getSvgRoot().parentNode) {
|
|
this.workspace.getBubbleCanvas().appendChild(this.getSvgRoot());
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle a mouse-down on an SVG comment.
|
|
* @param {!Event} e Mouse down event or touch start event.
|
|
* @private
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.pathMouseDown_ = function(e) {
|
|
var gesture = this.workspace.getGesture(e);
|
|
if (gesture) {
|
|
gesture.handleBubbleStart(e, this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Show the context menu for this workspace comment.
|
|
* @param {!Event} e Mouse event.
|
|
* @private
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.showContextMenu_ = function(e) {
|
|
if (this.workspace.options.readOnly) {
|
|
return;
|
|
}
|
|
// Save the current workspace comment in a variable for use in closures.
|
|
var comment = this;
|
|
var menuOptions = [];
|
|
|
|
if (this.isDeletable() && this.isMovable()) {
|
|
menuOptions.push(Blockly.ContextMenu.commentDuplicateOption(comment));
|
|
menuOptions.push(Blockly.ContextMenu.commentDeleteOption(comment));
|
|
}
|
|
|
|
Blockly.ContextMenu.show(e, menuOptions, this.RTL);
|
|
};
|
|
|
|
/**
|
|
* Select this comment. Highlight it visually.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.select = function() {
|
|
if (Blockly.selected == this) {
|
|
return;
|
|
}
|
|
var oldId = null;
|
|
if (Blockly.selected) {
|
|
oldId = Blockly.selected.id;
|
|
// Unselect any previously selected block or comment.
|
|
Blockly.Events.disable();
|
|
try {
|
|
Blockly.selected.unselect();
|
|
} finally {
|
|
Blockly.Events.enable();
|
|
}
|
|
}
|
|
var event = new Blockly.Events.Ui(null, 'selected', oldId, this.id);
|
|
event.workspaceId = this.workspace.id;
|
|
Blockly.Events.fire(event);
|
|
Blockly.selected = this;
|
|
this.addSelect();
|
|
};
|
|
|
|
/**
|
|
* Unselect this comment. Remove its highlighting.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.unselect = function() {
|
|
if (Blockly.selected != this) {
|
|
return;
|
|
}
|
|
var event = new Blockly.Events.Ui(null, 'selected', this.id, null);
|
|
event.workspaceId = this.workspace.id;
|
|
Blockly.Events.fire(event);
|
|
Blockly.selected = null;
|
|
this.removeSelect();
|
|
};
|
|
|
|
/**
|
|
* Select this comment. Highlight it visually.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.addSelect = function() {
|
|
Blockly.utils.addClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
|
|
this.setFocus();
|
|
};
|
|
|
|
/**
|
|
* Unselect this comment. Remove its highlighting.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.removeSelect = function() {
|
|
Blockly.utils.removeClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
|
|
this.blurFocus();
|
|
};
|
|
|
|
/**
|
|
* Focus this comment. Highlight it visually.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.addFocus = function() {
|
|
Blockly.utils.addClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
};
|
|
|
|
/**
|
|
* Unfocus this comment. Remove its highlighting.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.removeFocus = function() {
|
|
Blockly.utils.removeClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
};
|
|
|
|
/**
|
|
* Return the coordinates of the top-left corner of this comment relative to the
|
|
* drawing surface's origin (0,0), in workspace units.
|
|
* If the comment is on the workspace, (0, 0) is the origin of the workspace
|
|
* coordinate system.
|
|
* This does not change with workspace scale.
|
|
* @return {!goog.math.Coordinate} Object with .x and .y properties in
|
|
* workspace coordinates.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() {
|
|
var x = 0;
|
|
var y = 0;
|
|
|
|
var dragSurfaceGroup = this.useDragSurface_ ?
|
|
this.workspace.blockDragSurface_.getGroup() : null;
|
|
|
|
var element = this.getSvgRoot();
|
|
if (element) {
|
|
do {
|
|
// Loop through this comment and every parent.
|
|
var xy = Blockly.utils.getRelativeXY(element);
|
|
x += xy.x;
|
|
y += xy.y;
|
|
// If this element is the current element on the drag surface, include
|
|
// the translation of the drag surface itself.
|
|
if (this.useDragSurface_ &&
|
|
this.workspace.blockDragSurface_.getCurrentBlock() == element) {
|
|
var surfaceTranslation =
|
|
this.workspace.blockDragSurface_.getSurfaceTranslation();
|
|
x += surfaceTranslation.x;
|
|
y += surfaceTranslation.y;
|
|
}
|
|
element = element.parentNode;
|
|
} while (element && element != this.workspace.getBubbleCanvas() &&
|
|
element != dragSurfaceGroup);
|
|
}
|
|
this.xy_ = new goog.math.Coordinate(x, y);
|
|
return this.xy_;
|
|
};
|
|
|
|
/**
|
|
* Move a comment by a relative offset.
|
|
* @param {number} dx Horizontal offset, in workspace units.
|
|
* @param {number} dy Vertical offset, in workspace units.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) {
|
|
var event = new Blockly.Events.CommentMove(this);
|
|
// TODO: Do I need to look up the relative to surface XY position here?
|
|
var xy = this.getRelativeToSurfaceXY();
|
|
this.translate(xy.x + dx, xy.y + dy);
|
|
event.recordNew();
|
|
Blockly.Events.fire(event);
|
|
this.workspace.resizeContents();
|
|
};
|
|
|
|
/**
|
|
* Transforms a comment by setting the translation on the transform attribute
|
|
* of the block's SVG.
|
|
* @param {number} x The x coordinate of the translation in workspace units.
|
|
* @param {number} y The y coordinate of the translation in workspace units.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.translate = function(x, y) {
|
|
this.xy_ = new goog.math.Coordinate(x, y);
|
|
this.getSvgRoot().setAttribute('transform',
|
|
'translate(' + x + ',' + y + ')');
|
|
};
|
|
|
|
/**
|
|
* Move this comment to its workspace's drag surface, accounting for positioning.
|
|
* Generally should be called at the same time as setDragging(true).
|
|
* Does nothing if useDragSurface_ is false.
|
|
* @private
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.moveToDragSurface_ = function() {
|
|
if (!this.useDragSurface_) {
|
|
return;
|
|
}
|
|
// The translation for drag surface blocks,
|
|
// is equal to the current relative-to-surface position,
|
|
// to keep the position in sync as it move on/off the surface.
|
|
// This is in workspace coordinates.
|
|
var xy = this.getRelativeToSurfaceXY();
|
|
this.clearTransformAttributes_();
|
|
this.workspace.blockDragSurface_.translateSurface(xy.x, xy.y);
|
|
// Execute the move on the top-level SVG component
|
|
this.workspace.blockDragSurface_.setBlocksAndShow(this.getSvgRoot());
|
|
};
|
|
|
|
/**
|
|
* Move this comment back to the workspace block canvas.
|
|
* Generally should be called at the same time as setDragging(false).
|
|
* Does nothing if useDragSurface_ is false.
|
|
* @param {!goog.math.Coordinate} newXY The position the comment should take on
|
|
* on the workspace canvas, in workspace coordinates.
|
|
* @private
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.moveOffDragSurface_ = function(newXY) {
|
|
if (!this.useDragSurface_) {
|
|
return;
|
|
}
|
|
// Translate to current position, turning off 3d.
|
|
this.translate(newXY.x, newXY.y);
|
|
this.workspace.blockDragSurface_.clearAndHide(this.workspace.getCanvas());
|
|
};
|
|
|
|
/**
|
|
* Move this comment during a drag, taking into account whether we are using a
|
|
* drag surface to translate blocks.
|
|
* @param {?Blockly.BlockDragSurfaceSvg} dragSurface The surface that carries
|
|
* rendered items during a drag, or null if no drag surface is in use.
|
|
* @param {!goog.math.Coordinate} newLoc The location to translate to, in
|
|
* workspace coordinates.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.moveDuringDrag = function(dragSurface, newLoc) {
|
|
if (dragSurface) {
|
|
dragSurface.translateSurface(newLoc.x, newLoc.y);
|
|
} else {
|
|
this.svgGroup_.translate_ = 'translate(' + newLoc.x + ',' + newLoc.y + ')';
|
|
this.svgGroup_.setAttribute('transform',
|
|
this.svgGroup_.translate_ + this.svgGroup_.skew_);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Move the bubble group to the specified location in workspace coordinates.
|
|
* @param {number} x The x position to move to.
|
|
* @param {number} y The y position to move to.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.moveTo = function(x, y) {
|
|
this.translate(x, y);
|
|
};
|
|
|
|
/**
|
|
* Clear the comment of transform="..." attributes.
|
|
* Used when the comment is switching from 3d to 2d transform or vice versa.
|
|
* @private
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.clearTransformAttributes_ = function() {
|
|
Blockly.utils.removeAttribute(this.getSvgRoot(), 'transform');
|
|
};
|
|
|
|
/**
|
|
* Return the rendered size of the comment or the stored size if the comment is
|
|
* not rendered. This differs from getHeightWidth in the behavior of rendered
|
|
* minimized comments. This function reports the actual size of the minimized
|
|
* comment instead of the full sized comment height/width.
|
|
* @return {!{height: number, width: number}} Object with height and width
|
|
* properties in workspace units.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.getBubbleSize = function() {
|
|
if (this.rendered_) {
|
|
return {
|
|
width: parseInt(this.svgRect_.getAttribute('width')),
|
|
height: parseInt(this.svgRect_.getAttribute('height'))
|
|
};
|
|
} else {
|
|
this.getHeightWidth();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Returns the coordinates of a bounding box describing the dimensions of this
|
|
* comment.
|
|
* Coordinate system: workspace coordinates.
|
|
* @return {!{topLeft: goog.math.Coordinate, bottomRight: goog.math.Coordinate}}
|
|
* Object with top left and bottom right coordinates of the bounding box.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.getBoundingRectangle = function() {
|
|
var blockXY = this.getRelativeToSurfaceXY();
|
|
var commentBounds = this.getHeightWidth();
|
|
var topLeft;
|
|
var bottomRight;
|
|
if (this.RTL) {
|
|
topLeft = new goog.math.Coordinate(blockXY.x - (commentBounds.width),
|
|
blockXY.y);
|
|
// Add the width of the tab/puzzle piece knob to the x coordinate
|
|
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
bottomRight = new goog.math.Coordinate(blockXY.x,
|
|
blockXY.y + commentBounds.height);
|
|
} else {
|
|
// Subtract the width of the tab/puzzle piece knob to the x coordinate
|
|
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
topLeft = new goog.math.Coordinate(blockXY.x, blockXY.y);
|
|
bottomRight = new goog.math.Coordinate(blockXY.x + commentBounds.width,
|
|
blockXY.y + commentBounds.height);
|
|
}
|
|
return {topLeft: topLeft, bottomRight: bottomRight};
|
|
};
|
|
|
|
/**
|
|
* Add or remove the UI indicating if this comment is movable or not.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.updateMovable = function() {
|
|
if (this.isMovable()) {
|
|
Blockly.utils.addClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
|
|
} else {
|
|
Blockly.utils.removeClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Set whether this comment is movable or not.
|
|
* @param {boolean} movable True if movable.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.setMovable = function(movable) {
|
|
Blockly.WorkspaceCommentSvg.superClass_.setMovable.call(this, movable);
|
|
this.updateMovable();
|
|
};
|
|
|
|
/**
|
|
* Recursively adds or removes the dragging class to this node and its children.
|
|
* @param {boolean} adding True if adding, false if removing.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.setDragging = function(adding) {
|
|
if (adding) {
|
|
var group = this.getSvgRoot();
|
|
group.translate_ = '';
|
|
group.skew_ = '';
|
|
Blockly.utils.addClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
|
|
} else {
|
|
Blockly.utils.removeClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Return the root node of the SVG or null if none exists.
|
|
* @return {Element} The root SVG node (probably a group).
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.getSvgRoot = function() {
|
|
return this.svgGroup_;
|
|
};
|
|
|
|
/**
|
|
* Returns this comment's text.
|
|
* @return {string} Comment text.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.getText = function() {
|
|
return this.textarea_ ? this.textarea_.value : this.content_;
|
|
};
|
|
|
|
/**
|
|
* Set this comment's text.
|
|
* @param {string} text Comment text.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.setText = function(text) {
|
|
Blockly.WorkspaceCommentSvg.superClass_.setText.call(this, text);
|
|
if (this.textarea_) {
|
|
this.textarea_.value = text;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Update the cursor over this comment by adding or removing a class.
|
|
* @param {boolean} enable True if the delete cursor should be shown, false
|
|
* otherwise.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.setDeleteStyle = function(enable) {
|
|
if (enable) {
|
|
Blockly.utils.addClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
|
|
} else {
|
|
Blockly.utils.removeClass(
|
|
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
|
|
}
|
|
};
|
|
|
|
Blockly.WorkspaceCommentSvg.prototype.setAutoLayout = function() {
|
|
// NOP for compatibility with the bubble dragger.
|
|
};
|
|
|
|
/**
|
|
* Decode an XML comment tag and create a rendered comment on the workspace.
|
|
* @param {!Element} xmlComment XML comment element.
|
|
* @param {!Blockly.Workspace} workspace The workspace.
|
|
* @param {number=} opt_wsWidth The width of the workspace, which is used to
|
|
* position comments correctly in RTL.
|
|
* @return {!Blockly.WorkspaceCommentSvg} The created workspace comment.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.fromXml = function(xmlComment, workspace,
|
|
opt_wsWidth) {
|
|
Blockly.Events.disable();
|
|
try {
|
|
var info = Blockly.WorkspaceComment.parseAttributes(xmlComment);
|
|
|
|
var comment = new Blockly.WorkspaceCommentSvg(workspace,
|
|
info.content, info.h, info.w, info.minimized, info.id);
|
|
if (workspace.rendered) {
|
|
comment.initSvg();
|
|
comment.render(false);
|
|
}
|
|
// Position the comment correctly, taking into account the width of a
|
|
// rendered RTL workspace.
|
|
if (!isNaN(info.x) && !isNaN(info.y)) {
|
|
if (workspace.RTL) {
|
|
var wsWidth = opt_wsWidth || workspace.getWidth();
|
|
comment.moveBy(wsWidth - info.x, info.y);
|
|
} else {
|
|
comment.moveBy(info.x, info.y);
|
|
}
|
|
}
|
|
} finally {
|
|
Blockly.Events.enable();
|
|
}
|
|
Blockly.WorkspaceComment.fireCreateEvent(comment);
|
|
|
|
return comment;
|
|
};
|
|
|
|
/**
|
|
* Encode a comment subtree as XML with XY coordinates.
|
|
* @param {boolean=} opt_noId True if the encoder should skip the comment id.
|
|
* @return {!Element} Tree of XML elements.
|
|
* @package
|
|
*/
|
|
Blockly.WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
|
|
var width; // Not used in LTR.
|
|
if (this.workspace.RTL) {
|
|
// Here be performance dragons: This calls getMetrics().
|
|
width = this.workspace.getWidth();
|
|
}
|
|
var element = this.toXml(opt_noId);
|
|
var xy = this.getRelativeToSurfaceXY();
|
|
element.setAttribute('x',
|
|
Math.round(this.workspace.RTL ? width - xy.x : xy.x));
|
|
element.setAttribute('y', Math.round(xy.y));
|
|
element.setAttribute('h', this.getHeight());
|
|
element.setAttribute('w', this.getWidth());
|
|
return element;
|
|
};
|