From 8749a4c6d495466b8dd63c4d1823e5b8509b5955 Mon Sep 17 00:00:00 2001 From: galczo5 Date: Sun, 7 Oct 2018 11:51:06 +0200 Subject: [PATCH 1/5] Added 'show' and 'hide' methods to dropdown --- js/src/dropdown.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/js/src/dropdown.js b/js/src/dropdown.js index a7a77cb3b6ca..05724232d4b6 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -194,6 +194,53 @@ class Dropdown { .trigger($.Event(Event.SHOWN, relatedTarget)) } + show() { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { + return + } + const isActive = $(this._menu).hasClass(ClassName.SHOW) + if (isActive) { + return + } + + const showEvent = $.Event(Event.SHOW, { + relatedTarget: this._element + }) + + const parent = Dropdown._getParentFromElement(this._element) + $(parent).trigger(showEvent) + + if (showEvent.isDefaultPrevented()) { + return + } + + $(this._menu).toggleClass(ClassName.SHOW) + } + + hide() { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { + return + } + + const isActive = $(this._menu).hasClass(ClassName.SHOW) + if (!isActive) { + return + } + + const hideEvent = $.Event(Event.HIDE, { + relatedTarget: this._element + }) + + const parent = Dropdown._getParentFromElement(this._element) + $(parent).trigger(hideEvent) + + if (hideEvent.isDefaultPrevented()) { + return + } + + $(this._menu).toggleClass(ClassName.SHOW) + } + dispose() { $.removeData(this._element, DATA_KEY) $(this._element).off(EVENT_KEY) From c38d15235e630487a84f9d07760e3d6ee9b6fcd6 Mon Sep 17 00:00:00 2001 From: galczo5 Date: Sun, 7 Oct 2018 20:28:44 +0200 Subject: [PATCH 2/5] Added unit tests for dropdown.js 'show' and 'hide' methods --- js/src/dropdown.js | 16 +++++++--- js/tests/unit/dropdown.js | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 05724232d4b6..96d8c3ba248d 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -203,9 +203,10 @@ class Dropdown { return } - const showEvent = $.Event(Event.SHOW, { + const relatedTarget = { relatedTarget: this._element - }) + } + const showEvent = $.Event(Event.SHOW, relatedTarget) const parent = Dropdown._getParentFromElement(this._element) $(parent).trigger(showEvent) @@ -215,6 +216,9 @@ class Dropdown { } $(this._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.SHOWN, relatedTarget)) } hide() { @@ -227,9 +231,10 @@ class Dropdown { return } - const hideEvent = $.Event(Event.HIDE, { + const relatedTarget = { relatedTarget: this._element - }) + } + const hideEvent = $.Event(Event.HIDE, relatedTarget) const parent = Dropdown._getParentFromElement(this._element) $(parent).trigger(hideEvent) @@ -239,6 +244,9 @@ class Dropdown { } $(this._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.HIDDEN, relatedTarget)) } dispose() { diff --git a/js/tests/unit/dropdown.js b/js/tests/unit/dropdown.js index 40489c5f2c3f..2264536174a5 100644 --- a/js/tests/unit/dropdown.js +++ b/js/tests/unit/dropdown.js @@ -1097,4 +1097,69 @@ $(function () { assert.ok(dropdown._menu === null) assert.ok(dropdown._element === null) }) + + QUnit.test('should show dropdown', function (assert) { + assert.expect(2) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + var done = assert.async() + + $dropdown + .parent('.dropdown') + .on('show.bs.dropdown', function () { + assert.ok(true, 'show was fired') + }) + .on('shown.bs.dropdown', function () { + assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown') + done() + }) + + dropdown.show() + }) + + QUnit.test('should hide dropdown', function (assert) { + assert.expect(2) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + var done = assert.async() + $dropdown.trigger('click') + + $dropdown + .parent('.dropdown') + .on('hide.bs.dropdown', function () { + assert.ok(true, 'hide was fired') + }) + .on('hidden.bs.dropdown', function () { + assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is hidden') + done() + }) + + dropdown.hide() + }) }) From 174da9d9ec20f5fbf6715caa9df2d6b9adfb6b9e Mon Sep 17 00:00:00 2001 From: galczo5 Date: Mon, 8 Oct 2018 20:20:54 +0200 Subject: [PATCH 3/5] Added more tests of show/hide methods in dropdown.js --- js/src/dropdown.js | 4 +- js/tests/unit/dropdown.js | 199 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 2 deletions(-) diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 96d8c3ba248d..3e13deb59275 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -208,7 +208,7 @@ class Dropdown { } const showEvent = $.Event(Event.SHOW, relatedTarget) - const parent = Dropdown._getParentFromElement(this._element) + const parent = Dropdown._getParentFromElement(this._element) $(parent).trigger(showEvent) if (showEvent.isDefaultPrevented()) { @@ -236,7 +236,7 @@ class Dropdown { } const hideEvent = $.Event(Event.HIDE, relatedTarget) - const parent = Dropdown._getParentFromElement(this._element) + const parent = Dropdown._getParentFromElement(this._element) $(parent).trigger(hideEvent) if (hideEvent.isDefaultPrevented()) { diff --git a/js/tests/unit/dropdown.js b/js/tests/unit/dropdown.js index 2264536174a5..fd9b7f962958 100644 --- a/js/tests/unit/dropdown.js +++ b/js/tests/unit/dropdown.js @@ -1162,4 +1162,203 @@ $(function () { dropdown.hide() }) + + QUnit.test('should not hide dropdown', function (assert) { + assert.expect(1) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + $dropdown.trigger('click') + dropdown.show() + + assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is still shown') + }) + + QUnit.test('should not show dropdown', function (assert) { + assert.expect(1) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + dropdown.hide() + assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is still hidden') + }) + + QUnit.test('should show dropdown', function (assert) { + assert.expect(2) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + var done = assert.async() + + $dropdown + .parent('.dropdown') + .on('show.bs.dropdown', function () { + assert.ok(true, 'show was fired') + }) + .on('shown.bs.dropdown', function () { + assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown') + done() + }) + + dropdown.show() + }) + + QUnit.test('should prevent default event on show method call', function (assert) { + assert.expect(1) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + var done = assert.async() + + $dropdown + .parent('.dropdown') + .on('show.bs.dropdown', function (event) { + event.preventDefault() + done() + }) + + dropdown.show() + assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is hidden') + }) + + QUnit.test('should prevent default event on hide method call', function (assert) { + assert.expect(1) + + var dropdownHTML = + '' + + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var dropdown = $dropdown.data('bs.dropdown') + var done = assert.async() + $dropdown.trigger('click') + + $dropdown + .parent('.dropdown') + .on('hide.bs.dropdown', function (event) { + event.preventDefault() + done() + }) + + dropdown.hide() + assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown') + }) + + QUnit.test('should not open dropdown via show method if target is disabled via attribute', function (assert) { + assert.expect(1) + var dropdownHTML = + '' + $(dropdownHTML).appendTo('#qunit-fixture') + var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown() + $dropdown.show() + assert.ok(!$dropdown.parent('.dropdown').hasClass('show')) + }) + + QUnit.test('should not open dropdown via show method if target is disabled via class', function (assert) { + assert.expect(1) + var dropdownHTML = + '' + + $(dropdownHTML).appendTo('#qunit-fixture') + var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown() + $dropdown.show() + assert.ok(!$dropdown.parent('.dropdown').hasClass('show')) + }) + + QUnit.test('should not hide dropdown via hide method if target is disabled via attribute', function (assert) { + assert.expect(1) + var dropdownHTML = + '' + $(dropdownHTML).appendTo('#qunit-fixture') + var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown() + $dropdown.hide() + assert.ok($dropdown.parent('.dropdown').hasClass('show')) + }) + + QUnit.test('should not hide dropdown via hide method if target is disabled via class', function (assert) { + assert.expect(1) + var dropdownHTML = + '' + + $(dropdownHTML).appendTo('#qunit-fixture') + var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown() + $dropdown.hide() + assert.ok($dropdown.parent('.dropdown').hasClass('show')) + }) }) From 78a8af1e826ef4dafd77eba282680159cdc417f9 Mon Sep 17 00:00:00 2001 From: galczo5 Date: Thu, 18 Oct 2018 21:11:31 +0200 Subject: [PATCH 4/5] Refactored isActive in dropdown.js --- js/src/dropdown.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 3e13deb59275..e52c51e4db75 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -195,11 +195,7 @@ class Dropdown { } show() { - if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { - return - } - const isActive = $(this._menu).hasClass(ClassName.SHOW) - if (isActive) { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || $(this._menu).hasClass(ClassName.SHOW)) { return } @@ -222,12 +218,7 @@ class Dropdown { } hide() { - if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { - return - } - - const isActive = $(this._menu).hasClass(ClassName.SHOW) - if (!isActive) { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || !$(this._menu).hasClass(ClassName.SHOW)) { return } From b2a75f6736fa08a6fc3989a3e0454ca3c4665e57 Mon Sep 17 00:00:00 2001 From: galczo5 Date: Sat, 20 Oct 2018 11:41:04 +0200 Subject: [PATCH 5/5] Added description of show/hide methods in dropdowns.md --- site/docs/4.1/components/dropdowns.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/docs/4.1/components/dropdowns.md b/site/docs/4.1/components/dropdowns.md index 9adfa499bc33..d82b4d63fe88 100644 --- a/site/docs/4.1/components/dropdowns.md +++ b/site/docs/4.1/components/dropdowns.md @@ -839,6 +839,8 @@ Note when `boundary` is set to any value other than `'scrollParent'`, the style | Method | Description | | --- | --- | | `$().dropdown('toggle')` | Toggles the dropdown menu of a given navbar or tabbed navigation. | +| `$().dropdown('show')` | Shows the dropdown menu of a given navbar or tabbed navigation. | +| `$().dropdown('hide')` | Hides the dropdown menu of a given navbar or tabbed navigation. | | `$().dropdown('update')` | Updates the position of an element's dropdown. | | `$().dropdown('dispose')` | Destroys an element's dropdown. |