/** * Called whenever anything on the workspace changes. * Prevent mismatched types. * @param {!Abstract} e Change event. * @this Blockly.Block */ protected override void onchange(Events.Abstract e) { var blockA = this.getInputTargetBlock("THEN"); var blockB = this.getInputTargetBlock("ELSE"); var parentConnection = this.outputConnection.targetConnection; // Disconnect blocks that existed prior to this change if they don't match. if ((blockA != null || blockB != null) && parentConnection != null) { for (var i = 0; i < 2; i++) { var block = (i == 1) ? blockA : blockB; if (block != null && !block.outputConnection.checkType_(parentConnection)) { // Ensure that any disconnections are grouped with the causing event. Events.setGroup(e.group); if (parentConnection == this.prevParentConnection_) { this.unplug(); parentConnection.getSourceBlock().bumpNeighbours_(); } else { block.unplug(); block.bumpNeighbours_(); } Events.setGroup(false); } } } this.prevParentConnection_ = parentConnection; }
/// <summary> /// Resize the editor and the underlying block to fit the text. /// </summary> protected void resizeEditor_(Events.Abstract e = null) { var div = WidgetDiv.DIV; var bBox = this.fieldGroup_.getBBox(); div.Style.Width = bBox.width * this.workspace_.scale + "px"; div.Style.Height = bBox.height * this.workspace_.scale + "px"; var xy = this.getAbsoluteXY_(); // In RTL mode block fields and LTR input fields the left edge moves, // whereas the right edge is fixed. Reposition the editor. if (this.sourceBlock_.RTL) { var borderBBox = this.getScaledBBox_(); xy.x += borderBBox.width; xy.x -= div.OffsetWidth; } // Shift by a few pixels to line up exactly. xy.y += 1; if (goog.userAgent.GECKO && WidgetDiv.DIV.Style.Top != null) { // Firefox mis-reports the location of the border by a pixel // once the WidgetDiv is moved into position. xy.x -= 1; xy.y -= 1; } if (goog.userAgent.WEBKIT) { xy.y -= 3; } div.Style.Left = xy.x + "px"; div.Style.Top = xy.y + "px"; }
/// <summary> /// Enable/disable a block depending on whether it is properly connected. /// Use this on applications where all blocks should be connected to a top block. /// Recommend setting the 'disable' option to 'false' in the config so that /// users don't try to reenable disabled orphan blocks. /// </summary> /// <param name="ev">Custom data for event.</param> public static void disableOrphans(Events.Abstract ev) { if (ev.type == Events.MOVE || ev.type == Events.CREATE) { Events.disable(); var workspace = Workspace.getById(ev.workspaceId); var block = workspace.getBlockById(ev.blockId); if (block != null) { if (block.getParent() != null && !block.getParent().disabled) { var children = block.getDescendants(); foreach (var child in children) { child.setDisabled(false); } } else if ((block.outputConnection != null || block.previousConnection != null) && Core.dragMode_ == Core.DRAG_NONE) { do { block.setDisabled(true); block = block.getNextBlock(); } while (block != null); } } Events.enable(); } }
/** * Called whenever anything on the workspace changes. * Prevent mismatched types from being compared. * @param {!Abstract} e Change event. * @this Blockly.Block */ protected override void onchange(Events.Abstract e) { var blockA = this.getInputTargetBlock("A"); var blockB = this.getInputTargetBlock("B"); // Disconnect blocks that existed prior to this change if they don't match. if (blockA != null && blockB != null && !blockA.outputConnection.checkType_(blockB.outputConnection)) { // Mismatch between two inputs. Disconnect previous and bump it away. // Ensure that any disconnections are grouped with the causing event. Events.setGroup(e.group); for (var i = 0; i < this.prevBlocks_.Length; i++) { var block = this.prevBlocks_[i]; if (block == blockA || block == blockB) { block.unplug(); block.bumpNeighbours_(); } } Events.setGroup(false); } this.prevBlocks_[0] = blockA; this.prevBlocks_[1] = blockB; }
/// <summary> /// Create a custom event and fire it. /// </summary> /// <param name="ev">Custom data for event.</param> public static void fire(Events.Abstract ev) { if (!Events.isEnabled()) { return; } if (Events.FIRE_QUEUE_.Length == 0) { // First event added; schedule a firing of the event queue. Window.SetTimeout(Events.fireNow_, 0); } Events.FIRE_QUEUE_.Push(ev); }
/** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. * @param {!Abstract} e Change event. * @this Blockly.Block */ protected override void onchange(Events.Abstract e) { if (((WorkspaceSvg)this.workspace).isDragging()) { return; // Don't change state at the start of a drag. } var legal = false; // Is the block nested in a procedure? var block = (Block)this; do { if (Array.IndexOf(this.FUNCTION_TYPES, block.type) != -1) { legal = true; break; } block = block.getSurroundParent(); } while (block != null); if (legal) { // If needed, toggle whether this block has a return value. if (block.type == ProceduresDefnoreturnBlock.type_name && this.hasReturnValue_) { this.removeInput("VALUE"); this.appendDummyInput("VALUE") .appendField(Msg.PROCEDURES_DEFRETURN_RETURN); this.hasReturnValue_ = false; } else if (block.type == ProceduresDefreturnBlock.type_name && !this.hasReturnValue_) { this.removeInput("VALUE"); this.appendValueInput("VALUE") .appendField(Msg.PROCEDURES_DEFRETURN_RETURN); this.hasReturnValue_ = true; } this.setWarningText(null); if (!this.isInFlyout) { this.setDisabled(false); } } else { this.setWarningText(Msg.PROCEDURES_IFRETURN_WARNING); if (!this.isInFlyout && !this.getInheritedDisabled()) { this.setDisabled(true); } } }
/// <summary> /// Fire a change ev. /// </summary> /// <param name="ev">Event to fire.</param> public void fireChangeListener(Events.Abstract ev) { if (ev.recordUndo) { this.undoStack_.Push(ev); this.redoStack_.Clear(); while (this.undoStack_.Length > this.MAX_UNDO) { this.undoStack_.Shift(); } } for (var i = 0; i < this.listeners_.Length; i++) { this.listeners_[i](ev); } }
/** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. * @param {!Abstract} e Change event. * @this Blockly.Block */ protected override void onchange(Events.Abstract e) { if (((WorkspaceSvg)this.workspace).isDragging()) { return; // Don't change state at the start of a drag. } var legal = false; // Is the block nested in a loop? var block = (Block)this; do { if (Array.IndexOf(this.LOOP_TYPES, block.type) != -1) { legal = true; break; } block = block.getSurroundParent(); } while (block != null); if (legal) { this.setWarningText(null); if (!this.isInFlyout) { this.setDisabled(false); } } else { this.setWarningText(Msg.CONTROLS_FLOW_STATEMENTS_WARNING); if (!this.isInFlyout && !this.getInheritedDisabled()) { this.setDisabled(true); } } }
/** * Procedure calls cannot exist without the corresponding procedure * definition. Enforce this link whenever an event is fired. * @this Blockly.Block */ protected override void onchange(Events.Abstract e) { if (this.workspace == null || this.workspace.isFlyout) { // Block is deleted or is in a flyout. return; } if (e.type == Events.CREATE && Array.IndexOf(((Events.Create)e).ids, this.id) != -1) { // Look for the case where a procedure call was created (usually through // paste) and there is no matching definition. In this case, create // an empty definition block with the correct signature. var name = this.getProcedureCall(); var def = Core.Procedures.getDefinition(name, this.workspace); if (def != null && (def.type != this.defType_ || JSON.Stringify(def.arguments_.ToArray()) != JSON.Stringify(this.arguments_))) { // The signatures don't match. def = null; } if (def == null) { Events.setGroup(e.group); /** * Create matching definition block. * <xml> * <block type="procedures_defreturn" x="10" y="20"> * <mutation name="test"> * <arg name="x"></arg> * </mutation> * <field name="NAME">test</field> * </block> * </xml> */ var xml = goog.dom.createDom("xml"); var block = goog.dom.createDom("block"); block.SetAttribute("type", this.defType_); var xy = this.getRelativeToSurfaceXY(); var x = xy.x + Core.SNAP_RADIUS * (this.RTL ? -1 : 1); var y = xy.y + Core.SNAP_RADIUS * 2; block.SetAttribute("x", x.ToString()); block.SetAttribute("y", y.ToString()); var mutation = this.mutationToDom(); block.AppendChild(mutation); var field = goog.dom.createDom("field"); field.SetAttribute("name", "NAME"); field.AppendChild(Document.CreateTextNode(this.getProcedureCall())); block.AppendChild(field); xml.AppendChild(block); Xml.domToWorkspace(xml, this.workspace); Events.setGroup(false); } } else if (e.type == Events.DELETE) { // Look for the case where a procedure definition has been deleted, // leaving this block (a procedure call) orphaned. In this case, delete // the orphan. var name = this.getProcedureCall(); var def = Core.Procedures.getDefinition(name, this.workspace); if (def == null) { Events.setGroup(e.group); this.dispose(true, false); Events.setGroup(false); } } }