Esempio n. 1
0
        /// <summary>
        /// Show the inline free-text editor on top of the text.
        /// </summary>
        /// <param name="opt_quietInput">True if editor should be created without
        /// focus.Defaults to false.</param>
        public override void showEditor_(bool opt_quietInput)
        {
            this.workspace_ = (WorkspaceSvg)this.sourceBlock_.workspace;
            var quietInput = opt_quietInput || false;

            if (!quietInput && (goog.userAgent.MOBILE || goog.userAgent.ANDROID ||
                                goog.userAgent.IPAD))
            {
                // Mobile browsers have issues with in-line textareas (focus & keyboards).
                var newValue = Window.Prompt(Msg.CHANGE_VALUE_TITLE, this.text_);
                if (this.sourceBlock_ != null)
                {
                    newValue = this.callValidator(newValue);
                }
                this.setValue(newValue);
                return;
            }

            WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_());
            var div = WidgetDiv.DIV;
            // Create the input.
            var htmlInput = (HTMLInputElement)
                            goog.dom.createDom(goog.dom.TagName.INPUT, "blocklyHtmlInput");

            htmlInput.SetAttribute("spellcheck", this.spellcheck_.ToString());
            var fontSize =
                (FieldTextInput.FONTSIZE * this.workspace_.scale) + "pt";

            div.Style.FontSize       = fontSize;
            htmlInput.Style.FontSize = fontSize;
            /** @type {!HTMLInputElement} */
            FieldTextInput.htmlInput_ = htmlInput;
            div.AppendChild(htmlInput);

            htmlInput.Value        = htmlInput.DefaultValue = this.text_;
            htmlInput["oldValue_"] = null;
            this.validate_();
            this.resizeEditor_();
            if (!quietInput)
            {
                htmlInput.Focus();
                htmlInput.Select();
            }

            // Bind to keydown -- trap Enter without IME and Esc to hide.
            htmlInput["onKeyDownWrapper_"] =
                Core.bindEventWithChecks_(htmlInput, "keydown", this,
                                          new Action <KeyboardEvent>(this.onHtmlInputKeyDown_));
            // Bind to keyup -- trap Enter; resize after every keystroke.
            htmlInput["onKeyUpWrapper_"] =
                Core.bindEventWithChecks_(htmlInput, "keyup", this,
                                          new Action <Event>(this.onHtmlInputChange_));
            // Bind to keyPress -- repeatedly resize when holding down a key.
            htmlInput["onKeyPressWrapper_"] =
                Core.bindEventWithChecks_(htmlInput, "keypress", this,
                                          new Action <Event>(this.onHtmlInputChange_));
            htmlInput["onWorkspaceChangeWrapper_"] = new Action <Events.Abstract>(this.resizeEditor_);
            this.workspace_.addChangeListener((Action <Events.Abstract>)htmlInput["onWorkspaceChangeWrapper_"]);
        }
Esempio n. 2
0
        /// <summary>
        /// Create a date picker under the date field.
        /// </summary>
        public override void showEditor_(bool opt_quietInput)
        {
            WidgetDiv.show(this, this.sourceBlock_.RTL,
                           new Action(FieldDate.widgetDispose_));
            // Create the date picker using Closure.
            FieldDate.loadLanguage_();
            var picker = new goog.ui.DatePicker();

            picker.setAllowNone(false);
            picker.setShowWeekNum(false);

            // Position the picker to line up with the field.
            // Record windowSize and scrollOffset before adding the picker.
            var windowSize   = goog.dom.getViewportSize();
            var scrollOffset = goog.style.getViewportPageOffset(Document.Instance);
            var xy           = this.getAbsoluteXY_();
            var borderBBox   = this.getScaledBBox_();
            var div          = WidgetDiv.DIV;

            picker.render(div);
            picker.setDate(new Date(this.getValue()));
            // Record pickerSize after adding the date picker.
            var pickerSize = goog.style.getSize(picker.getElement());

            // Flip the picker vertically if off the bottom.
            if (xy.y + pickerSize.height + borderBBox.height >=
                windowSize.height + scrollOffset.y)
            {
                xy.y -= pickerSize.height - 1;
            }
            else
            {
                xy.y += borderBBox.height - 1;
            }
            if (this.sourceBlock_.RTL)
            {
                xy.x += borderBBox.width;
                xy.x -= pickerSize.width;
                // Don't go offscreen left.
                if (xy.x < scrollOffset.x)
                {
                    xy.x = scrollOffset.x;
                }
            }
            else
            {
                // Don't go offscreen right.
                if (xy.x > windowSize.width + scrollOffset.x - pickerSize.width)
                {
                    xy.x = windowSize.width + scrollOffset.x - pickerSize.width;
                }
            }
            WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset,
                               this.sourceBlock_.RTL);

            // Configure event handler.
            var thisField = this;

            FieldDate.changeEventKey_ = goog.events.listen(picker,
                                                           goog.ui.DatePicker.Events.CHANGE,
                                                           new Action <Bridge.Html5.Event>((e) => {
                var date = e.Date != null ? e.Date.ToIsoString(true) : "";
                WidgetDiv.hide();
                if (thisField.sourceBlock_ != null)
                {
                    // Call any validation function, and allow it to override.
                    date = thisField.callValidator(date);
                }
                thisField.setValue(date);
            }));
        }
