UNPKG

cloud-blocks

Version:

Cloud Blocks is a library for building scratch computing interfaces with Luxrobo MODI.

458 lines (410 loc) 11.7 kB
/** * @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 the workspace. * @author fenichel@google.com (Rachel Fenichel) */ 'use strict'; goog.provide('Blockly.WorkspaceComment'); goog.require('Blockly.Events.CommentChange'); goog.require('Blockly.Events.CommentCreate'); goog.require('Blockly.Events.CommentDelete'); goog.require('Blockly.Events.CommentMove'); goog.require('goog.math.Coordinate'); /** * Class for a workspace comment. * @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 in the minimized state * @param {string=} opt_id Optional ID. Use this ID if provided, otherwise * create a new ID. If the ID conflicts with an in-use ID, a new one will * be generated. * @constructor */ Blockly.WorkspaceComment = function ( workspace, content, height, width, minimized, opt_id ) { /** @type {string} */ this.id = opt_id && !workspace.getCommentById(opt_id) ? opt_id : Blockly.utils.genUid(); workspace.addTopComment(this); /** * The comment's position in workspace units. (0, 0) is at the workspace's * origin; scale does not change this value. * @type {!goog.math.Coordinate} * @protected */ this.xy_ = new goog.math.Coordinate(0, 0); /** * The comment's height in workspace units. Scale does not change this value. * @type {number} * @private */ this.height_ = height; /** * The comment's width in workspace units. Scale does not change this value. * @type {number} * @private */ this.width_ = width; /** * The comment's minimized state. * @type{boolean} * @private */ this.isMinimized_ = minimized; /** * @type {!Blockly.Workspace} */ this.workspace = workspace; /** * @protected * @type {boolean} */ this.RTL = workspace.RTL; /** * @type {boolean} * @private */ this.deletable_ = true; /** * @type {boolean} * @private */ this.movable_ = true; /** * @protected * @type {!string} */ this.content_ = content; /** * @package * @type {boolean} */ this.isComment = true; Blockly.WorkspaceComment.fireCreateEvent(this); }; /** * Maximum lable length (actual label length will include * one additional character, the ellipsis). * @private */ Blockly.WorkspaceComment.MAX_LABEL_LENGTH = 12; /** * Maximum character length for comment text. * @private */ Blockly.WorkspaceComment.COMMENT_TEXT_LIMIT = 8000; /** * Dispose of this comment. * @package */ Blockly.WorkspaceComment.prototype.dispose = function () { if (!this.workspace) { // The comment has already been deleted. return; } if (Blockly.Events.isEnabled()) { Blockly.Events.fire(new Blockly.Events.CommentDelete(this)); } // Remove from the list of top comments and the comment database. this.workspace.removeTopComment(this); this.workspace = null; }; // Height, width, x, and y are all stored on even non-rendered comments, to // preserve state if you pass the contents through a headless workspace. /** * Get comment height. * @return {number} comment height. * @package */ Blockly.WorkspaceComment.prototype.getHeight = function () { return this.height_; }; /** * Set comment height. * @param {number} height comment height. * @package */ Blockly.WorkspaceComment.prototype.setHeight = function (height) { this.height_ = height; }; /** * Get comment width. * @return {number} comment width. * @package */ Blockly.WorkspaceComment.prototype.getWidth = function () { return this.width_; }; /** * Set comment width. * @param {number} width comment width. * @package */ Blockly.WorkspaceComment.prototype.setWidth = function (width) { this.width_ = width; }; /** * Get the height and width of this comment. * @return {{height: number, width: number}} The height and width of this comment; * these numbers do not change as the workspace scales. */ Blockly.WorkspaceComment.prototype.getHeightWidth = function () { return { height: this.height_, width: this.width_ }; }; /** * Get stored location. * @return {!goog.math.Coordinate} The comment's stored location. This is not * valid if the comment is currently being dragged. * @package */ Blockly.WorkspaceComment.prototype.getXY = function () { return this.xy_.clone(); }; /** * 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.WorkspaceComment.prototype.moveBy = function (dx, dy) { var event = new Blockly.Events.CommentMove(this); this.xy_.translate(dx, dy); event.recordNew(); Blockly.Events.fire(event); }; /** * Get whether this comment is deletable or not. * @return {boolean} True if deletable. * @package */ Blockly.WorkspaceComment.prototype.isDeletable = function () { return ( this.deletable_ && !(this.workspace && this.workspace.options.readOnly) ); }; /** * Set whether this comment is deletable or not. * @param {boolean} deletable True if deletable. * @package */ Blockly.WorkspaceComment.prototype.setDeletable = function (deletable) { this.deletable_ = deletable; }; /** * Get whether this comment is movable or not. * @return {boolean} True if movable. * @package */ Blockly.WorkspaceComment.prototype.isMovable = function () { return this.movable_ && !(this.workspace && this.workspace.options.readOnly); }; /** * Set whether this comment is movable or not. * @param {boolean} movable True if movable. * @package */ Blockly.WorkspaceComment.prototype.setMovable = function (movable) { this.movable_ = movable; }; /** * Returns this comment's text. * @return {string} Comment text. * @package */ Blockly.WorkspaceComment.prototype.getText = function () { return this.content_; }; /** * Set this comment's text content. * @param {string} text Comment text. * @package */ Blockly.WorkspaceComment.prototype.setText = function (text) { if (this.content_ != text) { Blockly.Events.fire( new Blockly.Events.CommentChange( this, { text: this.content_ }, { text: text } ) ); this.content_ = text; } }; /** * Check whether this comment is currently minimized. * @return {boolean} True if minimized * @package */ Blockly.WorkspaceComment.prototype.isMinimized = function () { return this.isMinimized_; }; /** * 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.WorkspaceComment.prototype.toXmlWithXY = function (opt_noId) { var element = this.toXml(opt_noId); element.setAttribute('x', Math.round(this.xy_.x)); element.setAttribute('y', Math.round(this.xy_.y)); element.setAttribute('h', this.height_); element.setAttribute('w', this.width_); return element; }; /** * Get the truncated text for this comment to display in the minimized * top bar. * @return {string} The truncated comment text * @package */ Blockly.WorkspaceComment.prototype.getLabelText = function () { if (this.content_.length > Blockly.WorkspaceComment.MAX_LABEL_LENGTH) { if (this.RTL) { return ( '\u2026' + this.content_.slice(0, Blockly.WorkspaceComment.MAX_LABEL_LENGTH) ); } return ( this.content_.slice(0, Blockly.WorkspaceComment.MAX_LABEL_LENGTH) + '\u2026' ); } else { return this.content_; } }; /** * Encode a comment subtree as XML, but don't serialize the XY coordinates or * width and height. If you need that additional information use toXmlWithXY. * @param {boolean=} opt_noId True if the encoder should skip the comment id. * @return {!Element} Tree of XML elements. * @package */ Blockly.WorkspaceComment.prototype.toXml = function (opt_noId) { var commentElement = goog.dom.createDom('comment'); if (!opt_noId) { commentElement.setAttribute('id', this.id); } if (this.isMinimized_) { commentElement.setAttribute('minimized', true); } commentElement.textContent = this.getText(); return commentElement; }; /** * Fire a create event for the given workspace comment, if comments are enabled. * @param {!Blockly.WorkspaceComment} comment The comment that was just created. * @package */ Blockly.WorkspaceComment.fireCreateEvent = function (comment) { if (Blockly.Events.isEnabled()) { var existingGroup = Blockly.Events.getGroup(); if (!existingGroup) { Blockly.Events.setGroup(true); } try { Blockly.Events.fire(new Blockly.Events.CommentCreate(comment)); } finally { if (!existingGroup) { Blockly.Events.setGroup(false); } } } }; /** * Decode an XML comment tag and create a comment on the workspace. * @param {!Element} xmlComment XML comment element. * @param {!Blockly.Workspace} workspace The workspace. * @return {!Blockly.WorkspaceComment} The created workspace comment. * @package */ Blockly.WorkspaceComment.fromXml = function (xmlComment, workspace) { var info = Blockly.WorkspaceComment.parseAttributes(xmlComment); var comment = new Blockly.WorkspaceComment( workspace, info.content, info.h, info.w, info.minimized, info.id ); if (!isNaN(info.x) && !isNaN(info.y)) { comment.moveBy(info.x, info.y); } Blockly.WorkspaceComment.fireCreateEvent(comment); return comment; }; /** * Decode an XML comment tag and return the results in an object. * @param {!Element} xml XML comment element. * @return {!Object} An object containing the information about the comment. * @package */ Blockly.WorkspaceComment.parseAttributes = function (xml) { var xmlH = xml.getAttribute('h'); var xmlW = xml.getAttribute('w'); return { /* @type {string} */ id: xml.getAttribute('id'), /** * The height of the comment in workspace units, or 100 if not specified. * @type {number} */ h: xmlH ? parseInt(xmlH, 10) : 100, /** * The width of the comment in workspace units, or 100 if not specified. * @type {number} */ w: xmlW ? parseInt(xmlW, 10) : 100, /** * The x position of the comment in workspace coordinates, or NaN if not * specified in the XML. * @type {number} */ x: parseInt(xml.getAttribute('x'), 10), /** * The y position of the comment in workspace coordinates, or NaN if not * specified in the XML. * @type {number} */ y: parseInt(xml.getAttribute('y'), 10), /** * Whether this comment is minimized. Defaults to false if not specified in * the XML. * @type {boolean} */ minimized: xml.getAttribute('minimized') == 'true' || false, /* @type {string} */ content: xml.textContent }; };