Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorGeoSot <geo.sotis@gmail.com>2021-03-23 09:22:59 +0300
committerGitHub <noreply@github.com>2021-03-23 09:22:59 +0300
commit1c02ef4f971afe5df75d4e1889435f3edd9f2bbd (patch)
treebb36fd300edd2b90e435f53b0b13e5fd8f29df3e /js
parentd9da43f3cc9daaa6050685687416f3abd3ee25eb (diff)
Allow offcanvas to be initialized in open state (#33382)
* Update docs to use new .show behavior and clarify some copy for first example Co-authored-by: Mark Otto <markdotto@gmail.com> Co-authored-by: XhmikosR <xhmikosr@gmail.com>
Diffstat (limited to 'js')
-rw-r--r--js/src/offcanvas.js10
-rw-r--r--js/tests/unit/offcanvas.spec.js138
2 files changed, 139 insertions, 9 deletions
diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js
index 4b98565e2c..1824b3e3b4 100644
--- a/js/src/offcanvas.js
+++ b/js/src/offcanvas.js
@@ -31,6 +31,7 @@ const NAME = 'offcanvas'
const DATA_KEY = 'bs.offcanvas'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
+const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
const ESCAPE_KEY = 'Escape'
const Default = {
@@ -48,7 +49,8 @@ const DefaultType = {
const CLASS_NAME_BACKDROP_BODY = 'offcanvas-backdrop'
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_TOGGLING = 'offcanvas-toggling'
-const ACTIVE_SELECTOR = `.offcanvas.show, .${CLASS_NAME_TOGGLING}`
+const OPEN_SELECTOR = '.offcanvas.show'
+const ACTIVE_SELECTOR = `${OPEN_SELECTOR}, .${CLASS_NAME_TOGGLING}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
@@ -72,7 +74,7 @@ class Offcanvas extends BaseComponent {
super(element)
this._config = this._getConfig(config)
- this._isShown = element.classList.contains(CLASS_NAME_SHOW)
+ this._isShown = false
this._addEventListeners()
}
@@ -262,6 +264,10 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
data.toggle(this)
})
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+ SelectorEngine.find(OPEN_SELECTOR).forEach(el => (Data.get(el, DATA_KEY) || new Offcanvas(el)).show())
+})
+
/**
* ------------------------------------------------------------------------
* jQuery
diff --git a/js/tests/unit/offcanvas.spec.js b/js/tests/unit/offcanvas.spec.js
index 4fb6c17ecb..0122d4dff3 100644
--- a/js/tests/unit/offcanvas.spec.js
+++ b/js/tests/unit/offcanvas.spec.js
@@ -145,6 +145,44 @@ describe('Offcanvas', () => {
expect(offCanvas._config.scroll).toEqual(false)
})
})
+ describe('options', () => {
+ it('if scroll is enabled, should allow body to scroll while offcanvas is open', done => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
+
+ const offCanvasEl = fixtureEl.querySelector('.offcanvas')
+ const offCanvas = new Offcanvas(offCanvasEl, { scroll: true })
+ const initialOverFlow = document.body.style.overflow
+
+ offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+ expect(document.body.style.overflow).toEqual(initialOverFlow)
+
+ offCanvas.hide()
+ })
+ offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
+ expect(document.body.style.overflow).toEqual(initialOverFlow)
+ done()
+ })
+ offCanvas.show()
+ })
+
+ it('if scroll is disabled, should not allow body to scroll while offcanvas is open', done => {
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
+
+ const offCanvasEl = fixtureEl.querySelector('.offcanvas')
+ const offCanvas = new Offcanvas(offCanvasEl, { scroll: false })
+
+ offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+ expect(document.body.style.overflow).toEqual('hidden')
+
+ offCanvas.hide()
+ })
+ offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
+ expect(document.body.style.overflow).toEqual('auto')
+ done()
+ })
+ offCanvas.show()
+ })
+ })
describe('toggle', () => {
it('should call show method if show class is not present', () => {
@@ -161,10 +199,12 @@ describe('Offcanvas', () => {
})
it('should call hide method if show class is present', () => {
- fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- const offCanvasEl = fixtureEl.querySelector('.show')
+ const offCanvasEl = fixtureEl.querySelector('.offcanvas')
const offCanvas = new Offcanvas(offCanvasEl)
+ offCanvas.show()
+ expect(offCanvasEl.classList.contains('show')).toBe(true)
spyOn(offCanvas, 'hide')
@@ -178,12 +218,14 @@ describe('Offcanvas', () => {
it('should do nothing if already shown', () => {
fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
- spyOn(EventHandler, 'trigger')
-
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl)
offCanvas.show()
+ expect(offCanvasEl.classList.contains('show')).toBe(true)
+
+ spyOn(EventHandler, 'trigger').and.callThrough()
+ offCanvas.show()
expect(EventHandler.trigger).not.toHaveBeenCalled()
})
@@ -226,13 +268,30 @@ describe('Offcanvas', () => {
offCanvas.show()
})
+
+ it('on window load, should make visible an offcanvas element, if its markup contains class "show"', done => {
+ fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
+
+ const offCanvasEl = fixtureEl.querySelector('div')
+ spyOn(Offcanvas.prototype, 'show').and.callThrough()
+
+ offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+ done()
+ })
+
+ window.dispatchEvent(createEvent('load'))
+
+ const instance = Offcanvas.getInstance(offCanvasEl)
+ expect(instance).not.toBeNull()
+ expect(Offcanvas.prototype.show).toHaveBeenCalled()
+ })
})
describe('hide', () => {
it('should do nothing if already shown', () => {
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
- spyOn(EventHandler, 'trigger')
+ spyOn(EventHandler, 'trigger').and.callThrough()
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl)
@@ -243,10 +302,11 @@ describe('Offcanvas', () => {
})
it('should hide a shown element', done => {
- fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl)
+ offCanvas.show()
offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
expect(offCanvasEl.classList.contains('show')).toEqual(false)
@@ -257,10 +317,11 @@ describe('Offcanvas', () => {
})
it('should not fire hidden when hide is prevented', done => {
- fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
+ fixtureEl.innerHTML = '<div class="offcanvas"></div>'
const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl)
+ offCanvas.show()
const expectEnd = () => {
setTimeout(() => {
@@ -315,6 +376,52 @@ describe('Offcanvas', () => {
expect(Offcanvas.prototype.toggle).not.toHaveBeenCalled()
})
+
+ it('should not call toggle if another offcanvas is open', done => {
+ fixtureEl.innerHTML = [
+ '<button id="btn2" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2" ></button>',
+ '<div id="offcanvas1" class="offcanvas"></div>',
+ '<div id="offcanvas2" class="offcanvas"></div>'
+ ].join('')
+
+ const trigger2 = fixtureEl.querySelector('#btn2')
+ const offcanvasEl1 = document.querySelector('#offcanvas1')
+ const offcanvasEl2 = document.querySelector('#offcanvas2')
+ const offcanvas1 = new Offcanvas(offcanvasEl1)
+
+ offcanvasEl1.addEventListener('shown.bs.offcanvas', () => {
+ trigger2.click()
+ })
+ offcanvasEl1.addEventListener('hidden.bs.offcanvas', () => {
+ expect(Offcanvas.getInstance(offcanvasEl2)).toEqual(null)
+ done()
+ })
+ offcanvas1.show()
+ })
+
+ it('should focus on trigger element after closing offcanvas', done => {
+ fixtureEl.innerHTML = [
+ '<button id="btn" data-bs-toggle="offcanvas" data-bs-target="#offcanvas" ></button>',
+ '<div id="offcanvas" class="offcanvas"></div>'
+ ].join('')
+
+ const trigger = fixtureEl.querySelector('#btn')
+ const offcanvasEl = fixtureEl.querySelector('#offcanvas')
+ const offcanvas = new Offcanvas(offcanvasEl)
+ spyOn(trigger, 'focus')
+
+ offcanvasEl.addEventListener('shown.bs.offcanvas', () => {
+ offcanvas.hide()
+ })
+ offcanvasEl.addEventListener('hidden.bs.offcanvas', () => {
+ setTimeout(() => {
+ expect(trigger.focus).toHaveBeenCalled()
+ done()
+ }, 5)
+ })
+
+ trigger.click()
+ })
})
describe('jQueryInterface', () => {
@@ -432,6 +539,23 @@ describe('Offcanvas', () => {
jQueryMock.fn.offcanvas.call(jQueryMock, 'show')
expect(Offcanvas.prototype.show).toHaveBeenCalled()
})
+
+ it('should create a offcanvas with given config', () => {
+ fixtureEl.innerHTML = '<div></div>'
+
+ const div = fixtureEl.querySelector('div')
+
+ jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
+ jQueryMock.elements = [div]
+
+ jQueryMock.fn.offcanvas.call(jQueryMock, { scroll: true })
+ spyOn(Offcanvas.prototype, 'constructor')
+ expect(Offcanvas.prototype.constructor).not.toHaveBeenCalledWith(div, { scroll: true })
+
+ const offcanvas = Offcanvas.getInstance(div)
+ expect(offcanvas).toBeDefined()
+ expect(offcanvas._config.scroll).toBe(true)
+ })
})
describe('getInstance', () => {