Esempio n. 3
0
        /// <summary>
        /// Create a palette under the colour field.
        /// </summary>
        public override void showEditor_(bool opt_quietInput)
        {
            WidgetDiv.show(this, this.sourceBlock_.RTL,
                           new Action(FieldColour.widgetDispose_));
            // Create the palette using Closure.
            var picker = new goog.ui.ColorPicker();

            picker.setSize(this.columns_ ?? FieldColour.COLUMNS);
            picker.setColors(new JsArray <string>(this.colours_ ?? FieldColour.COLOURS));

            // Position the palette to line up with the field.
            // Record windowSize and scrollOffset before adding the palette.
            var windowSize   = goog.dom.getViewportSize();
            var scrollOffset = goog.style.getViewportPageOffset(Document.Instance);
            var xy           = this.getAbsoluteXY_();
            var borderBBox   = this.getScaledBBox_();
            var div          = WidgetDiv.DIV;

            picker.render(div);
            picker.setSelectedColor(this.getValue());
            // Record paletteSize after adding the palette.
            var paletteSize = goog.style.getSize(picker.getElement());

            // Flip the palette vertically if off the bottom.
            if (xy.y + paletteSize.height + borderBBox.height >=
                windowSize.height + scrollOffset.y)
            {
                xy.y -= paletteSize.height - 1;
            }
            else
            {
                xy.y += borderBBox.height - 1;
            }
            if (this.sourceBlock_.RTL)
            {
                xy.x += borderBBox.width;
                xy.x -= paletteSize.width;
                // Don't go offscreen left.
                if (xy.x < scrollOffset.x)
                {
                    xy.x = scrollOffset.x;
                }
            }
            else
            {
                // Don't go offscreen right.
                if (xy.x > windowSize.width + scrollOffset.x - paletteSize.width)
                {
                    xy.x = windowSize.width + scrollOffset.x - paletteSize.width;
                }
            }
            WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset,
                               this.sourceBlock_.RTL);

            // Configure event handler.
            var thisField = this;

            FieldColour.changeEventKey_ = goog.events.listen(picker,
                                                             goog.ui.ColorPicker.EventType.CHANGE,
                                                             new Action <goog.events.Event>((e) => {
                string colour = ((goog.ui.ColorPicker)e.target).getSelectedColor() ?? "#000000";
                WidgetDiv.hide();
                if (thisField.sourceBlock_ != null)
                {
                    // Call any validation function, and allow it to override.
                    colour = thisField.callValidator(colour);
                }
                if (colour != null)
                {
                    thisField.setValue(colour);
                }
            }));
        }
