Beispiel #1
0
        /// <summary>
        /// Decode an XML block tag and create a block (and possibly sub blocks) on the
        /// workspace.
        /// </summary>
        /// <param name="xmlBlock">XML block element.</param>
        /// <param name="workspace">The workspace.</param>
        /// <returns>The root block created.</returns>
        public static Block domToBlock(Element xmlBlock, Workspace workspace)
        {
            BlockSvg topBlock;

            // Create top-level block.
            Events.disable();
            try {
                topBlock = Xml.domToBlockHeadless_(xmlBlock, workspace);
                if (workspace.rendered)
                {
                    // Hide connections to speed up assembly.
                    topBlock.setConnectionsHidden(true);
                    // Generate list of all blocks.
                    var blocks = topBlock.getDescendants();
                    // Render each block.
                    for (var i = blocks.Length - 1; i >= 0; i--)
                    {
                        ((BlockSvg)blocks[i]).initSvg();
                    }
                    for (var i = blocks.Length - 1; i >= 0; i--)
                    {
                        ((BlockSvg)blocks[i]).render(false);
                    }
                    // Populating the connection database may be defered until after the
                    // blocks have rendered.
                    Window.SetTimeout(() => {
                        if (topBlock.workspace != null)                            // Check that the block hasn't been deleted.
                        {
                            topBlock.setConnectionsHidden(false);
                        }
                    }, 1);
                    topBlock.updateDisabled();
                    // Allow the scrollbars to resize and move based on the new contents.
                    // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing.
                    ((WorkspaceSvg)workspace).resizeContents();
                }
            }
            finally {
                Events.enable();
            }
            if (Events.isEnabled())
            {
                Events.fire(new Events.Create(topBlock));
            }
            return(topBlock);
        }
