mirror of
https://github.com/twbs/bootstrap.git
synced 2025-10-04 00:02:43 -04:00
feature(modal): add dynamic config
- adds the ability to change the configuration settings of the modal window during script execution - adds tests for new functionality
This commit is contained in:
parent
a360960b8d
commit
9c526253b4
@ -12,7 +12,7 @@ import Backdrop from './util/backdrop.js'
|
||||
import { enableDismissTrigger } from './util/component-functions.js'
|
||||
import FocusTrap from './util/focustrap.js'
|
||||
import {
|
||||
defineJQueryPlugin, isRTL, isVisible, reflow
|
||||
defineJQueryPlugin, execute, isRTL, isVisible, reflow
|
||||
} from './util/index.js'
|
||||
import ScrollBarHelper from './util/scrollbar.js'
|
||||
|
||||
@ -54,9 +54,9 @@ const Default = {
|
||||
}
|
||||
|
||||
const DefaultType = {
|
||||
backdrop: '(boolean|string)',
|
||||
focus: 'boolean',
|
||||
keyboard: 'boolean'
|
||||
backdrop: '(boolean|string|function)',
|
||||
focus: '(boolean|function)',
|
||||
keyboard: '(boolean|function)'
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,7 +157,7 @@ class Modal extends BaseComponent {
|
||||
// Private
|
||||
_initializeBackDrop() {
|
||||
return new Backdrop({
|
||||
isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,
|
||||
isVisible: Boolean(this._resolvePossibleFunction(this._config.backdrop)), // 'static' option will be translated to true, and booleans will keep their value
|
||||
isAnimated: this._isAnimated()
|
||||
})
|
||||
}
|
||||
@ -190,7 +190,7 @@ class Modal extends BaseComponent {
|
||||
this._element.classList.add(CLASS_NAME_SHOW)
|
||||
|
||||
const transitionComplete = () => {
|
||||
if (this._config.focus) {
|
||||
if (this._resolvePossibleFunction(this._config.focus)) {
|
||||
this._focustrap.activate()
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ class Modal extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._config.keyboard) {
|
||||
if (this._resolvePossibleFunction(this._config.keyboard)) {
|
||||
this.hide()
|
||||
return
|
||||
}
|
||||
@ -230,12 +230,14 @@ class Modal extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._config.backdrop === 'static') {
|
||||
const backdrop = this._resolvePossibleFunction(this._config.backdrop)
|
||||
|
||||
if (backdrop === 'static') {
|
||||
this._triggerBackdropTransition()
|
||||
return
|
||||
}
|
||||
|
||||
if (this._config.backdrop) {
|
||||
if (backdrop) {
|
||||
this.hide()
|
||||
}
|
||||
})
|
||||
@ -314,6 +316,10 @@ class Modal extends BaseComponent {
|
||||
this._element.style.paddingRight = ''
|
||||
}
|
||||
|
||||
_resolvePossibleFunction(arg) {
|
||||
return execute(arg, [this])
|
||||
}
|
||||
|
||||
// Static
|
||||
static jQueryInterface(config, relatedTarget) {
|
||||
return this.each(function () {
|
||||
|
@ -237,6 +237,7 @@ describe('Modal', () => {
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should set is transitioning if fade class is present', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog"></div></div>'
|
||||
@ -550,6 +551,7 @@ describe('Modal', () => {
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should close modal when escape key is pressed with keyboard = true and backdrop is static', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
@ -677,6 +679,44 @@ describe('Modal', () => {
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should call .focus() when config function returns true', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const focusSpy = spyOn(modalEl, 'focus')
|
||||
const modal = new Modal(modalEl, {
|
||||
focus: () => true
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
expect(focusSpy).toHaveBeenCalled()
|
||||
resolve()
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should NOT call .focus() when config function returns false', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const focusSpy = spyOn(modalEl, 'focus')
|
||||
const modal = new Modal(modalEl, {
|
||||
focus: () => false
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
expect(focusSpy).not.toHaveBeenCalled()
|
||||
resolve()
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('hide', () => {
|
||||
@ -766,6 +806,129 @@ describe('Modal', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not close on Escape when "keyboard" option is dynamically changed to false', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const config = { keyboard: 'closing' }
|
||||
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const modal = new Modal(modalEl, {
|
||||
keyboard: () => config.keyboard === 'closing'
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
config.keyboard = 'nothing'
|
||||
|
||||
const keydownEscape = createEvent('keydown')
|
||||
keydownEscape.key = 'Escape'
|
||||
modalEl.dispatchEvent(keydownEscape)
|
||||
|
||||
expect(modal._isShown).toBeTrue()
|
||||
resolve()
|
||||
})
|
||||
|
||||
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||
reject(new Error('Should not hide a modal'))
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should close on Escape when "keyboard" option is dynamically changed to true', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const config = { keyboard: 'nothing' }
|
||||
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const modal = new Modal(modalEl, {
|
||||
keyboard: () => config.keyboard === 'closing'
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
config.keyboard = 'closing'
|
||||
|
||||
const keydownEscape = createEvent('keydown')
|
||||
keydownEscape.key = 'Escape'
|
||||
modalEl.dispatchEvent(keydownEscape)
|
||||
})
|
||||
|
||||
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||
resolve()
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should close by backdrop click when option dynamically changed to true', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const config = { backdrop: 'static' }
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const modal = new Modal(modalEl, {
|
||||
backdrop: () => config.backdrop
|
||||
})
|
||||
|
||||
const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough()
|
||||
EventHandler.one(modalEl, 'click', () => {
|
||||
if (config.backdrop === false) {
|
||||
modal.hide()
|
||||
}
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
config.backdrop = false
|
||||
|
||||
modalEl.click()
|
||||
})
|
||||
|
||||
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||
expect(backdropSpy).toHaveBeenCalled()
|
||||
resolve()
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not close by backdrop click when option dynamically changed to "static"', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
const config = { backdrop: false }
|
||||
const modalEl = fixtureEl.querySelector('.modal')
|
||||
const modal = new Modal(modalEl, {
|
||||
backdrop: () => config.backdrop
|
||||
})
|
||||
|
||||
const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough()
|
||||
EventHandler.one(modalEl, 'click', () => {
|
||||
if (config.backdrop === false) {
|
||||
modal.hide()
|
||||
}
|
||||
})
|
||||
|
||||
modalEl.addEventListener('shown.bs.modal', () => {
|
||||
config.backdrop = 'static'
|
||||
|
||||
modalEl.click()
|
||||
|
||||
expect(backdropSpy).not.toHaveBeenCalled()
|
||||
resolve()
|
||||
})
|
||||
|
||||
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||
reject(new Error('Should not hide a modal'))
|
||||
})
|
||||
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should do nothing is the modal is not shown', () => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
||||
@ -1077,6 +1240,7 @@ describe('Modal', () => {
|
||||
modal.show()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not focus the trigger if the modal is not visible', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = [
|
||||
@ -1109,6 +1273,7 @@ describe('Modal', () => {
|
||||
trigger.click()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not focus the trigger if the modal is not shown', () => {
|
||||
return new Promise(resolve => {
|
||||
fixtureEl.innerHTML = [
|
||||
@ -1162,6 +1327,7 @@ describe('Modal', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('jQueryInterface', () => {
|
||||
it('should create a modal', () => {
|
||||
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
|
||||
|
Loading…
x
Reference in New Issue
Block a user