diff options
author | David Barksdale <amatus@amatus.name> | 2016-09-10 17:58:46 -0500 |
---|---|---|
committer | David Barksdale <amatus@amatus.name> | 2016-09-10 18:32:35 -0500 |
commit | 475f9f3ac7688e58505690d420cafe6ae8bb8b5f (patch) | |
tree | b1bf14b10751fe4e9e146ad7244ec86bb123893d /blockly/core/comment.js | |
parent | 923561056ddb63ce82fd1ec2a5e249bbdae267bf (diff) |
Merge blockly sub-tree
Diffstat (limited to 'blockly/core/comment.js')
-rw-r--r-- | blockly/core/comment.js | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/blockly/core/comment.js b/blockly/core/comment.js new file mode 100644 index 0000000..2121530 --- /dev/null +++ b/blockly/core/comment.js @@ -0,0 +1,278 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2011 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. + * @author fraser@google.com (Neil Fraser) + */ +'use strict'; + +goog.provide('Blockly.Comment'); + +goog.require('Blockly.Bubble'); +goog.require('Blockly.Icon'); +goog.require('goog.userAgent'); + + +/** + * Class for a comment. + * @param {!Blockly.Block} block The block associated with this comment. + * @extends {Blockly.Icon} + * @constructor + */ +Blockly.Comment = function(block) { + Blockly.Comment.superClass_.constructor.call(this, block); + this.createIcon(); +}; +goog.inherits(Blockly.Comment, Blockly.Icon); + +/** + * Comment text (if bubble is not visible). + * @private + */ +Blockly.Comment.prototype.text_ = ''; + +/** + * Width of bubble. + * @private + */ +Blockly.Comment.prototype.width_ = 160; + +/** + * Height of bubble. + * @private + */ +Blockly.Comment.prototype.height_ = 80; + +/** + * Draw the comment icon. + * @param {!Element} group The icon group. + * @private + */ +Blockly.Comment.prototype.drawIcon_ = function(group) { + // Circle. + Blockly.createSvgElement('circle', + {'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'}, + group); + // Can't use a real '?' text character since different browsers and operating + // systems render it differently. + // Body of question mark. + Blockly.createSvgElement('path', + {'class': 'blocklyIconSymbol', + 'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405 0.607,-5.534 -3.765,-3.874v1.7c3.12,-1.657 3.698,0.118 2.336,1.25 -1.201,0.998 -1.201,1.528 -1.204,2.19z'}, + group); + // Dot of question point. + Blockly.createSvgElement('rect', + {'class': 'blocklyIconSymbol', + 'x': '6.8', 'y': '10.78', 'height': '2', 'width': '2'}, + group); +}; + +/** + * Create the editor for the comment's bubble. + * @return {!Element} The top-level node of the editor. + * @private + */ +Blockly.Comment.prototype.createEditor_ = function() { + /* Create the editor. Here's the markup that will be generated: + <foreignObject x="8" y="8" width="164" height="164"> + <body xmlns="http://www.w3.org/1999/xhtml" class="blocklyMinimalBody"> + <textarea xmlns="http://www.w3.org/1999/xhtml" + class="blocklyCommentTextarea" + style="height: 164px; width: 164px;"></textarea> + </body> + </foreignObject> + */ + this.foreignObject_ = Blockly.createSvgElement('foreignObject', + {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, + null); + var body = document.createElementNS(Blockly.HTML_NS, 'body'); + body.setAttribute('xmlns', Blockly.HTML_NS); + body.className = 'blocklyMinimalBody'; + var textarea = document.createElementNS(Blockly.HTML_NS, 'textarea'); + textarea.className = 'blocklyCommentTextarea'; + textarea.setAttribute('dir', this.block_.RTL ? 'RTL' : 'LTR'); + body.appendChild(textarea); + this.textarea_ = textarea; + this.foreignObject_.appendChild(body); + Blockly.bindEvent_(textarea, 'mouseup', this, this.textareaFocus_); + // Don't zoom with mousewheel. + Blockly.bindEvent_(textarea, 'wheel', this, function(e) { + e.stopPropagation(); + }); + Blockly.bindEvent_(textarea, 'change', this, function(e) { + if (this.text_ != textarea.value) { + Blockly.Events.fire(new Blockly.Events.Change( + this.block_, 'comment', null, this.text_, textarea.value)); + this.text_ = textarea.value; + } + }); + setTimeout(function() { + textarea.focus(); + }, 0); + return this.foreignObject_; +}; + +/** + * Add or remove editability of the comment. + * @override + */ +Blockly.Comment.prototype.updateEditable = function() { + if (this.isVisible()) { + // Toggling visibility will force a rerendering. + this.setVisible(false); + this.setVisible(true); + } + // Allow the icon to update. + Blockly.Icon.prototype.updateEditable.call(this); +}; + +/** + * Callback function triggered when the bubble has resized. + * Resize the text area accordingly. + * @private + */ +Blockly.Comment.prototype.resizeBubble_ = function() { + if (this.isVisible()) { + var size = this.bubble_.getBubbleSize(); + var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; + this.foreignObject_.setAttribute('width', size.width - doubleBorderWidth); + this.foreignObject_.setAttribute('height', size.height - doubleBorderWidth); + this.textarea_.style.width = (size.width - doubleBorderWidth - 4) + 'px'; + this.textarea_.style.height = (size.height - doubleBorderWidth - 4) + 'px'; + } +}; + +/** + * Show or hide the comment bubble. + * @param {boolean} visible True if the bubble should be visible. + */ +Blockly.Comment.prototype.setVisible = function(visible) { + if (visible == this.isVisible()) { + // No change. + return; + } + Blockly.Events.fire( + new Blockly.Events.Ui(this.block_, 'commentOpen', !visible, visible)); + if ((!this.block_.isEditable() && !this.textarea_) || goog.userAgent.IE) { + // Steal the code from warnings to make an uneditable text bubble. + // MSIE does not support foreignobject; textareas are impossible. + // http://msdn.microsoft.com/en-us/library/hh834675%28v=vs.85%29.aspx + // Always treat comments in IE as uneditable. + Blockly.Warning.prototype.setVisible.call(this, visible); + return; + } + // Save the bubble stats before the visibility switch. + var text = this.getText(); + var size = this.getBubbleSize(); + if (visible) { + // Create the bubble. + this.bubble_ = new Blockly.Bubble( + /** @type {!Blockly.WorkspaceSvg} */ (this.block_.workspace), + this.createEditor_(), this.block_.svgPath_, + this.iconXY_, this.width_, this.height_); + this.bubble_.registerResizeEvent(this.resizeBubble_.bind(this)); + this.updateColour(); + } else { + // Dispose of the bubble. + this.bubble_.dispose(); + this.bubble_ = null; + this.textarea_ = null; + this.foreignObject_ = null; + } + // Restore the bubble stats after the visibility switch. + this.setText(text); + this.setBubbleSize(size.width, size.height); +}; + +/** + * Bring the comment to the top of the stack when clicked on. + * @param {!Event} e Mouse up event. + * @private + */ +Blockly.Comment.prototype.textareaFocus_ = function(e) { + // Ideally this would be hooked to the focus event for the comment. + // However doing so in Firefox swallows the cursor for unknown reasons. + // So this is hooked to mouseup instead. No big deal. + this.bubble_.promote_(); + // Since the act of moving this node within the DOM causes a loss of focus, + // we need to reapply the focus. + this.textarea_.focus(); +}; + +/** + * Get the dimensions of this comment's bubble. + * @return {!Object} Object with width and height properties. + */ +Blockly.Comment.prototype.getBubbleSize = function() { + if (this.isVisible()) { + return this.bubble_.getBubbleSize(); + } else { + return {width: this.width_, height: this.height_}; + } +}; + +/** + * Size this comment's bubble. + * @param {number} width Width of the bubble. + * @param {number} height Height of the bubble. + */ +Blockly.Comment.prototype.setBubbleSize = function(width, height) { + if (this.textarea_) { + this.bubble_.setBubbleSize(width, height); + } else { + this.width_ = width; + this.height_ = height; + } +}; + +/** + * Returns this comment's text. + * @return {string} Comment text. + */ +Blockly.Comment.prototype.getText = function() { + return this.textarea_ ? this.textarea_.value : this.text_; +}; + +/** + * Set this comment's text. + * @param {string} text Comment text. + */ +Blockly.Comment.prototype.setText = function(text) { + if (this.text_ != text) { + Blockly.Events.fire(new Blockly.Events.Change( + this.block_, 'comment', null, this.text_, text)); + this.text_ = text; + } + if (this.textarea_) { + this.textarea_.value = text; + } +}; + +/** + * Dispose of this comment. + */ +Blockly.Comment.prototype.dispose = function() { + if (Blockly.Events.isEnabled()) { + this.setText(''); // Fire event to delete comment. + } + this.block_.comment = null; + Blockly.Icon.prototype.dispose.call(this); +}; |