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/language/config/optional/tour.tour.language.yml b/core/modules/language/config/optional/tour.tour.language.yml index 7cca3e5..3c0dbf3 100644 --- a/core/modules/language/config/optional/tour.tour.language.yml +++ b/core/modules/language/config/optional/tour.tour.language.yml @@ -42,7 +42,7 @@ tips: body: '

    Operations are provided for editing and deleting your languages.

    You can edit the name and the direction of the language.

    Deleted languages can be added back at a later time. Deleting a language will remove all interface translations associated with it, and content in this language will be set to be language neutral. Note that you cannot delete the default language of the site.

    ' weight: 5 attributes: - data-class: dropbutton-wrapper + data-class: dropbutton language-continue: id: language-continue plugin: text 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..f116aea 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/css/views_ui.admin.css b/core/modules/views_ui/css/views_ui.admin.css index e932af1..638db6a 100644 --- a/core/modules/views_ui/css/views_ui.admin.css +++ b/core/modules/views_ui/css/views_ui.admin.css @@ -203,6 +203,6 @@ html.js .js-only { html.js span.js-only { display: inline; } -.js .views-edit-view .dropbutton-wrapper { +.js .views-edit-view .dropbutton { width: auto; } 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