예제 #1
0
        /// <summary>
        /// Converts a DOM structure into properly indented text.
        /// </summary>
        /// <param name="dom">A tree of XML elements.</param>
        /// <returns>Text representation.</returns>
        public static string domToPrettyText(Element dom)
        {
            // This function is not guaranteed to be correct for all XML.
            // But it handles the XML that Blockly generates.
            var blob = Xml.domToText(dom);
            // Place every open and close tag on its own line.
            var lines = blob.Split("<");
            // Indent every line.
            var indent = "";

            for (var i = 1; i < lines.Length; i++)
            {
                var line = lines[i];
                if (line[0] == '/')
                {
                    indent = indent.Substring(2);
                }
                lines[i] = indent + "<" + line;
                if (line[0] != '/' && line.Slice(-2) != "/>")
                {
                    indent += "  ";
                }
            }
            // Pull simple tags back together.
            // E.g. <foo></foo>
            var text = lines.Join("\n");

            text = text.Replace(new Regex(@"(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>", RegexOptions.Multiline), "$1</$2>");
            // Trim leading blank line.
            return(text.Replace(new Regex(@"^\n"), ""));
        }
예제 #2
0
        /// <summary>
        /// When a procedure definition changes its parameters, find and edit all its
        /// callers.
        /// </summary>
        /// <param name="defBlock">Procedure definition block.</param>
        public void mutateCallers(ProceduresDefBlock defBlock)
        {
            var oldRecordUndo = Events.recordUndo;
            var name          = defBlock.getProcedureDef().Item1;
            var xmlElement    = defBlock.mutationToDom(true);
            var callers       = getCallers(name, defBlock.workspace);

            foreach (var caller in callers)
            {
                var oldMutationDom = caller.mutationToDom();
                var oldMutation    = oldMutationDom != null?Xml.domToText(oldMutationDom) : null;

                caller.domToMutation(xmlElement);
                var newMutationDom = caller.mutationToDom();
                var newMutation    = newMutationDom != null?Xml.domToText(newMutationDom) : null;

                if (oldMutation != newMutation)
                {
                    // Fire a mutation on every caller block.  But don't record this as an
                    // undo action since it is deterministically tied to the procedure's
                    // definition mutation.
                    Events.recordUndo = false;
                    Events.fire(new Events.Change(
                                    caller, "mutation", null, oldMutation, newMutation));
                    Events.recordUndo = oldRecordUndo;
                }
            }
        }
예제 #3
0
            /// <summary>
            /// Encode the event as JSON.
            /// </summary>
            /// <returns>JSON representation.</returns>
            public override EventJsonData toJson()
            {
                var json = base.toJson();

                json.xml = Xml.domToText(this.xml);
                json.ids = this.ids;
                return(json);
            }
예제 #4
0
        /// <summary>
        /// Update the source block when the mutator's blocks are changed.
        /// Bump down any block that's too high.
        /// Fired whenever a change is made to the mutator's workspace.
        /// </summary>
        private void workspaceChanged_()
        {
            if (this.workspace_ == null)
            {
                return;
            }

            if (Core.dragMode_ == Core.DRAG_NONE)
            {
                var blocks = this.workspace_.getTopBlocks(false);
                var MARGIN = 20;
                foreach (BlockSvg block in blocks)
                {
                    var blockXY = block.getRelativeToSurfaceXY();
                    var blockHW = block.getHeightWidth();
                    if (blockXY.y + blockHW.height < MARGIN)
                    {
                        // Bump any block that's above the top back inside.
                        block.moveBy(0, MARGIN - blockHW.height - blockXY.y);
                    }
                }
            }

            // When the mutator's workspace changes, update the source block.
            if (this.rootBlock_.workspace == this.workspace_)
            {
                Events.setGroup(true);
                var block          = this.block_;
                var oldMutationDom = block.mutationToDom();
                var oldMutation    = oldMutationDom != null && Xml.domToText(oldMutationDom) != null;
                // Switch off rendering while the source block is rebuilt.
                var savedRendered = block.rendered;
                block.rendered = false;
                // Allow the source block to rebuild itself.
                block.compose(this.rootBlock_);
                // Restore rendering and show the changes.
                block.rendered = savedRendered;
                // Mutation may have added some elements that need initalizing.
                block.initSvg();
                var newMutationDom = block.mutationToDom();
                var newMutation    = newMutationDom != null && Xml.domToText(newMutationDom) != null;
                if (oldMutation != newMutation)
                {
                    Events.fire(new Events.Change(
                                    block, "mutation", null, oldMutation.ToString(), newMutation.ToString()));
                    // Ensure that any bump is part of this mutation's event group.
                    var group = Events.getGroup();
                    Window.SetTimeout(() => {
                        Events.setGroup(group);
                        block.bumpNeighbours_();
                        Events.setGroup(false);
                    }, Core.BUMP_DELAY);
                }
                if (block.rendered)
                {
                    block.render();
                }
                this.resizeBubble_();
                Events.setGroup(false);
            }
        }
예제 #5
0
            /// <summary>
            /// Run a change event.
            /// </summary>
            /// <param name="forward">True if run forward, false if run backward (undo).</param>
            public override void run(bool forward)
            {
                var workspace = Workspace.getById(this.workspaceId);
                var block     = (BlockSvg)workspace.getBlockById(this.blockId);

                if (block == null)
                {
                    Console.WriteLine("Can't change non-existant block: " + this.blockId);
                    return;
                }
                if (block.mutator != null)
                {
                    // Close the mutator (if open) since we don't want to update it.
                    block.mutator.setVisible(false);
                }
                var value = forward ? this.newValue : this.oldValue;

                switch (this.element)
                {
                case "field":
                    var field = block.getField(this.name);
                    if (field != null)
                    {
                        // Run the validator for any side-effects it may have.
                        // The validator's opinion on validity is ignored.
                        field.callValidator(value);
                        field.setValue(value);
                    }
                    else
                    {
                        Console.WriteLine("Can't set non-existant field: " + this.name);
                    }
                    break;

                case "comment":
                    block.setCommentText(value);
                    break;

                case "collapsed":
                    block.setCollapsed(value == "true");
                    break;

                case "disabled":
                    block.setDisabled(value == "true");
                    break;

                case "inline":
                    block.setInputsInline(value == "true");
                    break;

                case "mutation":
                    var oldMutation = "";
                    if (true /*block.mutationToDom*/)
                    {
                        var oldMutationDom = block.mutationToDom();
                        oldMutation = oldMutationDom != null?oldMutationDom.ToString() : Xml.domToText(oldMutationDom);
                    }
                    if (true /*block.domToMutation*/)
                    {
                        value = value != null ? value : "<mutation></mutation>";
                        var dom = Xml.textToDom("<xml>" + value + "</xml>");
                        block.domToMutation((Element)dom.FirstChild);
                    }
                    Events.fire(new Events.Change(
                                    block, "mutation", null, oldMutation, value));
                    break;

                default:
                    Console.WriteLine("Unknown change type: " + this.element);
                    break;
                }
            }