From c426aad3879b15dcde2727edce0032571efb2827 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 11 Feb 2019 11:23:41 -0800 Subject: [PATCH] Use dropdown div for dropdowns --- core/css.js | 93 +++++++++++++++++++++++++++++------------- core/dropdowndiv.js | 2 +- core/field_dropdown.js | 65 +++++++++++++++++++---------- 3 files changed, 110 insertions(+), 50 deletions(-) diff --git a/core/css.js b/core/css.js index 5524a3102..4b4f3032f 100644 --- a/core/css.js +++ b/core/css.js @@ -190,8 +190,8 @@ Blockly.Css.CONTENT = [ 'z-index: 1000;', 'display: none;', 'border: 1px solid;', - 'border-radius: 4px;', - 'box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, .3);', + 'border-radius: 1px;', + //'box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, .3);', 'padding: 4px;', '-webkit-user-select: none;', '}', @@ -643,9 +643,9 @@ Blockly.Css.CONTENT = [ 'max-height: 100%;', '}', - '.blocklyDropdownMenu {', - 'padding: 0 !important;', - '}', + // '.blocklyDropdownMenu {', + // 'padding: 0 !important;', + // '}', /* Override the default Closure URL. */ '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,', @@ -822,6 +822,13 @@ Blockly.Css.CONTENT = [ 'z-index: 20000;', /* Arbitrary, but some apps depend on it... */ '}', + '.blocklyDropDownDiv .goog-menu {', + 'cursor: default;', + 'font: normal 13px "Helvetica Neue", Helvetica, sans-serif;', + 'outline: none;', + 'z-index: 20000;', /* Arbitrary, but some apps depend on it... */ + '}', + /* Copied from: goog/css/menuitem.css */ /* * Copyright 2009 The Closure Library Authors. All Rights Reserved. @@ -851,19 +858,22 @@ Blockly.Css.CONTENT = [ * rely solely on the BiDi flipping by the CSS compiler. That's why we're * not adding the #noflip to .goog-menuitem. */ - '.blocklyWidgetDiv .goog-menuitem {', + '.blocklyWidgetDiv .goog-menuitem, ', + '.blocklyDropDownDiv .goog-menuitem {', 'color: #000;', 'font: normal 13px Arial, sans-serif;', 'list-style: none;', 'margin: 0;', /* 28px on the left for icon or checkbox; 7em on the right for shortcut. */ - 'padding: 4px 7em 4px 28px;', + 'min-width: 7em;', + 'padding: 5px 5px 5px 28px;', 'white-space: nowrap;', '}', /* BiDi override for the resting state. */ /* #noflip */ - '.blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl {', + '.blocklyWidgetDiv .goog-menuitem.goog-menuitem-rtl, ', + '.blocklyDropDownDiv .goog-menuitem.goog-menuitem-rtl {', /* Flip left/right padding for BiDi. */ 'padding-left: 7em;', 'padding-right: 28px;', @@ -872,36 +882,43 @@ Blockly.Css.CONTENT = [ /* If a menu doesn't have checkable items or items with icons, * remove padding. */ - '.blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem,', - '.blocklyWidgetDiv .goog-menu-noicon .goog-menuitem {', + '.blocklyWidgetDiv .goog-menu-nocheckbox .goog-menuitem, ', + '.blocklyWidgetDiv .goog-menu-noicon .goog-menuitem, ', + '.blocklyDropDownDiv .goog-menu-nocheckbox .goog-menuitem, ', + '.blocklyDropDownDiv .goog-menu-noicon .goog-menuitem { ', 'padding-left: 12px;', '}', /* If a menu doesn't have items with shortcuts, leave just enough room for * submenu arrows, if they are rendered. */ - '.blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem {', + '.blocklyWidgetDiv .goog-menu-noaccel .goog-menuitem, ', + '.blocklyDropDownDiv .goog-menu-noaccel .goog-menuitem {', 'padding-right: 20px;', '}', - '.blocklyWidgetDiv .goog-menuitem-content {', + '.blocklyWidgetDiv .goog-menuitem-content, ', + '.blocklyDropDownDiv .goog-menuitem-content {', 'color: #000;', 'font: normal 13px Arial, sans-serif;', '}', /* State: disabled. */ - '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel,', - '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content {', + '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-accel, ', + '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-content, ', + '.blocklyDropDownDiv .goog-menuitem-disabled .goog-menuitem-accel, ', + '.blocklyDropDownDiv .goog-menuitem-disabled .goog-menuitem-content {', 'color: #ccc !important;', '}', - '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon {', + '.blocklyWidgetDiv .goog-menuitem-disabled .goog-menuitem-icon, ', + '.blocklyDropDownDiv .goog-menuitem-disabled .goog-menuitem-icon {', 'opacity: 0.3;', 'filter: alpha(opacity=30);', '}', /* State: hover. */ - '.blocklyWidgetDiv .goog-menuitem-highlight,', + '.blocklyWidgetDiv .goog-menuitem-highlight, ', '.blocklyWidgetDiv .goog-menuitem-hover {', 'background-color: #d6e9f8;', /* Use an explicit top and bottom border so that the selection is visible', @@ -913,9 +930,16 @@ Blockly.Css.CONTENT = [ 'padding-top: 3px;', '}', + '.blocklyDropDownDiv .goog-menuitem-highlight, ', + '.blocklyDropDownDiv .goog-menuitem-hover {', + 'background-color: rgba(0, 0, 0, 0.2);', + '}', + /* State: selected/checked. */ - '.blocklyWidgetDiv .goog-menuitem-checkbox,', - '.blocklyWidgetDiv .goog-menuitem-icon {', + '.blocklyWidgetDiv .goog-menuitem-checkbox, ', + '.blocklyWidgetDiv .goog-menuitem-icon, ', + '.blocklyDropDownDiv .goog-menuitem-checkbox, ', + '.blocklyDropDownDiv .goog-menuitem-icon {', 'background-repeat: no-repeat;', 'height: 16px;', 'left: 6px;', @@ -927,21 +951,30 @@ Blockly.Css.CONTENT = [ /* BiDi override for the selected/checked state. */ /* #noflip */ - '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox,', - '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon {', + '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-checkbox, ', + '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-icon, ', + '.blocklyDropDownDiv .goog-menuitem-rtl .goog-menuitem-checkbox, ', + '.blocklyDropDownDiv .goog-menuitem-rtl .goog-menuitem-icon {', /* Flip left/right positioning. */ 'left: auto;', 'right: 6px;', '}', - '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox,', - '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon {', + '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-checkbox, ', + '.blocklyWidgetDiv .goog-option-selected .goog-menuitem-icon, ', + '.blocklyDropDownDiv .goog-option-selected .goog-menuitem-checkbox, ', + '.blocklyDropDownDiv .goog-option-selected .goog-menuitem-icon {', /* Client apps may override the URL at which they serve the sprite. */ - 'background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;', + //'background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;', + 'background: url(<<>>/sprites.png) no-repeat -48px -16px !important;', + 'position: static;', /* Scroll with the menu. */ + 'float: left;', + 'margin-left: -24px;', '}', /* Keyboard shortcut ("accelerator") style. */ - '.blocklyWidgetDiv .goog-menuitem-accel {', + '.blocklyWidgetDiv .goog-menuitem-accel, ', + '.blocklyDropDownDiv .goog-menuitem-accel {', 'color: #999;', /* Keyboard shortcuts are untranslated; always left-to-right. */ /* #noflip */ @@ -955,7 +988,8 @@ Blockly.Css.CONTENT = [ /* BiDi override for shortcut style. */ /* #noflip */ - '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel {', + '.blocklyWidgetDiv .goog-menuitem-rtl .goog-menuitem-accel, ', + '.blocklyDropDownDiv .goog-menuitem-rtl .goog-menuitem-accel {', /* Flip left/right positioning and text alignment. */ 'left: 0;', 'right: auto;', @@ -963,11 +997,13 @@ Blockly.Css.CONTENT = [ '}', /* Mnemonic styles. */ - '.blocklyWidgetDiv .goog-menuitem-mnemonic-hint {', + '.blocklyWidgetDiv .goog-menuitem-mnemonic-hint, ', + '.blocklyDropDownDiv .goog-menuitem-mnemonic-hint {', 'text-decoration: underline;', '}', - '.blocklyWidgetDiv .goog-menuitem-mnemonic-separator {', + '.blocklyWidgetDiv .goog-menuitem-mnemonic-separator, ', + '.blocklyDropDownDiv .goog-menuitem-mnemonic-separator {', 'color: #999;', 'font-size: 12px;', 'padding-left: 4px;', @@ -987,7 +1023,8 @@ Blockly.Css.CONTENT = [ * @author attila@google.com (Attila Bodis) */ - '.blocklyWidgetDiv .goog-menuseparator {', + '.blocklyWidgetDiv .goog-menuseparator, ', + '.blocklyDropDownDiv .goog-menuseparator {', 'border-top: 1px solid #ccc;', 'margin: 4px 0;', 'padding: 0;', diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index d2cf86622..49f1ad8fe 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -93,7 +93,7 @@ Blockly.DropDownDiv.ARROW_HORIZONTAL_PADDING = 12; * @type {number} * @const */ -Blockly.DropDownDiv.PADDING_Y = 20; +Blockly.DropDownDiv.PADDING_Y = 8; /** * Length of animations in seconds. diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 1de845765..4df54395a 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -140,7 +140,15 @@ Blockly.FieldDropdown.prototype.init = function() { * @private */ Blockly.FieldDropdown.prototype.showEditor_ = function() { - Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, null); + // consider passing the options into createMenu instead of getting them twice. + var options = this.getOptions(); + if (options.length == 0) return; + + this.dropDownOpen_ = true; + // If there is an existing drop-down someone else owns, hide it immediately and clear it. + Blockly.DropDownDiv.hideWithoutAnimation(); + Blockly.DropDownDiv.clearContent(); + var menu = this.createMenu_(); this.addActionListener_(menu); this.positionMenu_(menu); @@ -154,13 +162,16 @@ Blockly.FieldDropdown.prototype.showEditor_ = function() { Blockly.FieldDropdown.prototype.addActionListener_ = function(menu) { var thisField = this; + var selected = false; function callback(e) { + if (selected) return; var menu = this; var menuItem = e.target; if (menuItem) { thisField.onItemSelected(menu, menuItem); + selected = true; } - Blockly.WidgetDiv.hideIfOwner(thisField); + Blockly.DropDownDiv.hide(); Blockly.Events.setGroup(false); } // Listen for mouse/keyboard events. @@ -205,25 +216,28 @@ Blockly.FieldDropdown.prototype.createMenu_ = function() { * @private */ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) { - // Record viewport dimensions before adding the dropdown. - var viewportBBox = Blockly.utils.getViewportBBox(); - var anchorBBox = this.getAnchorDimensions_(); + // // Record viewport dimensions before adding the dropdown. + // var viewportBBox = Blockly.utils.getViewportBBox(); + // var anchorBBox = this.getAnchorDimensions_(); + // this.createWidget_(menu); + // var menuSize = Blockly.utils.uiMenu.getSize(menu); + + // var menuMaxHeightPx = Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH + // * document.documentElement.clientHeight; + // if (menuSize.height > menuMaxHeightPx) { + // menuSize.height = menuMaxHeightPx; + // } + + // if (this.sourceBlock_.RTL) { + // Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize); + // } + // // Position the menu. + // Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, + // this.sourceBlock_.RTL); this.createWidget_(menu); - var menuSize = Blockly.utils.uiMenu.getSize(menu); - - var menuMaxHeightPx = Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH - * document.documentElement.clientHeight; - if (menuSize.height > menuMaxHeightPx) { - menuSize.height = menuMaxHeightPx; - } - - if (this.sourceBlock_.RTL) { - Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize); - } - // Position the menu. - Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, - this.sourceBlock_.RTL); + this.updateColours_(); + Blockly.DropDownDiv.showPositionedByField(this); // Calling menuDom.focus() has to wait until after the menu has been placed // correctly. Otherwise it will cause a page scroll to get the misplaced menu // in view. See issue #1329. @@ -236,13 +250,22 @@ Blockly.FieldDropdown.prototype.positionMenu_ = function(menu) { * @private */ Blockly.FieldDropdown.prototype.createWidget_ = function(menu) { - var div = Blockly.WidgetDiv.DIV; - menu.render(div); + var contentDiv = Blockly.DropDownDiv.getContentDiv(); + menu.render(contentDiv); Blockly.utils.addClass(menu.getElement(), 'blocklyDropdownMenu'); // Enable autofocus after the initial render to avoid issue #1329. menu.setAllowAutoFocus(true); }; +/** + * Set the colours of the dropdown div to match the colours of the field or + * parent block. + * @private + */ +Blockly.FieldDropdown.prototype.updateColours_ = function() { + Blockly.DropDownDiv.setColour('#ffffff', '#dddddd'); +}; + /** * Returns the coordinates of the anchor rectangle for the widget div. * On a FieldDropdown we take the top-left corner of the field, then adjust for