Beispiel #2
0
        /// <summary>
        /// Decode an XML block tag and create a block (and possibly sub blocks) on the
        /// workspace.
        /// </summary>
        /// <param name="xmlBlock">XML block element.</param>
        /// <param name="workspace">The workspace.</param>
        /// <returns>The root block created.</returns>
        private static BlockSvg domToBlockHeadless_(Element xmlBlock, Workspace workspace)
        {
            BlockSvg block         = null;
            var      prototypeName = xmlBlock.GetAttribute("type");

            goog.asserts.assert(prototypeName != null, "Block type unspecified: %s",
                                xmlBlock.OuterHTML);
            var id = xmlBlock.GetAttribute("id");

            block = (BlockSvg)workspace.newBlock(prototypeName, id);

            BlockSvg blockChild = null;

            foreach (var xmlChild_ in xmlBlock.ChildNodes)
            {
                if (xmlChild_.NodeType == NodeType.Text)
                {
                    // Ignore any text at the <block> level.  It's all whitespace anyway.
                    continue;
                }
                Element xmlChild = (Element)xmlChild_;
                Input   input;

                // Find any enclosed blocks or shadows in this tag.
                Element childBlockNode  = null;
                Element childShadowNode = null;
                foreach (var grandchildNode in xmlChild.ChildNodes)
                {
                    if (grandchildNode.NodeType == NodeType.Element)
                    {
                        if (grandchildNode.NodeName.ToLowerCase() == "block")
                        {
                            childBlockNode = (Element)grandchildNode;
                        }
                        else if (grandchildNode.NodeName.ToLowerCase() == "shadow")
                        {
                            childShadowNode = (Element)grandchildNode;
                        }
                    }
                }
                // Use the shadow block if there is no child block.
                if (childBlockNode == null && childShadowNode != null)
                {
                    childBlockNode = childShadowNode;
                }

                var name = xmlChild.GetAttribute("name");
                switch (xmlChild.NodeName.ToLowerCase())
                {
                case "mutation":
                    // Custom data for an advanced block.
                    if (true /*block.domToMutation*/)
                    {
                        block.domToMutation(xmlChild);
                        if (true /*block.initSvg*/)
                        {
                            // Mutation may have added some elements that need initalizing.
                            block.initSvg();
                        }
                    }
                    break;

                case "comment":
                    block.setCommentText(xmlChild.TextContent);
                    var visible = xmlChild.GetAttribute("pinned");
                    if (visible != null && !block.isInFlyout)
                    {
                        // Give the renderer a millisecond to render and position the block
                        // before positioning the comment bubble.
                        Window.SetTimeout(() => {
                            if (block.comment != null /*&& block.comment.setVisible*/)
                            {
                                block.comment.setVisible(visible == "true");
                            }
                        }, 1);
                    }
                    var bubbleW = Script.ParseFloat(xmlChild.GetAttribute("w") ?? "0.0");
                    var bubbleH = Script.ParseFloat(xmlChild.GetAttribute("h") ?? "0.0");
                    if (!Double.IsNaN(bubbleW) && !Double.IsNaN(bubbleH) &&
                        block.comment != null /*&& block.comment.setVisible*/)
                    {
                        block.comment.setBubbleSize(bubbleW, bubbleH);
                    }
                    break;

                case "data":
                    block.data = xmlChild.TextContent;
                    break;

                case "title":
                // Titles were renamed to field in December 2013.
                // Fall through.
                case "field":
                    var field = block.getField(name);
                    if (field == null)
                    {
                        Console.WriteLine("Ignoring non-existent field " + name + " in block " +
                                          prototypeName);
                        break;
                    }
                    field.setValue(xmlChild.TextContent);
                    break;

                case "value":
                case "statement":
                    input = block.getInput(name);
                    if (input == null)
                    {
                        Console.WriteLine("Ignoring non-existent input " + name + " in block " +
                                          prototypeName);
                        break;
                    }
                    if (childShadowNode != null)
                    {
                        input.connection.setShadowDom(childShadowNode);
                    }
                    if (childBlockNode != null)
                    {
                        blockChild = Xml.domToBlockHeadless_(childBlockNode,
                                                             workspace);
                        if (blockChild.outputConnection != null)
                        {
                            input.connection.connect(blockChild.outputConnection);
                        }
                        else if (blockChild.previousConnection != null)
                        {
                            input.connection.connect(blockChild.previousConnection);
                        }
                        else
                        {
                            goog.asserts.fail(
                                "Child block does not have output or previous statement.");
                        }
                    }
                    break;

                case "next":
                    if (childShadowNode != null && block.nextConnection != null)
                    {
                        block.nextConnection.setShadowDom(childShadowNode);
                    }
                    if (childBlockNode != null)
                    {
                        goog.asserts.assert(block.nextConnection != null,
                                            "Next statement does not exist.");
                        // If there is more than one XML "next" tag.
                        goog.asserts.assert(!block.nextConnection.isConnected(),
                                            "Next statement is already connected.");
                        blockChild = Xml.domToBlockHeadless_(childBlockNode,
                                                             workspace);
                        goog.asserts.assert(blockChild.previousConnection != null,
                                            "Next block does not have previous statement.");
                        block.nextConnection.connect(blockChild.previousConnection);
                    }
                    break;

                default:
                    // Unknown tag; ignore.  Same principle as HTML parsers.
                    Console.WriteLine("Ignoring unknown tag: " + xmlChild.NodeName);
                    break;
                }
            }

            var inline = xmlBlock.GetAttribute("inline");

            if (inline != null)
            {
                block.setInputsInline(inline == "true");
            }
            var disabled = xmlBlock.GetAttribute("disabled");

            if (disabled != null)
            {
                block.setDisabled(disabled == "true");
            }
            var deletable = xmlBlock.GetAttribute("deletable");

            if (deletable != null)
            {
                block.setDeletable(deletable == "true");
            }
            var movable = xmlBlock.GetAttribute("movable");

            if (movable != null)
            {
                block.setMovable(movable == "true");
            }
            var editable = xmlBlock.GetAttribute("editable");

            if (editable != null)
            {
                block.setEditable(editable == "true");
            }
            var collapsed = xmlBlock.GetAttribute("collapsed");

            if (collapsed != null)
            {
                block.setCollapsed(collapsed == "true");
            }
            if (xmlBlock.NodeName.ToLowerCase() == "shadow")
            {
                // Ensure all children are also shadows.
                var children = block.getChildren();
                foreach (var child in children)
                {
                    goog.asserts.assert(child.isShadow(),
                                        "Shadow block not allowed non-shadow child.");
                }
                block.setShadow(true);
            }
            return(block);
        }