/// <summary> /// Decode the JSON into an event. /// </summary> /// <param name="json">JSON representation.</param> /// <param name="workspace">Target workspace for event.</param> /// <returns>The event represented by the JSON.</returns> public static Events.Abstract fromJson(EventJsonData json, Workspace workspace) { Events.Abstract ev; switch (json.type.ToString()) { case Events.CREATE: ev = new Events.Create(null); break; case Events.DELETE: ev = new Events.Delete(null); break; case Events.CHANGE: ev = new Events.Change(null, null, null, null, null); break; case Events.MOVE: ev = new Events.Move(null); break; case Events.UI: ev = new Events.Ui(null, null, null, null); break; default: throw new Exception("Unknown ev type."); } ev.fromJson(json); ev.workspaceId = workspace.id; return(ev); }
/// <summary> /// Disconnect two blocks that are connected by this connection. /// </summary> /// <param name="parentBlock">The superior block.</param> /// <param name="childBlock">The inferior block.</param> protected virtual void disconnectInternal_(Block parentBlock, Block childBlock) { Events.Move e = null; if (Events.isEnabled()) { e = new Events.Move(childBlock); } var otherConnection = this.targetConnection; otherConnection.targetConnection = null; this.targetConnection = null; childBlock.setParent(null); if (e != null) { e.recordNew(); Events.fire(e); } }
/// <summary> /// Connect two connections together. This is the connection on the superior /// block. /// </summary> /// <param name="childConnection"></param> protected virtual void connect_(Connection childConnection) { var parentConnection = this; var parentBlock = parentConnection.getSourceBlock(); var childBlock = childConnection.getSourceBlock(); // Disconnect any existing parent on the child connection. if (childConnection.isConnected()) { childConnection.disconnect(); } if (parentConnection.isConnected()) { // Other connection is already connected to something. // Disconnect it and reattach it or bump it as needed. var orphanBlock = parentConnection.targetBlock(); var shadowDom = parentConnection.getShadowDom(); // Temporarily set the shadow DOM to null so it does not respawn. parentConnection.setShadowDom(null); // Displaced shadow blocks dissolve rather than reattaching or bumping. if (orphanBlock.isShadow()) { // Save the shadow block so that field values are preserved. shadowDom = Xml.blockToDom(orphanBlock); orphanBlock.dispose(); orphanBlock = null; } else if (parentConnection.type == Core.INPUT_VALUE) { // Value connections. // If female block is already connected, disconnect and bump the male. if (orphanBlock.outputConnection == null) { throw new Exception("Orphan block does not have an output connection."); } // Attempt to reattach the orphan at the end of the newly inserted // block. Since this block may be a row, walk down to the end // or to the first (and only) shadow block. var connection = Connection.lastConnectionInRow_( childBlock, orphanBlock); if (connection != null) { orphanBlock.outputConnection.connect(connection); orphanBlock = null; } } else if (parentConnection.type == Core.NEXT_STATEMENT) { // Statement connections. // Statement blocks may be inserted into the middle of a stack. // Split the stack. if (orphanBlock.previousConnection == null) { throw new Exception("Orphan block does not have a previous connection."); } // Attempt to reattach the orphan at the bottom of the newly inserted // block. Since this block may be a stack, walk down to the end. var newBlock = childBlock; while (newBlock.nextConnection != null) { var nextBlock = newBlock.getNextBlock(); if (nextBlock != null && !nextBlock.isShadow()) { newBlock = nextBlock; } else { if (orphanBlock.previousConnection.checkType_( newBlock.nextConnection)) { newBlock.nextConnection.connect(orphanBlock.previousConnection); orphanBlock = null; } break; } } } if (orphanBlock != null) { // Unable to reattach orphan. parentConnection.disconnect(); if (Events.recordUndo) { // Bump it off to the side after a moment. var group = Events.getGroup(); Window.SetTimeout(() => { // Verify orphan hasn't been deleted or reconnected (user on meth). if (orphanBlock.workspace != null && orphanBlock.getParent() == null) { Events.setGroup(group); if (orphanBlock.outputConnection != null) { ((RenderedConnection)orphanBlock.outputConnection).bumpAwayFrom_(parentConnection); } else if (orphanBlock.previousConnection != null) { ((RenderedConnection)orphanBlock.previousConnection).bumpAwayFrom_(parentConnection); } Events.setGroup(false); } }, Core.BUMP_DELAY); } } // Restore the shadow DOM. parentConnection.setShadowDom(shadowDom); } Events.Move e = null; if (Events.isEnabled()) { e = new Events.Move(childBlock); } // Establish the connections. Connection.connectReciprocally_(parentConnection, childConnection); // Demote the inferior block so that one is a child of the superior one. childBlock.setParent(parentBlock); if (e != null) { e.recordNew(); Events.fire(e); } }