diff --git a/core/lib/Drupal/Core/Render/Element/Dropbutton.php b/core/lib/Drupal/Core/Render/Element/Dropbutton.php index 76fab89..c690089 100644 --- a/core/lib/Drupal/Core/Render/Element/Dropbutton.php +++ b/core/lib/Drupal/Core/Render/Element/Dropbutton.php @@ -34,7 +34,8 @@ public function getInfo() { */ public static function preRenderDropbutton($element) { $element['#attached']['library'][] = 'core/drupal.dropbutton'; - $element['#attributes']['class'][] = 'dropbutton'; + $element['#attributes']['class'][] = 'dropbutton__menu'; + $element['#attributes']['class'][] = 'js-dropbutton__menu'; if (!isset($element['#theme_wrappers'])) { $element['#theme_wrappers'] = array(); } diff --git a/core/misc/dropbutton/dropbutton.css b/core/misc/dropbutton/dropbutton.css index 5990514..8e0fb82 100644 --- a/core/misc/dropbutton/dropbutton.css +++ b/core/misc/dropbutton/dropbutton.css @@ -7,75 +7,77 @@ /** * When a dropbutton has only one option, it is simply a button. */ -.dropbutton-wrapper, -.dropbutton-wrapper div { +.dropbutton, +.dropbutton div { box-sizing: border-box; } -.js .dropbutton-wrapper, -.js .dropbutton-widget { - display: block; +.js .dropbutton { position: relative; + display: block; + float: left; } @media screen and (max-width:600px) { - .js .dropbutton-wrapper { + .js .dropbutton { width: 100%; } } /* Splitbuttons */ @media screen and (min-width:600px) { - .form-actions .dropbutton-wrapper { + .form-actions .dropbutton { float: left; /* LTR */ } - [dir="rtl"] .form-actions .dropbutton-wrapper { + [dir="rtl"] .form-actions .dropbutton { float: right; } } -.js .form-actions .dropbutton-widget { +.js .form-actions .dropbutton { position: static; } -.js td .dropbutton-widget { - position: absolute; -} -.js td .dropbutton-wrapper { +.js td .dropbutton { min-height: 2em; } -.js td .dropbutton-multiple { - padding-right: 10em; /* LTR */ - margin-right: 2em; /* LTR */ +.js td .dropbutton--multiple { max-width: 100%; } -[dir="rtl"].js td .dropbutton-multiple { - padding-right: 0; - margin-right: 0; - padding-left: 10em; - margin-left: 2em; -} -.js td .dropbutton-multiple .dropbutton-action a, -.js td .dropbutton-multiple .dropbutton-action input, -.js td .dropbutton-multiple .dropbutton-action button { +.js td .dropbutton--multiple .dropbutton__action { width: auto; } /* UL styles are over-scoped in core, so this selector needs weight parity. */ -.js .dropbutton-widget .dropbutton { +.js .dropbutton .dropbutton__menu { + /* Positioning declarations */ + position: absolute; + top: 2em; + /* Box model declarations */ + display: none; + margin: 5px 0; + min-width: 100%; + padding: 5px 0; + /* Other declarations */ + background: #fff; + border: 1px solid #a6a6a6; + border-radius: 5px; list-style-image: none; list-style-type: none; - margin: 0; overflow: hidden; - padding: 0; } -.js .dropbutton li, -.js .dropbutton a { + +.dropbutton--multiple.is-open .dropbutton__menu { + display: block; +} + +.js .dropbutton__menu li, +.js .dropbutton__menu .dropbutton__action { display: block; outline: none; } -.js .dropbutton li:hover, -.js .dropbutton li:focus, -.js .dropbutton a:hover, -.js .dropbutton a:focus { +.js .dropbutton__menu li:hover, +.js .dropbutton__menu li:focus, +.js .dropbutton__menu a:hover, +.js .dropbutton__menu a:focus { outline: initial; } @@ -89,76 +91,100 @@ * The arrow is created using border on a zero-width, zero-height span. * The arrow inherits the link color, but can be overridden with border colors. */ -.js .dropbutton-multiple .dropbutton-widget { +.js .dropbutton--multiple { padding-right: 2em; /* LTR */ } -.js[dir="rtl"] .dropbutton-multiple .dropbutton-widget { +.js[dir="rtl"] .dropbutton--multiple { padding-left: 2em; padding-right: 0; } -.dropbutton-multiple.open, -.dropbutton-multiple.open .dropbutton-widget { +.dropbutton--multiple.is-open { max-width: none; -} -.dropbutton-multiple.open { z-index: 100; } -.dropbutton-multiple .dropbutton .secondary-action { - display: none; +.dropbutton--multiple .dropbutton__menu .dropbutton__action { + padding: 0.35em 1em; + color: #262626; + text-decoration: none; } -.dropbutton-multiple.open .dropbutton .secondary-action { - display: block; + +.dropbutton--multiple .dropbutton__menu .dropbutton__action:focus, +.dropbutton--multiple .dropbutton__menu .dropbutton__action:hover { + background: #c8ecfe; } -.dropbutton-toggle { + +.dropbutton__trigger { + /* Positioning declarations */ bottom: 0; - display: block; - position: absolute; right: 0; /* LTR */ - text-indent: 110%; top: 0; - white-space: nowrap; + /* Box model declarations */ + display: block; + height: auto; + margin: 0; + padding: 0; width: 2em; + /* Other declarations */ + cursor: pointer; + text-indent: 110%; + white-space: nowrap; } -[dir="rtl"] .dropbutton-toggle { +[dir="rtl"] .dropbutton__trigger { left: 0; right: auto; } -.dropbutton-toggle button { - background: none; - border: 0; - cursor: pointer; - display: block; - height: 100%; - margin: 0; - padding: 0; - width: 100%; -} -.dropbutton-toggle button:hover, -.dropbutton-toggle button:focus { +.dropbutton__trigger:hover, +.dropbutton__trigger:focus { outline: initial; } -.dropbutton-arrow { - border-bottom-color: transparent; - border-left-color: transparent; - border-right-color: transparent; - border-style: solid; - border-width: 0.3333em 0.3333em 0; - display: block; - height: 0; - line-height: 0; +.dropbutton__trigger:after { + /* Positioning declarations */ position: absolute; right: 40%; /* 0.6667em; */ /* LTR */ top: 50%; + /* Box model declarations */ + content: ""; + display: block; + height: 0; + line-height: 0; margin-top: -0.1666em; width: 0; + /* Other declarations */ + border-bottom-color: transparent; + border-left-color: transparent; + border-right-color: transparent; + border-style: solid; + border-width: 0.3333em 0.3333em 0; overflow: hidden; } -[dir="rtl"] .dropbutton-arrow { +[dir="rtl"] .dropbutton__trigger:after { left: 0.6667em; right: auto; } -.dropbutton-multiple.open .dropbutton-arrow { +.dropbutton--multiple.is-open .dropbutton__trigger:after { + top: 0.6667em; border-bottom: 0.3333em solid; border-top-color: transparent; - top: 0.6667em; +} +.dropbutton--multiple .button.dropbutton__action { + /* Box model declarations */ + padding-left: 1em; + float: left; + /* Other declarations */ + border-radius: 0; + border-top-left-radius: 20em; + border-bottom-left-radius: 20em; + font-size: 0.825rem; +} +.dropbutton .button.dropbutton__trigger { + /* Positioning declarations */ + position: absolute; + /* Box model declarations */ + padding-right: 1em; + float: left; + margin-left: -1px; + /* Other declarations */ + border-radius: 0; + border-top-right-radius: 20em; + border-bottom-right-radius: 20em; } diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js index 787cc56..a8d4077 100644 --- a/core/misc/dropbutton/dropbutton.js +++ b/core/misc/dropbutton/dropbutton.js @@ -14,12 +14,12 @@ */ Drupal.behaviors.dropButton = { attach: function (context, settings) { - var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton'); + var $dropbuttons = $(context).find('.dropbutton').once('dropbutton__menu'); if ($dropbuttons.length) { // Adds the delegated handler that will toggle dropdowns on click. var $body = $('body').once('dropbutton-click'); if ($body.length) { - $body.on('click', '.dropbutton-toggle', dropbuttonClickHandler); + $body.on('click', '.dropbutton__trigger', dropbuttonClickHandler); } // Initialize all buttons. var il = $dropbuttons.length; @@ -39,7 +39,7 @@ */ function dropbuttonClickHandler(e) { e.preventDefault(); - $(e.target).closest('.dropbutton-wrapper').toggleClass('open'); + $(e.target).closest('.dropbutton').toggleClass('is-open'); } /** @@ -71,27 +71,30 @@ /** * @type {jQuery} */ - this.$list = $dropbutton.find('.dropbutton'); + this.$list = $dropbutton.find('.dropbutton__menu'); /** * Find actions and mark them. * * @type {jQuery} */ - this.$actions = this.$list.find('li').addClass('dropbutton-action'); - + this.$actions = this.$list.find('li'); // Add the special dropdown only if there are hidden actions. if (this.$actions.length > 1) { // Identify the first element of the collection. - var $primary = this.$actions.slice(0, 1); + var $primary = this.$actions.slice(0, 1).find('a'); + // Remove parent
  • for first dropbutton action and move. + $primary.unwrap().addClass('button dropbutton__action').each(function() { + $(this).parent().before(this); + }); // Identify the secondary actions. - var $secondary = this.$actions.slice(1); - $secondary.addClass('secondary-action'); + var $secondary = this.$actions.slice(1).find('a'); + $secondary.addClass('dropbutton__action'); // Add toggle link. $primary.after(Drupal.theme('dropbuttonToggle', options)); // Bind mouse events. this.$dropbutton - .addClass('dropbutton-multiple') + .addClass('dropbutton--multiple') .on({ /** @@ -122,7 +125,10 @@ }); } else { - this.$dropbutton.addClass('dropbutton-single'); + //TODO route through button theming + this.$dropbutton.addClass('dropbutton--single'); + var $action = this.$actions.slice(0, 1).find('a'); + $action.unwrap().unwrap().addClass('button dropbutton__action'); } } @@ -152,8 +158,8 @@ */ toggle: function (show) { var isBool = typeof show === 'boolean'; - show = isBool ? show : !this.$dropbutton.hasClass('open'); - this.$dropbutton.toggleClass('open', show); + show = isBool ? show : !this.$dropbutton.hasClass('is-open'); + this.$dropbutton.toggleClass('is-open', show); }, /** @@ -216,7 +222,7 @@ * A string representing a DOM fragment. */ dropbuttonToggle: function (options) { - return '
  • '; + return ''; } }); diff --git a/core/modules/book/src/Tests/BookTest.php b/core/modules/book/src/Tests/BookTest.php index bfd3ae3..d786024 100644 --- a/core/modules/book/src/Tests/BookTest.php +++ b/core/modules/book/src/Tests/BookTest.php @@ -692,7 +692,7 @@ public function testAdminBookNodeListing() { $this->drupalGet('admin/structure/book/' . $this->book->id()); $this->assertText($this->book->label(), 'The book title is displayed on the administrative book listing page.'); - $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a'); + $elements = $this->xpath('//table//div[@class="dropbutton"]//a'); $this->assertEqual((string) $elements[0], 'View', 'View link is found from the list.'); } diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php index 5faa85c..a41c06e 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php @@ -200,7 +200,7 @@ protected function doTestTranslationOverview() { $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_path)); $this->assertEqual((string) $elements[0], $entity->getTranslation($langcode)->label(), format_string('Label correctly shown for %language translation.', array('%language' => $langcode))); $edit_path = $entity->url('edit-form', array('language' => $language)); - $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_path)); + $elements = $this->xpath('//table//div[@class="dropbutton"]//a[@href=:href]', array(':href' => $edit_path)); $this->assertEqual((string) $elements[0], t('Edit'), format_string('Edit link correct for %language translation.', array('%language' => $langcode))); } } diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index 3b2ac3e..075cdb2 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -150,7 +150,7 @@ function manageFieldsPage($type = '') { // Assert entity operations for all fields. $number_of_links = 3; $number_of_links_found = 0; - $operation_links = $this->xpath('//ul[@class = "dropbutton"]/li/a'); + $operation_links = $this->xpath('//div[@class = "dropbutton"]//a'); $url = base_path() . "admin/structure/types/manage/$type/fields/node.$type.body"; foreach ($operation_links as $link) { diff --git a/core/modules/node/src/Tests/AssertButtonsTrait.php b/core/modules/node/src/Tests/AssertButtonsTrait.php index 96eb6c8..8742f94 100644 --- a/core/modules/node/src/Tests/AssertButtonsTrait.php +++ b/core/modules/node/src/Tests/AssertButtonsTrait.php @@ -35,7 +35,7 @@ public function assertButtons($buttons, $dropbutton = TRUE) { $this->assertTrue(empty($save_button)); // Dropbutton elements. - $elements = $this->xpath('//div[@class="dropbutton-wrapper"]//input[@type="submit"]'); + $elements = $this->xpath('//div[@class="dropbutton"]//input[@type="submit"]'); $this->assertEqual($count, count($elements)); foreach ($elements as $element) { $value = isset($element['value']) ? (string) $element['value'] : ''; @@ -46,7 +46,7 @@ public function assertButtons($buttons, $dropbutton = TRUE) { else { // Assert there is a save button. $this->assertTrue(!empty($save_button)); - $this->assertNoRaw('dropbutton-wrapper'); + $this->assertNoRaw('dropbutton'); } } } diff --git a/core/modules/system/templates/dropbutton-wrapper.html.twig b/core/modules/system/templates/dropbutton-wrapper.html.twig index ca0ff7e..b07aa29 100644 --- a/core/modules/system/templates/dropbutton-wrapper.html.twig +++ b/core/modules/system/templates/dropbutton-wrapper.html.twig @@ -14,10 +14,8 @@ #} {% if children %} {% spaceless %} -
    -
    - {{ children }} -
    +
    + {{ children }}
    {% endspaceless %} {% endif %} diff --git a/core/modules/views/src/Tests/Plugin/RowRenderCacheTest.php b/core/modules/views/src/Tests/Plugin/RowRenderCacheTest.php index d44e229..0666b1c 100644 --- a/core/modules/views/src/Tests/Plugin/RowRenderCacheTest.php +++ b/core/modules/views/src/Tests/Plugin/RowRenderCacheTest.php @@ -157,10 +157,10 @@ protected function doTestRenderedOutput(AccountInterface $account, $check_cache $output = $view->style_plugin->getField($index, 'delete_node'); $this->assertEqual($output, $expected); - $expected = $access ? "
      " . + $expected = $access ? "
    " : ""; + "
    " : ""; $output = $view->style_plugin->getField($index, 'operations'); $this->assertEqual($output, $expected); diff --git a/core/modules/views_ui/config/optional/tour.tour.views-ui.yml b/core/modules/views_ui/config/optional/tour.tour.views-ui.yml index 1b4e475..0b04d67 100644 --- a/core/modules/views_ui/config/optional/tour.tour.views-ui.yml +++ b/core/modules/views_ui/config/optional/tour.tour.views-ui.yml @@ -60,7 +60,7 @@ tips: body: 'Add, rearrange or remove filters.' weight: 7 attributes: - data-class: 'views-ui-display-tab-bucket.filter .dropbutton-widget' + data-class: 'views-ui-display-tab-bucket.filter .dropbutton' views-ui-sorts: id: views-ui-sorts plugin: text @@ -76,7 +76,7 @@ tips: body: 'Add, rearrange or remove sorting rules.' weight: 9 attributes: - data-class: 'views-ui-display-tab-bucket.sort .dropbutton-widget' + data-class: 'views-ui-display-tab-bucket.sort .dropbutton' views-ui-preview: id: views-ui-preview plugin: text diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php index d71d888..d2b455c 100644 --- a/core/modules/views_ui/src/ViewEditForm.php +++ b/core/modules/views_ui/src/ViewEditForm.php @@ -396,7 +396,7 @@ public function getDisplayDetails($view, $display) { // Because some of the 'links' are actually submit buttons, we have to // manually wrap each item in
  • and the whole list in