Esempio n. 4
0
        /// <summary>
        /// Create a dropdown menu under the text.
        /// </summary>
        public override void showEditor_(bool opt_quietInput)
        {
            WidgetDiv.show(this, this.sourceBlock_.RTL, null);
            var thisField = this;

            var callback = new Action <goog.events.Event>((e) => {
                var menuItem = (goog.ui.MenuItem)e.target;
                if (menuItem != null)
                {
                    var value = menuItem.getValue();
                    if (thisField.sourceBlock_ != null)
                    {
                        // Call any validation function, and allow it to override.
                        value = thisField.callValidator(value);
                    }
                    if (value != null)
                    {
                        thisField.setValue(value);
                    }
                }
                WidgetDiv.hideIfOwner(thisField);
            });

            var menu = new goog.ui.Menu();

            menu.setRightToLeft(this.sourceBlock_.RTL);
            var options = this.getOptions_();

            for (var i = 0; i < options.Length; i++)
            {
                var text     = options[i].text;              // Human-readable text.
                var value    = options[i].value;             // Language-neutral value.
                var menuItem = new goog.ui.MenuItem(text);
                menuItem.setRightToLeft(this.sourceBlock_.RTL);
                menuItem.setValue(value);
                menuItem.setCheckable(true);
                menu.addChild(menuItem, true);
                menuItem.setChecked(value == this.value_);
            }
            // Listen for mouse/keyboard events.
            goog.events.listen(menu, goog.ui.Component.EventType.ACTION, callback);
            // Listen for touch events (why doesn't Closure handle this already?).
            var callbackTouchStart = new Action <goog.events.BrowserEvent>((e) => {
                var control = menu.getOwnerControl((Node)e.target);
                // Highlight the menu item.
                control.handleMouseDown(e);
            });
            var callbackTouchEnd = new Action <goog.events.Event>((e) => {
                var control = menu.getOwnerControl((Node)e.target);
                // Activate the menu item.
                control.performActionInternal(e);
            });

            menu.getHandler().listen(menu.getElement(), goog.events.EventType.TOUCHSTART,
                                     callbackTouchStart);
            menu.getHandler().listen(menu.getElement(), goog.events.EventType.TOUCHEND,
                                     callbackTouchEnd);

            // Record windowSize and scrollOffset before adding menu.
            var windowSize   = goog.dom.getViewportSize();
            var scrollOffset = goog.style.getViewportPageOffset(Document.Instance);
            var xy           = this.getAbsoluteXY_();
            var borderBBox   = this.getScaledBBox_();
            var div          = WidgetDiv.DIV;

            menu.render(div);
            var menuDom = menu.getElement();

            Core.addClass_(menuDom, "blocklyDropdownMenu");
            // Record menuSize after adding menu.
            var menuSize = goog.style.getSize(menuDom);

            // Recalculate height for the total content, not only box height.
            menuSize.height = menuDom.ScrollHeight;

            // Position the menu.
            // Flip menu vertically if off the bottom.
            if (xy.y + menuSize.height + borderBBox.height >=
                windowSize.height + scrollOffset.y)
            {
                xy.y -= menuSize.height + 2;
            }
            else
            {
                xy.y += borderBBox.height;
            }
            if (this.sourceBlock_.RTL)
            {
                xy.x += borderBBox.width;
                xy.x += FieldDropdown.CHECKMARK_OVERHANG;
                // Don't go offscreen left.
                if (xy.x < scrollOffset.x + menuSize.width)
                {
                    xy.x = scrollOffset.x + menuSize.width;
                }
            }
            else
            {
                xy.x -= FieldDropdown.CHECKMARK_OVERHANG;
                // Don't go offscreen right.
                if (xy.x > windowSize.width + scrollOffset.x - menuSize.width)
                {
                    xy.x = windowSize.width + scrollOffset.x - menuSize.width;
                }
            }
            WidgetDiv.position(xy.x, xy.y, windowSize, scrollOffset,
                               this.sourceBlock_.RTL);
            menu.setAllowAutoFocus(true);
            menuDom.Focus();
        }
Esempio n. 5
0
        /// <summary>
        /// Construct the menu based on the list of options and show the menu.
        /// </summary>
        /// <param name="e">Mouse event.</param>
        /// <param name="options">Array of menu options.</param>
        /// <param name="rtl">True if RTL, false if LTR.</param>
        public static void show(MouseEvent e, ContextMenuOption[] options, bool rtl)
        {
            WidgetDiv.show(Core.ContextMenu, rtl, null);
            if (options.Length == 0)
            {
                ContextMenu.hide();
                return;
            }

            /* Here's what one option object looks like:
             * {text: 'Make It So',
             * enabled: true,
             * callback: Blockly.MakeItSo}
             */
            var menu = new goog.ui.Menu();

            menu.setRightToLeft(rtl);
            foreach (var option in options)
            {
                var menuItem = new goog.ui.MenuItem(option.text);
                menuItem.setRightToLeft(rtl);
                menu.addChild(menuItem, true);
                menuItem.setEnabled(option.enabled);
                if (option.enabled)
                {
                    goog.events.listen(menuItem, goog.ui.Component.EventType.ACTION,
                                       option.callback);
                }
            }
            goog.events.listen(menu, goog.ui.Component.EventType.ACTION,
                               new Action <goog.events.Event>((ev) => ContextMenu.hide()));
            // Record windowSize and scrollOffset before adding menu.
            var windowSize   = goog.dom.getViewportSize();
            var scrollOffset = goog.style.getViewportPageOffset(Document.Instance);
            var div          = WidgetDiv.DIV;

            menu.render(div);
            var menuDom = menu.getElement();

            Core.addClass_(menuDom, "blocklyContextMenu");
            // Prevent system context menu when right-clicking a Blockly context menu.
            Core.bindEventWithChecks_(menuDom, "contextmenu", null, new Action <Event>(Core.noEvent));
            // Record menuSize after adding menu.
            var menuSize = goog.style.getSize(menuDom);

            // Position the menu.
            var x = e.ClientX + scrollOffset.x;
            var y = e.ClientY + scrollOffset.y;

            // Flip menu vertically if off the bottom.
            if (e.ClientY + menuSize.height >= windowSize.height)
            {
                y -= menuSize.height;
            }
            // Flip menu horizontally if off the edge.
            if (rtl)
            {
                if (menuSize.width >= e.ClientX)
                {
                    x += menuSize.width;
                }
            }
            else
            {
                if (e.ClientX + menuSize.width >= windowSize.width)
                {
                    x -= menuSize.width;
                }
            }
            WidgetDiv.position(x, y, windowSize, scrollOffset, rtl);

            menu.setAllowAutoFocus(true);
            // 1ms delay is required for focusing on context menus because some other
            // mouse event is still waiting in the queue and clears focus.
            Window.SetTimeout(() => { menuDom.Focus(); }, 1);
            ContextMenu.currentBlock = null;              // May be set by Blockly.Block.
        }