Example #1
0
        /// <summary>
        /// Add event listeners for workspace factory.
        /// </summary>
        /// <param name="controller"> The controller for the workspace
        /// factory tab.</param>
        private static void addWorkspaceFactoryEventListeners_(WorkspaceFactoryController controller)
        {
            // Use up and down arrow keys to move categories.
            Window.AddEventListener("keydown", new Action <Event>((e) => {
                // Don't let arrow keys have any effect if not in Workspace Factory
                // editing the toolbox.
                if (!(controller.keyEventsEnabled && controller.selectedMode
                      == WorkspaceFactoryController.MODE_TOOLBOX))
                {
                    return;
                }

                if (e.KeyCode == 38)
                {
                    // Arrow up.
                    controller.moveElement(-1);
                }
                else if (e.KeyCode == 40)
                {
                    // Arrow down.
                    controller.moveElement(1);
                }
            }));

            // Determines if a block breaks shadow block placement rules.
            // Breaks rules if (1) a shadow block no longer has a valid
            // parent, or (2) a normal block is inside of a shadow block.
            var isInvalidBlockPlacement = new Func <Blockly.Block, bool>((block) => {
                return((controller.isUserGenShadowBlock(block.id) &&
                        block.getSurroundParent() == null) ||
                       (!controller.isUserGenShadowBlock(block.id) && block.getSurroundParent() != null &&
                        controller.isUserGenShadowBlock(block.getSurroundParent().id)));
            });

            // Add change listeners for toolbox workspace in workspace factory.
            controller.toolboxWorkspace.addChangeListener((e) => {
                // Listen for Blockly move and delete events to update preview.
                // Not listening for Blockly create events because causes the user to drop
                // blocks when dragging them into workspace. Could cause problems if ever
                // load blocks into workspace directly without calling updatePreview.
                if (e.type == Blockly.Events.MOVE || e.type == Blockly.Events.DELETE ||
                    e.type == Blockly.Events.CHANGE)
                {
                    controller.saveStateFromWorkspace();
                    controller.updatePreview();
                }

                // Listen for Blockly UI events to correctly enable the "Edit Block" button.
                // Only enable "Edit Block" when a block is selected and it has a
                // surrounding parent, meaning it is nested in another block (blocks that
                // are not nested in parents cannot be shadow blocks).
                if (e.type == Blockly.Events.MOVE || (e.type == Blockly.Events.UI &&
                                                      ((Blockly.Events.Ui)e).element == "selected"))
                {
                    var selected = Blockly.Core.selected;

                    // Show shadow button if a block is selected. Show "Add Shadow" if
                    // a block is not a shadow block, show "Remove Shadow" if it is a
                    // shadow block.
                    if (selected != null)
                    {
                        var isShadow = controller.isUserGenShadowBlock(selected.id);
                        WorkspaceFactoryInit.displayAddShadow_(!isShadow);
                        WorkspaceFactoryInit.displayRemoveShadow_(isShadow);
                    }
                    else
                    {
                        WorkspaceFactoryInit.displayAddShadow_(false);
                        WorkspaceFactoryInit.displayRemoveShadow_(false);
                    }

                    if (selected != null && selected.getSurroundParent() != null &&
                        !controller.isUserGenShadowBlock(selected.getSurroundParent().id))
                    {
                        // Selected block is a valid shadow block or could be a valid shadow
                        // block.

                        // Enable block editing and remove warnings if the block is not a
                        // variable user-generated shadow block.
                        ((HTMLButtonElement)Document.GetElementById("button_addShadow")).Disabled    = false;
                        ((HTMLButtonElement)Document.GetElementById("button_removeShadow")).Disabled = false;

                        if (!FactoryUtils.hasVariableField(selected) &&
                            controller.isDefinedBlock(selected))
                        {
                            selected.setWarningText(null);
                        }
                    }
                    else
                    {
                        // Selected block cannot be a valid shadow block.

                        if (selected != null && isInvalidBlockPlacement(selected))
                        {
                            // Selected block breaks shadow block rules.
                            // Invalid shadow block if (1) a shadow block no longer has a valid
                            // parent, or (2) a normal block is inside of a shadow block.

                            if (!controller.isUserGenShadowBlock(selected.id))
                            {
                                // Warn if a non-shadow block is nested inside a shadow block.
                                selected.setWarningText("Only shadow blocks can be nested inside\n"
                                                        + "other shadow blocks.");
                            }
                            else if (!FactoryUtils.hasVariableField(selected))
                            {
                                // Warn if a shadow block is invalid only if not replacing
                                // warning for variables.
                                selected.setWarningText("Shadow blocks must be nested inside other"
                                                        + " blocks.");
                            }

                            // Give editing options so that the user can make an invalid shadow
                            // block a normal block.
                            ((HTMLButtonElement)Document.GetElementById("button_removeShadow")).Disabled = false;
                            ((HTMLButtonElement)Document.GetElementById("button_addShadow")).Disabled    = true;
                        }
                        else
                        {
                            // Selected block does not break any shadow block rules, but cannot
                            // be a shadow block.

                            // Remove possible "invalid shadow block placement" warning.
                            if (selected != null && controller.isDefinedBlock(selected) &&
                                (!FactoryUtils.hasVariableField(selected) ||
                                 !controller.isUserGenShadowBlock(selected.id)))
                            {
                                selected.setWarningText(null);
                            }

                            // No block selected that is a shadow block or could be a valid shadow
                            // block. Disable block editing.
                            ((HTMLButtonElement)Document.GetElementById("button_addShadow")).Disabled    = true;
                            ((HTMLButtonElement)Document.GetElementById("button_removeShadow")).Disabled = true;
                        }
                    }
                }

                // Convert actual shadow blocks added from the toolbox to user-generated
                // shadow blocks.
                if (e.type == Blockly.Events.CREATE)
                {
                    controller.convertShadowBlocks();

                    // Let the user create a Variables or Functions category if they use
                    // blocks from either category.

                    // Get all children of a block and add them to childList.
                    Action <Blockly.Block, JsArray <Blockly.Block> > getAllChildren = null;
                    getAllChildren = new Action <Blockly.Block, JsArray <Blockly.Block> >((block, childList) => {
                        childList.Push(block);
                        var children = block.getChildren();
                        for (var i = 0; i < children.Length; i++)
                        {
                            var child = children[i];
                            getAllChildren(child, childList);
                        }
                    });

                    var newBaseBlock = controller.toolboxWorkspace.getBlockById(e.blockId);
                    var allNewBlocks = new JsArray <Blockly.Block>();
                    getAllChildren(newBaseBlock, allNewBlocks);
                    var variableCreated  = false;
                    var procedureCreated = false;

                    // Check if the newly created block or any of its children are variable
                    // or procedure blocks.
                    for (var i = 0; i < allNewBlocks.Length; i++)
                    {
                        var block = allNewBlocks[i];
                        if (FactoryUtils.hasVariableField(block))
                        {
                            variableCreated = true;
                        }
                        else if (FactoryUtils.isProcedureBlock(block))
                        {
                            procedureCreated = true;
                        }
                    }

                    // If any of the newly created blocks are variable or procedure blocks,
                    // prompt the user to create the corresponding standard category.
                    if (variableCreated && !controller.hasVariablesCategory())
                    {
                        if (Window.Confirm("Your new block has a variables field. To use this block "
                                           + "fully, you will need a Variables category. Do you want to add "
                                           + "a Variables category to your custom toolbox?"))
                        {
                            controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX);
                            controller.loadCategoryByName("variables");
                        }
                    }

                    if (procedureCreated && !controller.hasProceduresCategory())
                    {
                        if (Window.Confirm("Your new block is a function block. To use this block "
                                           + "fully, you will need a Functions category. Do you want to add "
                                           + "a Functions category to your custom toolbox?"))
                        {
                            controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX);
                            controller.loadCategoryByName("functions");
                        }
                    }
                }
            });
        }
Example #2
0
        /// <summary>
        /// Initialize Blockly and layout.  Called on page load.
        /// </summary>
        public void init()
        {
            // Block Factory has a dependency on bits of Closure that core Blockly
            // doesn't have. When you run this from file:// without a copy of Closure,
            // it breaks it non-obvious ways.  Warning about this for now until the
            // dependency is broken.
            // TODO: #668.
            if (!goog.dom.xml.isNotDefined())
            {
                Window.Alert("Sorry: Closure dependency not found. We are working on removing " +
                             "this dependency.  In the meantime, you can use our hosted demo\n " +
                             "https://blockly-demo.appspot.com/static/demos/blockfactory/index.html" +
                             "\nor use these instructions to continue running locally:\n" +
                             "https://developers.google.com/blockly/guides/modify/web/closure");
                return;
            }

            var self = this;

            // Handle Blockly Storage with App Engine.
            if (BlocklyStorage.InWindow())
            {
                this.initializeBlocklyStorage();
            }

            // Assign click handlers.
            this.assignExporterClickHandlers();
            this.assignLibraryClickHandlers();
            this.assignBlockFactoryClickHandlers();
            // Hide and show the block library dropdown.
            Document.GetElementById("modalShadow").AddEventListener("click",
                                                                    new Action(() => {
                self.closeModal();
            }));

            this.onresize(null);
            Window.AddEventListener("resize", new Action(() => {
                self.onresize(null);
            }));

            // Inject Block Factory Main Workspace.
            var toolbox = Document.GetElementById("blockfactory_toolbox");

            BlockFactory.mainWorkspace = Blockly.Core.inject("blockly", new Dictionary <string, object> {
                { "collapse", false },
                { "toolbox", toolbox },
                { "media", "../../media/" }
            });

            // Add tab handlers for switching between Block Factory and Block Exporter.
            this.addTabHandlers(this.tabMap);

            // Assign exporter change listeners.
            this.assignExporterChangeListeners();

            // Create the root block on Block Factory main workspace.
            if (BlocklyStorage.InWindow() && Window.Location.Hash != null && Window.Location.Hash.Length > 1)
            {
                BlocklyStorage.retrieveXml(Window.Location.Hash.Substring(1),
                                           BlockFactory.mainWorkspace);
            }
            else
            {
                BlockFactory.showStarterBlock();
            }
            BlockFactory.mainWorkspace.clearUndo();

            // Add Block Factory event listeners.
            this.addBlockFactoryEventListeners();

            // Workspace Factory init.
            WorkspaceFactoryInit.initWorkspaceFactory(this.workspaceFactoryController);
        }
Example #3
0
        /// <summary>
        /// Assign click handlers for workspace factory.
        /// </summary>
        /// <param name="controller"> The controller for the workspace
        /// factory tab.</param>
        private static void assignWorkspaceFactoryClickHandlers_(WorkspaceFactoryController controller)
        {
            // Import Custom Blocks button.
            Document.GetElementById("button_importBlocks").AddEventListener
                ("click",
                new Action(() => {
                BlockFactory.blocklyFactory.openModal("dropdownDiv_importBlocks");
            }));
            Document.GetElementById("input_importBlocksJson").AddEventListener
                ("change",
                new Action <Event>((@event) => {
                controller.importBlocks(((HTMLInputElement)@event.Target).files[0], "JSON");
            }));
            Document.GetElementById("input_importBlocksJson").AddEventListener
                ("click", new Action(() => { BlockFactory.blocklyFactory.closeModal(); }));
            Document.GetElementById("input_importBlocksJs").AddEventListener
                ("change",
                new Action <Event>((@event) => {
                controller.importBlocks(((HTMLInputElement)@event.Target).files[0], "JavaScript");
            }));
            Document.GetElementById("input_importBlocksJs").AddEventListener
                ("click", new Action(() => { BlockFactory.blocklyFactory.closeModal(); }));

            // Load to Edit button.
            Document.GetElementById("button_load").AddEventListener
                ("click",
                new Action(() => {
                BlockFactory.blocklyFactory.openModal("dropdownDiv_load");
            }));
            Document.GetElementById("input_loadToolbox").AddEventListener
                ("change",
                new Action <Event>((@event) => {
                controller.importFile(((HTMLInputElement)@event.Target).files[0],
                                      WorkspaceFactoryController.MODE_TOOLBOX);
            }));
            Document.GetElementById("input_loadToolbox").AddEventListener
                ("click", new Action(() => { BlockFactory.blocklyFactory.closeModal(); }));
            Document.GetElementById("input_loadPreload").AddEventListener
                ("change",
                new Action <Event>((@event) => {
                controller.importFile(((HTMLInputElement)@event.Target).files[0],
                                      WorkspaceFactoryController.MODE_PRELOAD);
            }));
            Document.GetElementById("input_loadPreload").AddEventListener
                ("click", new Action(() => { BlockFactory.blocklyFactory.closeModal(); }));

            // Export button.
            Document.GetElementById("dropdown_exportOptions").AddEventListener
                ("click",
                new Action(() => {
                controller.exportInjectFile();
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_exportToolbox").AddEventListener
                ("click",
                new Action(() => {
                controller.exportXmlFile(WorkspaceFactoryController.MODE_TOOLBOX);
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_exportPreload").AddEventListener
                ("click",
                new Action(() => {
                controller.exportXmlFile(WorkspaceFactoryController.MODE_PRELOAD);
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_exportAll").AddEventListener
                ("click",
                new Action(() => {
                controller.exportInjectFile();
                controller.exportXmlFile(WorkspaceFactoryController.MODE_TOOLBOX);
                controller.exportXmlFile(WorkspaceFactoryController.MODE_PRELOAD);
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("button_export").AddEventListener
                ("click",
                new Action(() => {
                BlockFactory.blocklyFactory.openModal("dropdownDiv_export");
            }));

            // Clear button.
            Document.GetElementById("button_clear").AddEventListener
                ("click",
                new Action(() => {
                controller.clearAll();
            }));

            // Toolbox and Workspace tabs.
            Document.GetElementById("tab_toolbox").AddEventListener
                ("click",
                new Action(() => {
                controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX);
            }));
            Document.GetElementById("tab_preload").AddEventListener
                ("click",
                new Action(() => {
                controller.setMode(WorkspaceFactoryController.MODE_PRELOAD);
            }));

            // "+" button.
            Document.GetElementById("button_add").AddEventListener
                ("click",
                new Action(() => {
                BlockFactory.blocklyFactory.openModal("dropdownDiv_add");
            }));
            Document.GetElementById("dropdown_newCategory").AddEventListener
                ("click",
                new Action(() => {
                controller.addCategory();
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_loadCategory").AddEventListener
                ("click",
                new Action(() => {
                controller.loadCategory();
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_separator").AddEventListener
                ("click",
                new Action(() => {
                controller.addSeparator();
                BlockFactory.blocklyFactory.closeModal();
            }));
            Document.GetElementById("dropdown_loadStandardToolbox").AddEventListener
                ("click",
                new Action(() => {
                controller.loadStandardToolbox();
                BlockFactory.blocklyFactory.closeModal();
            }));

            // "-" button.
            Document.GetElementById("button_remove").AddEventListener
                ("click",
                new Action(() => {
                controller.removeElement();
            }));

            // Up/Down buttons.
            Document.GetElementById("button_up").AddEventListener
                ("click",
                new Action(() => {
                controller.moveElement(-1);
            }));
            Document.GetElementById("button_down").AddEventListener
                ("click",
                new Action(() => {
                controller.moveElement(1);
            }));

            // Edit Category button.
            Document.GetElementById("button_editCategory").AddEventListener
                ("click",
                new Action(() => {
                BlockFactory.blocklyFactory.openModal("dropdownDiv_editCategory");
            }));
            Document.GetElementById("dropdown_name").AddEventListener
                ("click",
                new Action(() => {
                controller.changeCategoryName();
                BlockFactory.blocklyFactory.closeModal();
            }));

            // Make/Remove Shadow buttons.
            Document.GetElementById("button_addShadow").AddEventListener
                ("click",
                new Action(() => {
                controller.addShadow();
                WorkspaceFactoryInit.displayAddShadow_(false);
                WorkspaceFactoryInit.displayRemoveShadow_(true);
            }));
            Document.GetElementById("button_removeShadow").AddEventListener
                ("click",
                new Action(() => {
                controller.removeShadow();
                WorkspaceFactoryInit.displayAddShadow_(true);
                WorkspaceFactoryInit.displayRemoveShadow_(false);

                // Disable shadow editing button if turning invalid shadow block back
                // to normal block.
                if (Blockly.Core.selected.getSurroundParent() == null)
                {
                    ((HTMLButtonElement)Document.GetElementById("button_addShadow")).Disabled = true;
                }
            }));

            // Help button on workspace tab.
            Document.GetElementById("button_optionsHelp").AddEventListener
                ("click", new Action(() => {
                Window.Open("https://developers.google.com/blockly/guides/get-started/web#configuration");
            }));

            // Reset to Default button on workspace tab.
            Document.GetElementById("button_standardOptions").AddEventListener
                ("click", new Action(() => {
                controller.setStandardOptionsAndUpdate();
            }));
        }