aboutsummaryrefslogtreecommitdiff
path: root/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'js/src')
-rw-r--r--js/src/.eslintrc.json14
-rw-r--r--js/src/alert.js (renamed from js/src/alert/alert.js)8
-rw-r--r--js/src/alert/alert.spec.js173
-rw-r--r--js/src/button.js (renamed from js/src/button/button.js)8
-rw-r--r--js/src/button/button.spec.js292
-rw-r--r--js/src/carousel.js (renamed from js/src/carousel/carousel.js)10
-rw-r--r--js/src/carousel/carousel.spec.js1201
-rw-r--r--js/src/collapse.js (renamed from js/src/collapse/collapse.js)10
-rw-r--r--js/src/collapse/collapse.spec.js826
-rw-r--r--js/src/dom/data.spec.js131
-rw-r--r--js/src/dom/event-handler.spec.js327
-rw-r--r--js/src/dom/manipulator.spec.js158
-rw-r--r--js/src/dom/selector-engine.spec.js115
-rw-r--r--js/src/dropdown.js (renamed from js/src/dropdown/dropdown.js)10
-rw-r--r--js/src/dropdown/dropdown.spec.js1564
-rw-r--r--js/src/modal.js (renamed from js/src/modal/modal.js)10
-rw-r--r--js/src/modal/modal.spec.js987
-rw-r--r--js/src/popover.js (renamed from js/src/popover/popover.js)8
-rw-r--r--js/src/popover/popover.spec.js251
-rw-r--r--js/src/scrollspy.js (renamed from js/src/scrollspy/scrollspy.js)10
-rw-r--r--js/src/scrollspy/scrollspy.spec.js653
-rw-r--r--js/src/tab.js (renamed from js/src/tab/tab.js)8
-rw-r--r--js/src/tab/tab.spec.js593
-rw-r--r--js/src/toast.js (renamed from js/src/toast/toast.js)8
-rw-r--r--js/src/toast/toast.spec.js374
-rw-r--r--js/src/tooltip.js (renamed from js/src/tooltip/tooltip.js)12
-rw-r--r--js/src/tooltip/tooltip.spec.js1020
-rw-r--r--js/src/util/index.spec.js382
-rw-r--r--js/src/util/sanitizer.spec.js70
29 files changed, 51 insertions, 9182 deletions
diff --git a/js/src/.eslintrc.json b/js/src/.eslintrc.json
deleted file mode 100644
index 18ffdc003..000000000
--- a/js/src/.eslintrc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "root": true,
- "extends": [
- "../../.eslintrc.json"
- ],
- "overrides": [
- {
- "files": ["**/*.spec.js"],
- "env": {
- "jasmine": true
- }
- }
- ]
-}
diff --git a/js/src/alert/alert.js b/js/src/alert.js
index 024528b81..dbd931b52 100644
--- a/js/src/alert/alert.js
+++ b/js/src/alert.js
@@ -11,10 +11,10 @@ import {
emulateTransitionEnd,
getElementFromSelector,
getTransitionDurationFromElement
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/alert/alert.spec.js b/js/src/alert/alert.spec.js
deleted file mode 100644
index 61d656bd0..000000000
--- a/js/src/alert/alert.spec.js
+++ /dev/null
@@ -1,173 +0,0 @@
-import Alert from './alert'
-import { makeArray, getTransitionDurationFromElement } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Alert', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- it('should return version', () => {
- expect(typeof Alert.VERSION).toEqual('string')
- })
-
- describe('data-api', () => {
- it('should close an alert without instantiate it manually', () => {
- fixtureEl.innerHTML = [
- '<div class="alert">',
- ' <button type="button" data-dismiss="alert">x</button>',
- '</div>'
- ].join('')
-
- const button = document.querySelector('button')
-
- button.click()
- expect(makeArray(document.querySelectorAll('.alert')).length).toEqual(0)
- })
-
- it('should close an alert without instantiate it manually with the parent selector', () => {
- fixtureEl.innerHTML = [
- '<div class="alert">',
- ' <button type="button" data-target=".alert" data-dismiss="alert">x</button>',
- '</div>'
- ].join('')
-
- const button = document.querySelector('button')
-
- button.click()
- expect(makeArray(document.querySelectorAll('.alert')).length).toEqual(0)
- })
- })
-
- describe('close', () => {
- it('should close an alert', done => {
- const spy = jasmine.createSpy('spy', getTransitionDurationFromElement)
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = document.querySelector('.alert')
- const alert = new Alert(alertEl)
-
- alertEl.addEventListener('closed.bs.alert', () => {
- expect(makeArray(document.querySelectorAll('.alert')).length).toEqual(0)
- expect(spy).not.toHaveBeenCalled()
- done()
- })
-
- alert.close()
- })
-
- it('should close alert with fade class', done => {
- fixtureEl.innerHTML = '<div class="alert fade"></div>'
-
- const alertEl = document.querySelector('.alert')
- const alert = new Alert(alertEl)
-
- alertEl.addEventListener('transitionend', () => {
- expect().nothing()
- })
-
- alertEl.addEventListener('closed.bs.alert', () => {
- expect(makeArray(document.querySelectorAll('.alert')).length).toEqual(0)
- done()
- })
-
- alert.close()
- })
-
- it('should not remove alert if close event is prevented', done => {
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = document.querySelector('.alert')
- const alert = new Alert(alertEl)
-
- const endTest = () => {
- setTimeout(() => {
- expect(alert._removeElement).not.toHaveBeenCalled()
- done()
- }, 10)
- }
-
- spyOn(alert, '_removeElement')
-
- alertEl.addEventListener('close.bs.alert', event => {
- event.preventDefault()
- endTest()
- })
-
- alertEl.addEventListener('closed.bs.alert', () => {
- endTest()
- })
-
- alert.close()
- })
- })
-
- describe('dispose', () => {
- it('should dispose an alert', () => {
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = document.querySelector('.alert')
- const alert = new Alert(alertEl)
-
- expect(Alert.getInstance(alertEl)).toBeDefined()
-
- alert.dispose()
-
- expect(Alert.getInstance(alertEl)).toBeNull()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should handle config passed and toggle existing alert', () => {
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = fixtureEl.querySelector('.alert')
- const alert = new Alert(alertEl)
-
- spyOn(alert, 'close')
-
- jQueryMock.fn.alert = Alert.jQueryInterface
- jQueryMock.elements = [alertEl]
-
- jQueryMock.fn.alert.call(jQueryMock, 'close')
-
- expect(alert.close).toHaveBeenCalled()
- })
-
- it('should create new alert instance and call close', () => {
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = fixtureEl.querySelector('.alert')
-
- jQueryMock.fn.alert = Alert.jQueryInterface
- jQueryMock.elements = [alertEl]
-
- jQueryMock.fn.alert.call(jQueryMock, 'close')
-
- expect(Alert.getInstance(alertEl)).toBeDefined()
- expect(fixtureEl.querySelector('.alert')).toBeNull()
- })
-
- it('should just create an alert instance without calling close', () => {
- fixtureEl.innerHTML = '<div class="alert"></div>'
-
- const alertEl = fixtureEl.querySelector('.alert')
-
- jQueryMock.fn.alert = Alert.jQueryInterface
- jQueryMock.elements = [alertEl]
-
- jQueryMock.fn.alert.call(jQueryMock)
-
- expect(Alert.getInstance(alertEl)).toBeDefined()
- expect(fixtureEl.querySelector('.alert')).not.toBeNull()
- })
- })
-})
diff --git a/js/src/button/button.js b/js/src/button.js
index 4418ba6b8..6edd5cb64 100644
--- a/js/src/button/button.js
+++ b/js/src/button.js
@@ -5,10 +5,10 @@
* --------------------------------------------------------------------------
*/
-import { getjQuery } from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import SelectorEngine from '../dom/selector-engine'
+import { getjQuery } from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/button/button.spec.js b/js/src/button/button.spec.js
deleted file mode 100644
index 622881185..000000000
--- a/js/src/button/button.spec.js
+++ /dev/null
@@ -1,292 +0,0 @@
-import Button from './button'
-import EventHandler from '../dom/event-handler'
-
-/** Test helpers */
-import {
- getFixture,
- clearFixture,
- createEvent,
- jQueryMock
-} from '../../tests/helpers/fixture'
-
-describe('Button', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Button.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('data-api', () => {
- it('should toggle active class on click', () => {
- fixtureEl.innerHTML = [
- '<button class="btn" data-toggle="button">btn</button>',
- '<button class="btn testParent" data-toggle="button"><div class="test"></div></button>'
- ].join('')
-
- const btn = fixtureEl.querySelector('.btn')
- const divTest = fixtureEl.querySelector('.test')
- const btnTestParent = fixtureEl.querySelector('.testParent')
-
- expect(btn.classList.contains('active')).toEqual(false)
-
- btn.click()
-
- expect(btn.classList.contains('active')).toEqual(true)
-
- btn.click()
-
- expect(btn.classList.contains('active')).toEqual(false)
-
- divTest.click()
-
- expect(btnTestParent.classList.contains('active')).toEqual(true)
- })
-
- it('should trigger input change event when toggled button has input field', done => {
- fixtureEl.innerHTML = [
- '<div class="btn-group" data-toggle="buttons">',
- ' <label class="btn btn-primary">',
- ' <input type="radio" id="radio" autocomplete="off"> Radio',
- ' </label>',
- '</div>'
- ].join('')
-
- const input = fixtureEl.querySelector('input')
- const label = fixtureEl.querySelector('label')
-
- input.addEventListener('change', () => {
- expect().nothing()
- done()
- })
-
- label.click()
- })
-
- it('should not trigger input change event when input already checked and button is active', () => {
- fixtureEl.innerHTML = [
- '<button type="button" class="btn btn-primary active" data-toggle="buttons">',
- ' <input type="radio" id="radio" autocomplete="off" checked> Radio',
- '</button>'
- ].join('')
-
- const button = fixtureEl.querySelector('button')
-
- spyOn(EventHandler, 'trigger')
-
- button.click()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should remove active when an other radio button is clicked', () => {
- fixtureEl.innerHTML = [
- '<div class="btn-group btn-group-toggle" data-toggle="buttons">',
- ' <label class="btn btn-secondary active">',
- ' <input type="radio" name="options" id="option1" autocomplete="off" checked> Active',
- ' </label>',
- ' <label class="btn btn-secondary">',
- ' <input type="radio" name="options" id="option2" autocomplete="off"> Radio',
- ' </label>',
- ' <label class="btn btn-secondary">',
- ' <input type="radio" name="options" id="option3" autocomplete="off"> Radio',
- ' </label>',
- '</div>'
- ].join('')
-
- const option1 = fixtureEl.querySelector('#option1')
- const option2 = fixtureEl.querySelector('#option2')
-
- expect(option1.checked).toEqual(true)
- expect(option1.parentElement.classList.contains('active')).toEqual(true)
-
- const clickEvent = createEvent('click')
-
- option2.dispatchEvent(clickEvent)
-
- expect(option1.checked).toEqual(false)
- expect(option1.parentElement.classList.contains('active')).toEqual(false)
- expect(option2.checked).toEqual(true)
- expect(option2.parentElement.classList.contains('active')).toEqual(true)
- })
-
- it('should do nothing if the child is not an input', () => {
- fixtureEl.innerHTML = [
- '<div class="btn-group btn-group-toggle" data-toggle="buttons">',
- ' <label class="btn btn-secondary active">',
- ' <span id="option1">el 1</span>',
- ' </label>',
- ' <label class="btn btn-secondary">',
- ' <span id="option2">el 2</span>',
- ' </label>',
- ' <label class="btn btn-secondary">',
- ' <span>el 3</span>',
- ' </label>',
- '</div>'
- ].join('')
-
- const option2 = fixtureEl.querySelector('#option2')
- const clickEvent = createEvent('click')
-
- option2.dispatchEvent(clickEvent)
-
- expect().nothing()
- })
-
- it('should add focus class on focus event', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button"><input type="text" /></button>'
-
- const btn = fixtureEl.querySelector('.btn')
- const input = fixtureEl.querySelector('input')
-
- const focusEvent = createEvent('focus')
- input.dispatchEvent(focusEvent)
-
- expect(btn.classList.contains('focus')).toEqual(true)
- })
-
- it('should not add focus class', () => {
- fixtureEl.innerHTML = '<button data-toggle="button"><input type="text" /></button>'
-
- const btn = fixtureEl.querySelector('button')
- const input = fixtureEl.querySelector('input')
-
- const focusEvent = createEvent('focus')
- input.dispatchEvent(focusEvent)
-
- expect(btn.classList.contains('focus')).toEqual(false)
- })
-
- it('should remove focus class on blur event', () => {
- fixtureEl.innerHTML = '<button class="btn focus" data-toggle="button"><input type="text" /></button>'
-
- const btn = fixtureEl.querySelector('.btn')
- const input = fixtureEl.querySelector('input')
-
- const focusEvent = createEvent('blur')
- input.dispatchEvent(focusEvent)
-
- expect(btn.classList.contains('focus')).toEqual(false)
- })
-
- it('should not remove focus class on blur event', () => {
- fixtureEl.innerHTML = '<button class="focus" data-toggle="button"><input type="text" /></button>'
-
- const btn = fixtureEl.querySelector('button')
- const input = fixtureEl.querySelector('input')
-
- const focusEvent = createEvent('blur')
- input.dispatchEvent(focusEvent)
-
- expect(btn.classList.contains('focus')).toEqual(true)
- })
- })
-
- describe('toggle', () => {
- it('should toggle aria-pressed', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button" aria-pressed="false"></button>'
-
- const btnEl = fixtureEl.querySelector('.btn')
- const button = new Button(btnEl)
-
- expect(btnEl.getAttribute('aria-pressed')).toEqual('false')
- expect(btnEl.classList.contains('active')).toEqual(false)
-
- button.toggle()
-
- expect(btnEl.getAttribute('aria-pressed')).toEqual('true')
- expect(btnEl.classList.contains('active')).toEqual(true)
- })
-
- it('should handle disabled attribute on non-button elements', () => {
- fixtureEl.innerHTML = [
- '<div class="btn-group disabled" data-toggle="buttons" aria-disabled="true" disabled>',
- ' <label class="btn btn-danger disabled" aria-disabled="true" disabled>',
- ' <input type="checkbox" aria-disabled="true" autocomplete="off" disabled class="disabled"/>',
- ' </label>',
- '</div>'
- ].join('')
-
- const btnGroupEl = fixtureEl.querySelector('.btn-group')
- const btnDanger = fixtureEl.querySelector('.btn-danger')
- const input = fixtureEl.querySelector('input')
-
- const button = new Button(btnGroupEl)
-
- button.toggle()
-
- expect(btnDanger.hasAttribute('disabled')).toEqual(true)
- expect(input.checked).toEqual(false)
- })
- })
-
- describe('dispose', () => {
- it('should dispose a button', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button"></button>'
-
- const btnEl = fixtureEl.querySelector('.btn')
- const button = new Button(btnEl)
-
- expect(Button.getInstance(btnEl)).toBeDefined()
-
- button.dispose()
-
- expect(Button.getInstance(btnEl)).toBeNull()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should handle config passed and toggle existing button', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button"></button>'
-
- const btnEl = fixtureEl.querySelector('.btn')
- const button = new Button(btnEl)
-
- spyOn(button, 'toggle')
-
- jQueryMock.fn.button = Button.jQueryInterface
- jQueryMock.elements = [btnEl]
-
- jQueryMock.fn.button.call(jQueryMock, 'toggle')
-
- expect(button.toggle).toHaveBeenCalled()
- })
-
- it('should create new button instance and call toggle', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button"></button>'
-
- const btnEl = fixtureEl.querySelector('.btn')
-
- jQueryMock.fn.button = Button.jQueryInterface
- jQueryMock.elements = [btnEl]
-
- jQueryMock.fn.button.call(jQueryMock, 'toggle')
-
- expect(Button.getInstance(btnEl)).toBeDefined()
- expect(btnEl.classList.contains('active')).toEqual(true)
- })
-
- it('should just create a button instance without calling toggle', () => {
- fixtureEl.innerHTML = '<button class="btn" data-toggle="button"></button>'
-
- const btnEl = fixtureEl.querySelector('.btn')
-
- jQueryMock.fn.button = Button.jQueryInterface
- jQueryMock.elements = [btnEl]
-
- jQueryMock.fn.button.call(jQueryMock)
-
- expect(Button.getInstance(btnEl)).toBeDefined()
- expect(btnEl.classList.contains('active')).toEqual(false)
- })
- })
-})
diff --git a/js/src/carousel/carousel.js b/js/src/carousel.js
index 723bf57c6..5034f1798 100644
--- a/js/src/carousel/carousel.js
+++ b/js/src/carousel.js
@@ -16,11 +16,11 @@ import {
reflow,
triggerTransitionEnd,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/carousel/carousel.spec.js b/js/src/carousel/carousel.spec.js
deleted file mode 100644
index 4c13b6d22..000000000
--- a/js/src/carousel/carousel.spec.js
+++ /dev/null
@@ -1,1201 +0,0 @@
-import Carousel from './carousel'
-import EventHandler from '../dom/event-handler'
-
-/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Carousel', () => {
- const { Simulator, PointerEvent, MSPointerEvent } = window
- const originWinPointerEvent = PointerEvent || MSPointerEvent
- const supportPointerEvent = Boolean(PointerEvent || MSPointerEvent)
-
- window.MSPointerEvent = null
- const cssStyleCarousel = '.carousel.pointer-event { -ms-touch-action: none; touch-action: none; }'
-
- const stylesCarousel = document.createElement('style')
- stylesCarousel.type = 'text/css'
- stylesCarousel.appendChild(document.createTextNode(cssStyleCarousel))
-
- const clearPointerEvents = () => {
- window.PointerEvent = null
- }
-
- const restorePointerEvents = () => {
- window.PointerEvent = originWinPointerEvent
- }
-
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Carousel.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Carousel.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('constructor', () => {
- it('should go to next item if right arrow key is pressed', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {
- keyboard: true
- })
-
- spyOn(carousel, '_keydown').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2'))
- expect(carousel._keydown).toHaveBeenCalled()
- done()
- })
-
- const keyDown = createEvent('keydown')
- keyDown.which = 39
-
- carouselEl.dispatchEvent(keyDown)
- })
-
- it('should go to previous item if left arrow key is pressed', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="item1" class="carousel-item">item 1</div>',
- ' <div class="carousel-item active">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {
- keyboard: true
- })
-
- spyOn(carousel, '_keydown').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1'))
- expect(carousel._keydown).toHaveBeenCalled()
- done()
- })
-
- const keyDown = createEvent('keydown')
- keyDown.which = 37
-
- carouselEl.dispatchEvent(keyDown)
- })
-
- it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {
- keyboard: true
- })
-
- spyOn(carousel, '_keydown').and.callThrough()
-
- carouselEl.addEventListener('keydown', event => {
- expect(carousel._keydown).toHaveBeenCalled()
- expect(event.defaultPrevented).toEqual(false)
- done()
- })
-
- const keyDown = createEvent('keydown')
- keyDown.which = 40
-
- carouselEl.dispatchEvent(keyDown)
- })
-
- it('should ignore keyboard events within <input>s and <textarea>s', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">',
- ' <input type="text" />',
- ' <textarea></textarea>',
- ' </div>',
- ' <div class="carousel-item"></div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const input = fixtureEl.querySelector('input')
- const textarea = fixtureEl.querySelector('textarea')
- const carousel = new Carousel(carouselEl, {
- keyboard: true
- })
-
- const spyKeyDown = spyOn(carousel, '_keydown').and.callThrough()
- const spyPrev = spyOn(carousel, 'prev')
- const spyNext = spyOn(carousel, 'next')
-
- const keyDown = createEvent('keydown', { bubbles: true, cancelable: true })
- keyDown.which = 39
- Object.defineProperty(keyDown, 'target', {
- value: input,
- writable: true,
- configurable: true
- })
-
- input.dispatchEvent(keyDown)
-
- expect(spyKeyDown).toHaveBeenCalled()
- expect(spyPrev).not.toHaveBeenCalled()
- expect(spyNext).not.toHaveBeenCalled()
-
- spyKeyDown.calls.reset()
- spyPrev.calls.reset()
- spyNext.calls.reset()
-
- Object.defineProperty(keyDown, 'target', {
- value: textarea
- })
- textarea.dispatchEvent(keyDown)
-
- expect(spyKeyDown).toHaveBeenCalled()
- expect(spyPrev).not.toHaveBeenCalled()
- expect(spyNext).not.toHaveBeenCalled()
- })
-
- it('should wrap around from end to start when wrap option is true', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="one" class="carousel-item active"></div>',
- ' <div id="two" class="carousel-item"></div>',
- ' <div id="three" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, { wrap: true })
- const getActiveId = () => {
- return carouselEl.querySelector('.carousel-item.active').getAttribute('id')
- }
-
- carouselEl.addEventListener('slid.bs.carousel', e => {
- const activeId = getActiveId()
-
- if (activeId === 'two') {
- carousel.next()
- return
- }
-
- if (activeId === 'three') {
- carousel.next()
- return
- }
-
- if (activeId === 'one') {
- // carousel wrapped around and slid from 3rd to 1st slide
- expect(activeId).toEqual('one')
- expect(e.from + 1).toEqual(3)
- done()
- }
- })
-
- carousel.next()
- })
-
- it('should stay at the start when the prev method is called and wrap is false', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="one" class="carousel-item active"></div>',
- ' <div id="two" class="carousel-item"></div>',
- ' <div id="three" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const firstElement = fixtureEl.querySelector('#one')
- const carousel = new Carousel(carouselEl, { wrap: false })
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- throw new Error('carousel slid when it should not have slid')
- })
-
- carousel.prev()
-
- setTimeout(() => {
- expect(firstElement.classList.contains('active')).toEqual(true)
- done()
- }, 10)
- })
-
- it('should not add touch event listeners if touch = false', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
-
- spyOn(Carousel.prototype, '_addTouchEventListeners')
-
- const carousel = new Carousel(carouselEl, {
- touch: false
- })
-
- expect(carousel._addTouchEventListeners).not.toHaveBeenCalled()
- })
-
- it('should not add touch event listeners if touch supported = false', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
-
- const carousel = new Carousel(carouselEl)
-
- EventHandler.off(carouselEl, '.bs-carousel')
- carousel._touchSupported = false
-
- spyOn(carousel, '_addTouchEventListeners')
-
- carousel._addEventListeners()
-
- expect(carousel._addTouchEventListeners).not.toHaveBeenCalled()
- })
-
- it('should add touch event listeners by default', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
-
- spyOn(Carousel.prototype, '_addTouchEventListeners')
-
- document.documentElement.ontouchstart = () => {}
- const carousel = new Carousel(carouselEl)
-
- expect(carousel._addTouchEventListeners).toHaveBeenCalled()
- })
-
- it('should allow swiperight and call prev with pointer events', done => {
- if (!supportPointerEvent) {
- expect().nothing()
- done()
- return
- }
-
- document.documentElement.ontouchstart = () => {}
- document.head.appendChild(stylesCarousel)
- Simulator.setType('pointer')
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'prev').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(item.classList.contains('active')).toEqual(true)
- expect(carousel.prev).toHaveBeenCalled()
- document.head.removeChild(stylesCarousel)
- delete document.documentElement.ontouchstart
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- deltaX: 300,
- deltaY: 0
- })
- })
-
- it('should allow swipeleft and call next with pointer events', done => {
- if (!supportPointerEvent) {
- expect().nothing()
- done()
- return
- }
-
- document.documentElement.ontouchstart = () => {}
- document.head.appendChild(stylesCarousel)
- Simulator.setType('pointer')
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'next').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(item.classList.contains('active')).toEqual(false)
- expect(carousel.next).toHaveBeenCalled()
- document.head.removeChild(stylesCarousel)
- delete document.documentElement.ontouchstart
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0
- })
- })
-
- it('should allow swiperight and call prev with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = () => {}
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'prev').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(item.classList.contains('active')).toEqual(true)
- expect(carousel.prev).toHaveBeenCalled()
- delete document.documentElement.ontouchstart
- restorePointerEvents()
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- deltaX: 300,
- deltaY: 0
- })
- })
-
- it('should allow swipeleft and call next with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = () => {}
-
- fixtureEl.innerHTML = [
- '<div class="carousel" data-interval="false">',
- ' <div class="carousel-inner">',
- ' <div id="item" class="carousel-item active">',
- ' <img alt="">',
- ' </div>',
- ' <div class="carousel-item">',
- ' <img alt="">',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const item = fixtureEl.querySelector('#item')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'next').and.callThrough()
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(item.classList.contains('active')).toEqual(false)
- expect(carousel.next).toHaveBeenCalled()
- delete document.documentElement.ontouchstart
- restorePointerEvents()
- done()
- })
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0
- })
- })
-
- it('should not allow pinch with touch events', done => {
- Simulator.setType('touch')
- clearPointerEvents()
- document.documentElement.ontouchstart = () => {}
-
- fixtureEl.innerHTML = '<div class="carousel" data-interval="false"></div>'
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
-
- Simulator.gestures.swipe(carouselEl, {
- pos: [300, 10],
- deltaX: -300,
- deltaY: 0,
- touches: 2
- }, () => {
- restorePointerEvents()
- delete document.documentElement.ontouchstart
- expect(carousel.touchDeltaX).toEqual(0)
- done()
- })
- })
-
- it('should call pause method on mouse over with pause equal to hover', done => {
- fixtureEl.innerHTML = '<div class="carousel"></div>'
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'pause')
-
- const mouseOverEvent = createEvent('mouseover')
- carouselEl.dispatchEvent(mouseOverEvent)
-
- setTimeout(() => {
- expect(carousel.pause).toHaveBeenCalled()
- done()
- }, 10)
- })
-
- it('should call cycle on mouse out with pause equal to hover', done => {
- fixtureEl.innerHTML = '<div class="carousel"></div>'
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'cycle')
-
- const mouseOutEvent = createEvent('mouseout')
- carouselEl.dispatchEvent(mouseOutEvent)
-
- setTimeout(() => {
- expect(carousel.cycle).toHaveBeenCalled()
- done()
- }, 10)
- })
- })
-
- describe('next', () => {
- it('should not slide if the carousel is sliding', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
- const carousel = new Carousel(carouselEl, {})
-
- spyOn(carousel, '_slide')
-
- carousel._isSliding = true
- carousel.next()
-
- expect(carousel._slide).not.toHaveBeenCalled()
- })
-
- it('should not fire slid when slide is prevented', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
- const carousel = new Carousel(carouselEl, {})
- let slidEvent = false
-
- const doneTest = () => {
- setTimeout(() => {
- expect(slidEvent).toEqual(false)
- done()
- }, 20)
- }
-
- carouselEl.addEventListener('slide.bs.carousel', e => {
- e.preventDefault()
- doneTest()
- })
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- slidEvent = true
- })
-
- carousel.next()
- })
-
- it('should fire slide event with: direction, relatedTarget, from and to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- const onSlide = e => {
- expect(e.direction).toEqual('left')
- expect(e.relatedTarget.classList.contains('carousel-item')).toEqual(true)
- expect(e.from).toEqual(0)
- expect(e.to).toEqual(1)
-
- carouselEl.removeEventListener('slide.bs.carousel', onSlide)
- carouselEl.addEventListener('slide.bs.carousel', onSlide2)
-
- carousel.prev()
- }
-
- const onSlide2 = e => {
- expect(e.direction).toEqual('right')
- done()
- }
-
- carouselEl.addEventListener('slide.bs.carousel', onSlide)
- carousel.next()
- })
-
- it('should fire slid event with: direction, relatedTarget, from and to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- const onSlid = e => {
- expect(e.direction).toEqual('left')
- expect(e.relatedTarget.classList.contains('carousel-item')).toEqual(true)
- expect(e.from).toEqual(0)
- expect(e.to).toEqual(1)
-
- carouselEl.removeEventListener('slid.bs.carousel', onSlid)
- carouselEl.addEventListener('slid.bs.carousel', onSlid2)
-
- carousel.prev()
- }
-
- const onSlid2 = e => {
- expect(e.direction).toEqual('right')
- done()
- }
-
- carouselEl.addEventListener('slid.bs.carousel', onSlid)
- carousel.next()
- })
-
- it('should get interval from data attribute in individual item', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {
- interval: 1814
- })
-
- expect(carousel._config.interval).toEqual(1814)
-
- carousel.next()
-
- expect(carousel._config.interval).toEqual(7)
- })
-
- it('should update indicators if present', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <ol class="carousel-indicators">',
- ' <li data-target="#myCarousel" data-slide-to="0" class="active"></li>',
- ' <li id="secondIndicator" data-target="#myCarousel" data-slide-to="1"></li>',
- ' <li data-target="#myCarousel" data-slide-to="2"></li>',
- ' </ol>',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const secondIndicator = fixtureEl.querySelector('#secondIndicator')
- const carousel = new Carousel(carouselEl)
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(secondIndicator.classList.contains('active')).toEqual(true)
- done()
- })
-
- carousel.next()
- })
- })
-
- describe('nextWhenVisible', () => {
- it('should not call next when the page is not visible', () => {
- fixtureEl.innerHTML = [
- '<div style="display: none;">',
- ' <div class="carousel" data-interval="false"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('.carousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'next')
-
- carousel.nextWhenVisible()
-
- expect(carousel.next).not.toHaveBeenCalled()
- })
- })
-
- describe('prev', () => {
- it('should not slide if the carousel is sliding', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
- const carousel = new Carousel(carouselEl, {})
-
- spyOn(carousel, '_slide')
-
- carousel._isSliding = true
- carousel.prev()
-
- expect(carousel._slide).not.toHaveBeenCalled()
- })
- })
-
- describe('pause', () => {
- it('should call cycle if the carousel have carousel-item-next and carousel-item-prev class', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item carousel-item-next">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'cycle')
- spyOn(window, 'clearInterval')
-
- carousel.pause()
-
- expect(carousel.cycle).toHaveBeenCalledWith(true)
- expect(window.clearInterval).toHaveBeenCalled()
- expect(carousel._isPaused).toEqual(true)
- })
-
- it('should not call cycle if nothing is in transition', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(carousel, 'cycle')
- spyOn(window, 'clearInterval')
-
- carousel.pause()
-
- expect(carousel.cycle).not.toHaveBeenCalled()
- expect(window.clearInterval).toHaveBeenCalled()
- expect(carousel._isPaused).toEqual(true)
- })
-
- it('should not set is paused at true if an event is passed', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
- const event = createEvent('mouseenter')
-
- spyOn(window, 'clearInterval')
-
- carousel.pause(event)
-
- expect(window.clearInterval).toHaveBeenCalled()
- expect(carousel._isPaused).toEqual(false)
- })
- })
-
- describe('cycle', () => {
- it('should set an interval', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(window, 'setInterval').and.callThrough()
-
- carousel.cycle()
-
- expect(window.setInterval).toHaveBeenCalled()
- })
-
- it('should not set interval if the carousel is paused', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(window, 'setInterval').and.callThrough()
-
- carousel._isPaused = true
- carousel.cycle(true)
-
- expect(window.setInterval).not.toHaveBeenCalled()
- })
-
- it('should clear interval if there is one', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev"></div>',
- ' <div class="carousel-control-next"></div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- carousel._interval = setInterval(() => {}, 10)
-
- spyOn(window, 'setInterval').and.callThrough()
- spyOn(window, 'clearInterval').and.callThrough()
-
- carousel.cycle()
-
- expect(window.setInterval).toHaveBeenCalled()
- expect(window.clearInterval).toHaveBeenCalled()
- })
- })
-
- describe('to', () => {
- it('should go directement to the provided index', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div id="item1" class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div id="item3" class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1'))
-
- carousel.to(2)
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
- done()
- })
- })
-
- it('should return to a previous slide if the provided index is lower than the current', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div id="item3" class="carousel-item active">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item3'))
-
- carousel.to(1)
-
- carouselEl.addEventListener('slid.bs.carousel', () => {
- expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2'))
- done()
- })
- })
-
- it('should do nothing if a wrong index is provided', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- const spy = spyOn(carousel, '_slide')
-
- carousel.to(25)
-
- expect(spy).not.toHaveBeenCalled()
-
- spy.calls.reset()
-
- carousel.to(-5)
-
- expect(spy).not.toHaveBeenCalled()
- })
-
- it('should call pause and cycle is the provided is the same compare to the current one', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- spyOn(carousel, '_slide')
- spyOn(carousel, 'pause')
- spyOn(carousel, 'cycle')
-
- carousel.to(0)
-
- expect(carousel._slide).not.toHaveBeenCalled()
- expect(carousel.pause).toHaveBeenCalled()
- expect(carousel.cycle).toHaveBeenCalled()
- })
-
- it('should wait before performing to if a slide is sliding', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl, {})
-
- spyOn(EventHandler, 'one').and.callThrough()
- spyOn(carousel, '_slide')
-
- carousel._isSliding = true
- carousel.to(1)
-
- expect(carousel._slide).not.toHaveBeenCalled()
- expect(EventHandler.one).toHaveBeenCalled()
-
- spyOn(carousel, 'to')
-
- EventHandler.trigger(carouselEl, 'slid.bs.carousel')
-
- setTimeout(() => {
- expect(carousel.to).toHaveBeenCalledWith(1)
- done()
- })
- })
- })
-
- describe('dispose', () => {
- it('should destroy a carousel', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item" data-interval="7">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const carouselEl = fixtureEl.querySelector('#myCarousel')
- const carousel = new Carousel(carouselEl)
-
- spyOn(EventHandler, 'off').and.callThrough()
-
- carousel.dispose()
-
- expect(EventHandler.off).toHaveBeenCalled()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a carousel', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.carousel = Carousel.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.carousel.call(jQueryMock)
-
- expect(Carousel.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a carousel', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const carousel = new Carousel(div)
-
- jQueryMock.fn.carousel = Carousel.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.carousel.call(jQueryMock)
-
- expect(Carousel.getInstance(div)).toEqual(carousel)
- })
-
- it('should call to if the config is a number', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const carousel = new Carousel(div)
- const slideTo = 2
-
- spyOn(carousel, 'to')
-
- jQueryMock.fn.carousel = Carousel.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.carousel.call(jQueryMock, slideTo)
-
- expect(carousel.to).toHaveBeenCalledWith(slideTo)
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.carousel = Carousel.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.carousel.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('data-api', () => {
- it('should init carousels with data-ride="carousel" on load', () => {
- fixtureEl.innerHTML = '<div data-ride="carousel"></div>'
-
- const carouselEl = fixtureEl.querySelector('div')
- const loadEvent = createEvent('load')
-
- window.dispatchEvent(loadEvent)
-
- expect(Carousel.getInstance(carouselEl)).toBeDefined()
- })
-
- it('should create carousel and go to the next slide on click', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev" data-target="#myCarousel" role="button" data-slide="prev"></div>',
- ' <div id="next" class="carousel-control-next" data-target="#myCarousel" role="button" data-slide="next"></div>',
- '</div>'
- ].join('')
-
- const next = fixtureEl.querySelector('#next')
- const item2 = fixtureEl.querySelector('#item2')
-
- next.click()
-
- setTimeout(() => {
- expect(item2.classList.contains('active')).toEqual(true)
- done()
- }, 10)
- })
-
- it('should create carousel and go to the next slide on click with data-slide-to', done => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div id="next" data-target="#myCarousel" data-slide-to="1"></div>',
- '</div>'
- ].join('')
-
- const next = fixtureEl.querySelector('#next')
- const item2 = fixtureEl.querySelector('#item2')
-
- next.click()
-
- setTimeout(() => {
- expect(item2.classList.contains('active')).toEqual(true)
- done()
- }, 10)
- })
-
- it('should do nothing if no selector on click on arrows', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="carousel slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev" data-target="#myCarousel" role="button" data-slide="prev"></div>',
- ' <div id="next" class="carousel-control-next" role="button" data-slide="next"></div>',
- '</div>'
- ].join('')
-
- const next = fixtureEl.querySelector('#next')
-
- next.click()
-
- expect().nothing()
- })
-
- it('should do nothing if no carousel class on click on arrows', () => {
- fixtureEl.innerHTML = [
- '<div id="myCarousel" class="slide">',
- ' <div class="carousel-inner">',
- ' <div class="carousel-item active">item 1</div>',
- ' <div id="item2" class="carousel-item">item 2</div>',
- ' <div class="carousel-item">item 3</div>',
- ' </div>',
- ' <div class="carousel-control-prev" data-target="#myCarousel" role="button" data-slide="prev"></div>',
- ' <div id="next" class="carousel-control-next" data-target="#myCarousel" role="button" data-slide="next"></div>',
- '</div>'
- ].join('')
-
- const next = fixtureEl.querySelector('#next')
-
- next.click()
-
- expect().nothing()
- })
- })
-})
diff --git a/js/src/collapse/collapse.js b/js/src/collapse.js
index 4de7b5282..f533885ec 100644
--- a/js/src/collapse/collapse.js
+++ b/js/src/collapse.js
@@ -16,11 +16,11 @@ import {
makeArray,
reflow,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/collapse/collapse.spec.js b/js/src/collapse/collapse.spec.js
deleted file mode 100644
index 154bc2c6b..000000000
--- a/js/src/collapse/collapse.spec.js
+++ /dev/null
@@ -1,826 +0,0 @@
-import Collapse from './collapse'
-import EventHandler from '../dom/event-handler'
-import { makeArray } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Collapse', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Collapse.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Collapse.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('constructor', () => {
- it('should allow jquery object in parent config', () => {
- fixtureEl.innerHTML = [
- '<div class="my-collapse">',
- ' <div class="item">',
- ' <a data-toggle="collapse" href="#">Toggle item</a>',
- ' <div class="collapse">Lorem ipsum</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const collapseEl = fixtureEl.querySelector('div.collapse')
- const myCollapseEl = fixtureEl.querySelector('.my-collapse')
- const fakejQueryObject = {
- 0: myCollapseEl
- }
- const collapse = new Collapse(collapseEl, {
- parent: fakejQueryObject
- })
-
- expect(collapse._config.parent).toEqual(fakejQueryObject)
- expect(collapse._getParent()).toEqual(myCollapseEl)
- })
-
- it('should allow non jquery object in parent config', () => {
- fixtureEl.innerHTML = [
- '<div class="my-collapse">',
- ' <div class="item">',
- ' <a data-toggle="collapse" href="#">Toggle item</a>',
- ' <div class="collapse">Lorem ipsum</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const collapseEl = fixtureEl.querySelector('div.collapse')
- const myCollapseEl = fixtureEl.querySelector('.my-collapse')
- const collapse = new Collapse(collapseEl, {
- parent: myCollapseEl
- })
-
- expect(collapse._config.parent).toEqual(myCollapseEl)
- })
-
- it('should allow string selector in parent config', () => {
- fixtureEl.innerHTML = [
- '<div class="my-collapse">',
- ' <div class="item">',
- ' <a data-toggle="collapse" href="#">Toggle item</a>',
- ' <div class="collapse">Lorem ipsum</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const collapseEl = fixtureEl.querySelector('div.collapse')
- const myCollapseEl = fixtureEl.querySelector('.my-collapse')
- const collapse = new Collapse(collapseEl, {
- parent: 'div.my-collapse'
- })
-
- expect(collapse._config.parent).toEqual('div.my-collapse')
- expect(collapse._getParent()).toEqual(myCollapseEl)
- })
- })
-
- describe('toggle', () => {
- it('should call show method if show class is not present', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl)
-
- spyOn(collapse, 'show')
-
- collapse.toggle()
-
- expect(collapse.show).toHaveBeenCalled()
- })
-
- it('should call hide method if show class is present', () => {
- fixtureEl.innerHTML = '<div class="show"></div>'
-
- const collapseEl = fixtureEl.querySelector('.show')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- spyOn(collapse, 'hide')
-
- collapse.toggle()
-
- expect(collapse.hide).toHaveBeenCalled()
- })
-
- it('should find collapse children if they have collapse class too not only data-parent', done => {
- fixtureEl.innerHTML = [
- '<div class="my-collapse">',
- ' <div class="item">',
- ' <a data-toggle="collapse" href="#">Toggle item 1</a>',
- ' <div id="collapse1" class="collapse show">Lorem ipsum 1</div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="triggerCollapse2" data-toggle="collapse" href="#">Toggle item 2</a>',
- ' <div id="collapse2" class="collapse">Lorem ipsum 2</div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const parent = fixtureEl.querySelector('.my-collapse')
- const collapseEl1 = fixtureEl.querySelector('#collapse1')
- const collapseEl2 = fixtureEl.querySelector('#collapse2')
-
- const collapseList = makeArray(fixtureEl.querySelectorAll('.collapse'))
- .map(el => new Collapse(el, {
- parent,
- toggle: false
- }))
-
- collapseEl2.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl2.classList.contains('show')).toEqual(true)
- expect(collapseEl1.classList.contains('show')).toEqual(false)
- done()
- })
-
- collapseList[1].toggle()
- })
- })
-
- describe('show', () => {
- it('should do nothing if is transitioning', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- spyOn(EventHandler, 'trigger')
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapse._isTransitioning = true
- collapse.show()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should do nothing if already shown', () => {
- fixtureEl.innerHTML = '<div class="show"></div>'
-
- spyOn(EventHandler, 'trigger')
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapse.show()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should show a collapsed element', done => {
- fixtureEl.innerHTML = '<div class="collapse" style="height: 0px;"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapseEl.addEventListener('show.bs.collapse', () => {
- expect(collapseEl.style.height).toEqual('0px')
- })
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl.classList.contains('show')).toEqual(true)
- expect(collapseEl.style.height).toEqual('')
- done()
- })
-
- collapse.show()
- })
-
- it('should show a collapsed element on width', done => {
- fixtureEl.innerHTML = '<div class="collapse width" style="width: 0px;"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapseEl.addEventListener('show.bs.collapse', () => {
- expect(collapseEl.style.width).toEqual('0px')
- })
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl.classList.contains('show')).toEqual(true)
- expect(collapseEl.style.width).toEqual('')
- done()
- })
-
- collapse.show()
- })
-
- it('should collapse only the first collapse', done => {
- fixtureEl.innerHTML = [
- '<div class="card" id="accordion1">',
- ' <div id="collapse1" class="collapse"/>',
- '</div>',
- '<div class="card" id="accordion2">',
- ' <div id="collapse2" class="collapse show"/>',
- '</div>'
- ].join('')
-
- const el1 = fixtureEl.querySelector('#collapse1')
- const el2 = fixtureEl.querySelector('#collapse2')
- const collapse = new Collapse(el1, {
- toggle: false
- })
-
- el1.addEventListener('shown.bs.collapse', () => {
- expect(el1.classList.contains('show')).toEqual(true)
- expect(el2.classList.contains('show')).toEqual(true)
- done()
- })
-
- collapse.show()
- })
-
- it('should not fire shown when show is prevented', done => {
- fixtureEl.innerHTML = '<div class="collapse"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- const expectEnd = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- }
-
- collapseEl.addEventListener('show.bs.collapse', e => {
- e.preventDefault()
- expectEnd()
- })
-
- collapseEl.addEventListener('shown.bs.collapse', () => {
- throw new Error('should not fire shown event')
- })
-
- collapse.show()
- })
- })
-
- describe('hide', () => {
- it('should do nothing if is transitioning', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- spyOn(EventHandler, 'trigger')
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapse._isTransitioning = true
- collapse.hide()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should do nothing if already shown', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- spyOn(EventHandler, 'trigger')
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapse.hide()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should hide a collapsed element', done => {
- fixtureEl.innerHTML = '<div class="collapse show"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- collapseEl.addEventListener('hidden.bs.collapse', () => {
- expect(collapseEl.classList.contains('show')).toEqual(false)
- expect(collapseEl.style.height).toEqual('')
- done()
- })
-
- collapse.hide()
- })
-
- it('should not fire hidden when hide is prevented', done => {
- fixtureEl.innerHTML = '<div class="collapse show"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- const expectEnd = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- }
-
- collapseEl.addEventListener('hide.bs.collapse', e => {
- e.preventDefault()
- expectEnd()
- })
-
- collapseEl.addEventListener('hidden.bs.collapse', () => {
- throw new Error('should not fire hidden event')
- })
-
- collapse.hide()
- })
- })
-
- describe('dispose', () => {
- it('should destroy a collapse', () => {
- fixtureEl.innerHTML = '<div class="collapse show"></div>'
-
- const collapseEl = fixtureEl.querySelector('div')
- const collapse = new Collapse(collapseEl, {
- toggle: false
- })
-
- expect(Collapse.getInstance(collapseEl)).toEqual(collapse)
-
- collapse.dispose()
-
- expect(Collapse.getInstance(collapseEl)).toEqual(null)
- })
- })
-
- describe('data-api', () => {
- it('should show multiple collapsed elements', done => {
- fixtureEl.innerHTML = [
- '<a role="button" data-toggle="collapse" class="collapsed" href=".multi"></a>',
- '<div id="collapse1" class="collapse multi"/>',
- '<div id="collapse2" class="collapse multi"/>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('a')
- const collapse1 = fixtureEl.querySelector('#collapse1')
- const collapse2 = fixtureEl.querySelector('#collapse2')
-
- collapse2.addEventListener('shown.bs.collapse', () => {
- expect(trigger.getAttribute('aria-expanded')).toEqual('true')
- expect(trigger.classList.contains('collapsed')).toEqual(false)
- expect(collapse1.classList.contains('show')).toEqual(true)
- expect(collapse1.classList.contains('show')).toEqual(true)
- done()
- })
-
- trigger.click()
- })
-
- it('should hide multiple collapsed elements', done => {
- fixtureEl.innerHTML = [
- '<a role="button" data-toggle="collapse" href=".multi"></a>',
- '<div id="collapse1" class="collapse multi show"/>',
- '<div id="collapse2" class="collapse multi show"/>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('a')
- const collapse1 = fixtureEl.querySelector('#collapse1')
- const collapse2 = fixtureEl.querySelector('#collapse2')
-
- collapse2.addEventListener('hidden.bs.collapse', () => {
- expect(trigger.getAttribute('aria-expanded')).toEqual('false')
- expect(trigger.classList.contains('collapsed')).toEqual(true)
- expect(collapse1.classList.contains('show')).toEqual(false)
- expect(collapse1.classList.contains('show')).toEqual(false)
- done()
- })
-
- trigger.click()
- })
-
- it('should remove "collapsed" class from target when collapse is shown', done => {
- fixtureEl.innerHTML = [
- '<a id="link1" role="button" data-toggle="collapse" class="collapsed" href="#" data-target="#test1" />',
- '<a id="link2" role="button" data-toggle="collapse" class="collapsed" href="#" data-target="#test1" />',
- '<div id="test1"></div>'
- ].join('')
-
- const link1 = fixtureEl.querySelector('#link1')
- const link2 = fixtureEl.querySelector('#link2')
- const collapseTest1 = fixtureEl.querySelector('#test1')
-
- collapseTest1.addEventListener('shown.bs.collapse', () => {
- expect(link1.getAttribute('aria-expanded')).toEqual('true')
- expect(link2.getAttribute('aria-expanded')).toEqual('true')
- expect(link1.classList.contains('collapsed')).toEqual(false)
- expect(link2.classList.contains('collapsed')).toEqual(false)
- done()
- })
-
- link1.click()
- })
-
- it('should add "collapsed" class to target when collapse is hidden', done => {
- fixtureEl.innerHTML = [
- '<a id="link1" role="button" data-toggle="collapse" href="#" data-target="#test1" />',
- '<a id="link2" role="button" data-toggle="collapse" href="#" data-target="#test1" />',
- '<div id="test1" class="show"></div>'
- ].join('')
-
- const link1 = fixtureEl.querySelector('#link1')
- const link2 = fixtureEl.querySelector('#link2')
- const collapseTest1 = fixtureEl.querySelector('#test1')
-
- collapseTest1.addEventListener('hidden.bs.collapse', () => {
- expect(link1.getAttribute('aria-expanded')).toEqual('false')
- expect(link2.getAttribute('aria-expanded')).toEqual('false')
- expect(link1.classList.contains('collapsed')).toEqual(true)
- expect(link2.classList.contains('collapsed')).toEqual(true)
- done()
- })
-
- link1.click()
- })
-
- it('should allow accordion to use children other than card', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion"></div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion"></div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('#linkTrigger')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOne = fixtureEl.querySelector('#collapseOne')
- const collapseTwo = fixtureEl.querySelector('#collapseTwo')
-
- collapseOne.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne.classList.contains('show')).toEqual(true)
- expect(collapseTwo.classList.contains('show')).toEqual(false)
-
- collapseTwo.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne.classList.contains('show')).toEqual(false)
- expect(collapseTwo.classList.contains('show')).toEqual(true)
- done()
- })
-
- triggerTwo.click()
- })
-
- trigger.click()
- })
-
- it('should not prevent event for input', done => {
- fixtureEl.innerHTML = [
- '<input type="checkbox" data-toggle="collapse" data-target="#collapsediv1" />',
- '<div id="collapsediv1"></div>'
- ].join('')
-
- const target = fixtureEl.querySelector('input')
- const collapseEl = fixtureEl.querySelector('#collapsediv1')
-
- collapseEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseEl.classList.contains('show')).toEqual(true)
- expect(target.checked).toEqual(true)
- done()
- })
-
- target.click()
- })
-
- it('should allow accordion to contain nested elements', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="row">',
- ' <div class="col-lg-6">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion"></div>',
- ' </div>',
- ' </div>',
- ' <div class="col-lg-6">',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion"></div>',
- ' </div>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerEl = fixtureEl.querySelector('#linkTrigger')
- const triggerTwoEl = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOneEl = fixtureEl.querySelector('#collapseOne')
- const collapseTwoEl = fixtureEl.querySelector('#collapseTwo')
-
- collapseOneEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseOneEl.classList.contains('show')).toEqual(true)
- expect(triggerEl.classList.contains('collapsed')).toEqual(false)
- expect(triggerEl.getAttribute('aria-expanded')).toEqual('true')
-
- expect(collapseTwoEl.classList.contains('show')).toEqual(false)
- expect(triggerTwoEl.classList.contains('collapsed')).toEqual(true)
- expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('false')
-
- collapseTwoEl.addEventListener('shown.bs.collapse', () => {
- expect(collapseOneEl.classList.contains('show')).toEqual(false)
- expect(triggerEl.classList.contains('collapsed')).toEqual(true)
- expect(triggerEl.getAttribute('aria-expanded')).toEqual('false')
-
- expect(collapseTwoEl.classList.contains('show')).toEqual(true)
- expect(triggerTwoEl.classList.contains('collapsed')).toEqual(false)
- expect(triggerTwoEl.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- triggerTwoEl.click()
- })
-
- triggerEl.click()
- })
-
- it('should allow accordion to target multiple elements', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <a id="linkTriggerOne" data-toggle="collapse" data-target=".collapseOne" href="#" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <a id="linkTriggerTwo" data-toggle="collapse" data-target=".collapseTwo" href="#" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseOneOne" class="collapse collapseOne" role="tabpanel" data-parent="#accordion"></div>',
- ' <div id="collapseOneTwo" class="collapse collapseOne" role="tabpanel" data-parent="#accordion"></div>',
- ' <div id="collapseTwoOne" class="collapse collapseTwo" role="tabpanel" data-parent="#accordion"></div>',
- ' <div id="collapseTwoTwo" class="collapse collapseTwo" role="tabpanel" data-parent="#accordion"></div>',
- '</div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('#linkTriggerOne')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const collapseOneOne = fixtureEl.querySelector('#collapseOneOne')
- const collapseOneTwo = fixtureEl.querySelector('#collapseOneTwo')
- const collapseTwoOne = fixtureEl.querySelector('#collapseTwoOne')
- const collapseTwoTwo = fixtureEl.querySelector('#collapseTwoTwo')
- const collapsedElements = {
- one: false,
- two: false
- }
-
- function firstTest() {
- expect(collapseOneOne.classList.contains('show')).toEqual(true)
- expect(collapseOneTwo.classList.contains('show')).toEqual(true)
-
- expect(collapseTwoOne.classList.contains('show')).toEqual(false)
- expect(collapseTwoTwo.classList.contains('show')).toEqual(false)
-
- triggerTwo.click()
- }
-
- function secondTest() {
- expect(collapseOneOne.classList.contains('show')).toEqual(false)
- expect(collapseOneTwo.classList.contains('show')).toEqual(false)
-
- expect(collapseTwoOne.classList.contains('show')).toEqual(true)
- expect(collapseTwoTwo.classList.contains('show')).toEqual(true)
- done()
- }
-
- collapseOneOne.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.one) {
- firstTest()
- } else {
- collapsedElements.one = true
- }
- })
-
- collapseOneTwo.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.one) {
- firstTest()
- } else {
- collapsedElements.one = true
- }
- })
-
- collapseTwoOne.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.two) {
- secondTest()
- } else {
- collapsedElements.two = true
- }
- })
-
- collapseTwoTwo.addEventListener('shown.bs.collapse', () => {
- if (collapsedElements.two) {
- secondTest()
- } else {
- collapsedElements.two = true
- }
- })
-
- trigger.click()
- })
-
- it('should collapse accordion children but not nested accordion children', done => {
- fixtureEl.innerHTML = [
- '<div id="accordion">',
- ' <div class="item">',
- ' <a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>',
- ' <div id="collapseOne" data-parent="#accordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">',
- ' <div id="nestedAccordion">',
- ' <div class="item">',
- ' <a id="nestedLinkTrigger" data-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>',
- ' <div id="nestedCollapseOne" data-parent="#nestedAccordion" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div class="item">',
- ' <a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>',
- ' <div id="collapseTwo" data-parent="#accordion" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const trigger = fixtureEl.querySelector('#linkTrigger')
- const triggerTwo = fixtureEl.querySelector('#linkTriggerTwo')
- const nestedTrigger = fixtureEl.querySelector('#nestedLinkTrigger')
- const collapseOne = fixtureEl.querySelector('#collapseOne')
- const collapseTwo = fixtureEl.querySelector('#collapseTwo')
- const nestedCollapseOne = fixtureEl.querySelector('#nestedCollapseOne')
-
- function handlerCollapseOne() {
- expect(collapseOne.classList.contains('show')).toEqual(true)
- expect(collapseTwo.classList.contains('show')).toEqual(false)
- expect(nestedCollapseOne.classList.contains('show')).toEqual(false)
-
- nestedCollapseOne.addEventListener('shown.bs.collapse', handlerNestedCollapseOne)
- nestedTrigger.click()
- collapseOne.removeEventListener('shown.bs.collapse', handlerCollapseOne)
- }
-
- function handlerNestedCollapseOne() {
- expect(collapseOne.classList.contains('show')).toEqual(true)
- expect(collapseTwo.classList.contains('show')).toEqual(false)
- expect(nestedCollapseOne.classList.contains('show')).toEqual(true)
-
- collapseTwo.addEventListener('shown.bs.collapse', () => {
- expect(collapseOne.classList.contains('show')).toEqual(false)
- expect(collapseTwo.classList.contains('show')).toEqual(true)
- expect(nestedCollapseOne.classList.contains('show')).toEqual(true)
- done()
- })
-
- triggerTwo.click()
- nestedCollapseOne.removeEventListener('shown.bs.collapse', handlerNestedCollapseOne)
- }
-
- collapseOne.addEventListener('shown.bs.collapse', handlerCollapseOne)
- trigger.click()
- })
-
- it('should add "collapsed" class and set aria-expanded to triggers only when all the targeted collapse are hidden', done => {
- fixtureEl.innerHTML = [
- '<a id="trigger1" role="button" data-toggle="collapse" href="#test1"/>',
- '<a id="trigger2" role="button" data-toggle="collapse" href="#test2"/>',
- '<a id="trigger3" role="button" data-toggle="collapse" href=".multi"/>',
- '<div id="test1" class="multi"/>',
- '<div id="test2" class="multi"/>'
- ].join('')
-
- const trigger1 = fixtureEl.querySelector('#trigger1')
- const trigger2 = fixtureEl.querySelector('#trigger2')
- const trigger3 = fixtureEl.querySelector('#trigger3')
- const target1 = fixtureEl.querySelector('#test1')
- const target2 = fixtureEl.querySelector('#test2')
-
- const target2Shown = () => {
- expect(trigger1.classList.contains('collapsed')).toEqual(false)
- expect(trigger1.getAttribute('aria-expanded')).toEqual('true')
-
- expect(trigger2.classList.contains('collapsed')).toEqual(false)
- expect(trigger2.getAttribute('aria-expanded')).toEqual('true')
-
- expect(trigger3.classList.contains('collapsed')).toEqual(false)
- expect(trigger3.getAttribute('aria-expanded')).toEqual('true')
-
- target2.addEventListener('hidden.bs.collapse', () => {
- expect(trigger1.classList.contains('collapsed')).toEqual(false)
- expect(trigger1.getAttribute('aria-expanded')).toEqual('true')
-
- expect(trigger2.classList.contains('collapsed')).toEqual(true)
- expect(trigger2.getAttribute('aria-expanded')).toEqual('false')
-
- expect(trigger3.classList.contains('collapsed')).toEqual(false)
- expect(trigger3.getAttribute('aria-expanded')).toEqual('true')
-
- target1.addEventListener('hidden.bs.collapse', () => {
- expect(trigger1.classList.contains('collapsed')).toEqual(true)
- expect(trigger1.getAttribute('aria-expanded')).toEqual('false')
-
- expect(trigger2.classList.contains('collapsed')).toEqual(true)
- expect(trigger2.getAttribute('aria-expanded')).toEqual('false')
-
- expect(trigger3.classList.contains('collapsed')).toEqual(true)
- expect(trigger3.getAttribute('aria-expanded')).toEqual('false')
- done()
- })
-
- trigger1.click()
- })
-
- trigger2.click()
- }
-
- target2.addEventListener('shown.bs.collapse', target2Shown)
- trigger3.click()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a collapse', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.collapse = Collapse.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.collapse.call(jQueryMock)
-
- expect(Collapse.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a collapse', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const collapse = new Collapse(div)
-
- jQueryMock.fn.collapse = Collapse.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.collapse.call(jQueryMock)
-
- expect(Collapse.getInstance(div)).toEqual(collapse)
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.collapse = Collapse.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.collapse.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('getInstance', () => {
- it('should return collapse instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const collapse = new Collapse(div)
-
- expect(Collapse.getInstance(div)).toEqual(collapse)
- })
-
- it('should return null when there is no collapse instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Collapse.getInstance(div)).toEqual(null)
- })
- })
-})
diff --git a/js/src/dom/data.spec.js b/js/src/dom/data.spec.js
deleted file mode 100644
index 46018dd5c..000000000
--- a/js/src/dom/data.spec.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import Data from './data'
-
-/** Test helpers */
-import { getFixture, clearFixture } from '../../tests/helpers/fixture'
-
-describe('Data', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('setData', () => {
- it('should set data in an element by adding a key attribute', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
- expect(div.key).toBeDefined()
- })
-
- it('should change data if something is already stored', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
-
- data.test = 'bsData2'
- Data.setData(div, 'test', data)
-
- expect(div.key).toBeDefined()
- })
- })
-
- describe('getData', () => {
- it('should return stored data', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
- expect(Data.getData(div, 'test')).toEqual(data)
- })
-
- it('should return null on undefined element', () => {
- expect(Data.getData(null)).toEqual(null)
- expect(Data.getData(undefined)).toEqual(null)
- })
-
- it('should return null when an element have nothing stored', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Data.getData(div, 'test')).toEqual(null)
- })
-
- it('should return null when an element have nothing stored with the provided key', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
-
- expect(Data.getData(div, 'test2')).toEqual(null)
- })
- })
-
- describe('removeData', () => {
- it('should do nothing when an element have nothing stored', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Data.removeData(div, 'test')
- expect().nothing()
- })
-
- it('should should do nothing if it\'s not a valid key provided', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
-
- expect(div.key).toBeDefined()
-
- Data.removeData(div, 'test2')
-
- expect(div.key).toBeDefined()
- })
-
- it('should remove data if something is stored', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
-
- expect(div.key).toBeDefined()
-
- Data.removeData(div, 'test')
-
- expect(div.key).toBeUndefined()
- })
- })
-})
diff --git a/js/src/dom/event-handler.spec.js b/js/src/dom/event-handler.spec.js
deleted file mode 100644
index dc5c5c30c..000000000
--- a/js/src/dom/event-handler.spec.js
+++ /dev/null
@@ -1,327 +0,0 @@
-import EventHandler from './event-handler'
-
-/** Test helpers */
-import { getFixture, clearFixture } from '../../tests/helpers/fixture'
-
-describe('EventHandler', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('on', () => {
- it('should not add event listener if the event is not a string', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- EventHandler.on(div, null, () => {})
- EventHandler.on(null, 'click', () => {})
-
- expect().nothing()
- })
-
- it('should add event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- EventHandler.on(div, 'click', () => {
- expect().nothing()
- done()
- })
-
- div.click()
- })
-
- it('should add namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- EventHandler.on(div, 'bs.namespace', () => {
- expect().nothing()
- done()
- })
-
- EventHandler.trigger(div, 'bs.namespace')
- })
-
- it('should add native namespaced event listener', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- EventHandler.on(div, 'click.namespace', () => {
- expect().nothing()
- done()
- })
-
- EventHandler.trigger(div, 'click')
- })
-
- it('should handle event delegation', done => {
- EventHandler.on(document, 'click', '.test', () => {
- expect().nothing()
- done()
- })
-
- fixtureEl.innerHTML = '<div class="test"></div>'
-
- const div = fixtureEl.querySelector('div')
-
- div.click()
- })
- })
-
- describe('one', () => {
- it('should call listener just one', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- let called = 0
- const div = fixtureEl.querySelector('div')
- const obj = {
- oneListener() {
- called++
- }
- }
-
- EventHandler.one(div, 'bootstrap', obj.oneListener)
-
- EventHandler.trigger(div, 'bootstrap')
- EventHandler.trigger(div, 'bootstrap')
-
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
- })
- })
-
- describe('off', () => {
- it('should not remove a listener', () => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- EventHandler.off(div, null, () => {})
- EventHandler.off(null, 'click', () => {})
- expect().nothing()
- })
-
- it('should remove a listener', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called = 0
- const handler = () => {
- called++
- }
-
- EventHandler.on(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
-
- EventHandler.off(div, 'foobar', handler)
- EventHandler.trigger(div, 'foobar')
-
- setTimeout(() => {
- expect(called).toEqual(1)
- done()
- }, 20)
- })
-
- it('should remove all the events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called = 0
-
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.on(div, 'foobar', () => {
- called++
- })
- EventHandler.trigger(div, 'foobar')
-
- EventHandler.off(div, 'foobar')
- EventHandler.trigger(div, 'foobar')
-
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
- })
-
- it('should remove all the namespaced listeners if namespace is passed', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called = 0
-
- EventHandler.on(div, 'foobar.namespace', () => {
- called++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- called++
- })
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
-
- EventHandler.off(div, '.namespace')
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foofoo.namespace')
-
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
- })
-
- it('should remove the namespaced listeners', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let calledCallback1 = 0
- let calledCallback2 = 0
-
- EventHandler.on(div, 'foobar.namespace', () => {
- calledCallback1++
- })
- EventHandler.on(div, 'foofoo.namespace', () => {
- calledCallback2++
- })
-
- EventHandler.trigger(div, 'foobar.namespace')
- EventHandler.off(div, 'foobar.namespace')
- EventHandler.trigger(div, 'foobar.namespace')
-
- EventHandler.trigger(div, 'foofoo.namespace')
-
- setTimeout(() => {
- expect(calledCallback1).toEqual(1)
- expect(calledCallback2).toEqual(1)
- done()
- }, 20)
- })
-
- it('should remove the all the namespaced listeners for native events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called = 0
-
- EventHandler.on(div, 'click.namespace', () => {
- called++
- })
- EventHandler.on(div, 'click.namespace2', () => {
- called++
- })
-
- EventHandler.trigger(div, 'click')
- EventHandler.off(div, 'click')
- EventHandler.trigger(div, 'click')
-
- setTimeout(() => {
- expect(called).toEqual(2)
- done()
- }, 20)
- })
-
- it('should remove the specified namespaced listeners for native events', done => {
- fixtureEl.innerHTML = '<div></div>'
- const div = fixtureEl.querySelector('div')
-
- let called1 = 0
- let called2 = 0
-
- EventHandler.on(div, 'click.namespace', () => {
- called1++
- })
- EventHandler.on(div, 'click.namespace2', () => {
- called2++
- })
- EventHandler.trigger(div, 'click')
-
- EventHandler.off(div, 'click.namespace')
- EventHandler.trigger(div, 'click')
-
- setTimeout(() => {
- expect(called1).toEqual(1)
- expect(called2).toEqual(2)
- done()
- }, 20)
- })
-
- it('should remove a listener registered by .one', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const handler = () => {
- throw new Error('called')
- }
-
- EventHandler.one(div, 'foobar', handler)
- EventHandler.off(div, 'foobar', handler)
-
- EventHandler.trigger(div, 'foobar')
- setTimeout(() => {
- expect().nothing()
- done()
- }, 20)
- })
-
- it('should remove the correct delegated event listener', () => {
- const element = document.createElement('div')
- const subelement = document.createElement('span')
- element.appendChild(subelement)
-
- const anchor = document.createElement('a')
- element.appendChild(anchor)
-
- let i = 0
- const handler = () => {
- i++
- }
-
- EventHandler.on(element, 'click', 'a', handler)
- EventHandler.on(element, 'click', 'span', handler)
-
- fixtureEl.appendChild(element)
-
- EventHandler.trigger(anchor, 'click')
- EventHandler.trigger(subelement, 'click')
-
- // first listeners called
- expect(i === 2).toEqual(true)
-
- EventHandler.off(element, 'click', 'span', handler)
- EventHandler.trigger(subelement, 'click')
-
- // removed listener not called
- expect(i === 2).toEqual(true)
-
- EventHandler.trigger(anchor, 'click')
-
- // not removed listener called
- expect(i === 3).toEqual(true)
-
- EventHandler.on(element, 'click', 'span', handler)
- EventHandler.trigger(anchor, 'click')
- EventHandler.trigger(subelement, 'click')
-
- // listener re-registered
- expect(i === 5).toEqual(true)
-
- EventHandler.off(element, 'click', 'span')
- EventHandler.trigger(subelement, 'click')
-
- // listener removed again
- expect(i === 5).toEqual(true)
- })
- })
-})
diff --git a/js/src/dom/manipulator.spec.js b/js/src/dom/manipulator.spec.js
deleted file mode 100644
index e96c068d4..000000000
--- a/js/src/dom/manipulator.spec.js
+++ /dev/null
@@ -1,158 +0,0 @@
-import Manipulator from './manipulator'
-
-/** Test helpers */
-import { getFixture, clearFixture } from '../../tests/helpers/fixture'
-
-describe('Manipulator', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('setDataAttribute', () => {
- it('should set data attribute', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.setDataAttribute(div, 'key', 'value')
- expect(div.getAttribute('data-key')).toEqual('value')
- })
-
- it('should set data attribute in lower case', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.setDataAttribute(div, 'tEsT', 'value')
- expect(div.getAttribute('data-test')).toEqual('value')
- })
- })
-
- describe('removeDataAttribute', () => {
- it('should remove data attribute', () => {
- fixtureEl.innerHTML = '<div data-key="value"></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.removeDataAttribute(div, 'key')
- expect(div.getAttribute('data-key')).toBeNull()
- })
-
- it('should remove data attribute in lower case', () => {
- fixtureEl.innerHTML = '<div data-testkey="value" ></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.removeDataAttribute(div, 'tEStKeY')
- expect(div.getAttribute('data-testkey')).toBeNull()
- })
- })
-
- describe('getDataAttributes', () => {
- it('should return empty object for null', () => {
- expect(Manipulator.getDataAttributes(null), {})
- expect().nothing()
- })
-
- it('should get all data attributes', () => {
- fixtureEl.innerHTML = '<div data-test="js" data-test2="js2" ></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Manipulator.getDataAttributes(div)).toEqual({
- test: 'js',
- test2: 'js2'
- })
- })
- })
-
- describe('getDataAttribute', () => {
- it('should get data attribute', () => {
- fixtureEl.innerHTML = '<div data-test="null" ></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Manipulator.getDataAttribute(div, 'test')).toBeNull()
- })
-
- it('should get data attribute in lower case', () => {
- fixtureEl.innerHTML = '<div data-test="value" ></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Manipulator.getDataAttribute(div, 'tEsT')).toEqual('value')
- })
-
- it('should normalize data', () => {
- fixtureEl.innerHTML = '<div data-test="false" ></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Manipulator.getDataAttribute(div, 'test')).toEqual(false)
-
- div.setAttribute('data-test', 'true')
- expect(Manipulator.getDataAttribute(div, 'test')).toEqual(true)
-
- div.setAttribute('data-test', '1')
- expect(Manipulator.getDataAttribute(div, 'test')).toEqual(1)
- })
- })
-
- describe('offset', () => {
- it('should return object with two properties top and left, both numbers', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const offset = Manipulator.offset(div)
-
- expect(offset).toBeDefined()
- expect(offset.top).toEqual(jasmine.any(Number))
- expect(offset.left).toEqual(jasmine.any(Number))
- })
- })
-
- describe('position', () => {
- it('should return object with two properties top and left, both numbers', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const position = Manipulator.position(div)
-
- expect(position).toBeDefined()
- expect(position.top).toEqual(jasmine.any(Number))
- expect(position.left).toEqual(jasmine.any(Number))
- })
- })
-
- describe('toggleClass', () => {
- it('should not error out if element is null or undefined', () => {
- Manipulator.toggleClass(null, 'test')
- Manipulator.toggleClass(undefined, 'test')
- expect().nothing()
- })
-
- it('should add class if it is missing', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.toggleClass(div, 'test')
- expect(div.classList.contains('test')).toEqual(true)
- })
-
- it('should remove class if it is set', () => {
- fixtureEl.innerHTML = '<div class="test"></div>'
-
- const div = fixtureEl.querySelector('div')
-
- Manipulator.toggleClass(div, 'test')
- expect(div.classList.contains('test')).toEqual(false)
- })
- })
-})
diff --git a/js/src/dom/selector-engine.spec.js b/js/src/dom/selector-engine.spec.js
deleted file mode 100644
index 28ccdf40b..000000000
--- a/js/src/dom/selector-engine.spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import SelectorEngine from './selector-engine'
-import { makeArray } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture } from '../../tests/helpers/fixture'
-
-describe('SelectorEngine', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('matches', () => {
- it('should return matched elements', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- expect(SelectorEngine.matches(fixtureEl, 'div')).toEqual(true)
- })
- })
-
- describe('find', () => {
- it('should find elements', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(makeArray(SelectorEngine.find('div', fixtureEl))).toEqual([div])
- })
-
- it('should find elements globaly', () => {
- fixtureEl.innerHTML = '<div id="test"></div>'
-
- const div = fixtureEl.querySelector('#test')
-
- expect(makeArray(SelectorEngine.find('#test'))).toEqual([div])
- })
-
- it('should handle :scope selectors', () => {
- fixtureEl.innerHTML = `<ul>
- <li></li>
- <li>
- <a href="#" class="active">link</a>
- </li>
- <li></li>
- </ul>`
-
- const listEl = fixtureEl.querySelector('ul')
- const aActive = fixtureEl.querySelector('.active')
-
- expect(makeArray(SelectorEngine.find(':scope > li > .active', listEl))).toEqual([aActive])
- })
- })
-
- describe('findOne', () => {
- it('should return one element', () => {
- fixtureEl.innerHTML = '<div id="test"></div>'
-
- const div = fixtureEl.querySelector('#test')
-
- expect(SelectorEngine.findOne('#test')).toEqual(div)
- })
- })
-
- describe('children', () => {
- it('should find children', () => {
- fixtureEl.innerHTML = `<ul>
- <li></li>
- <li></li>
- <li></li>
- </ul>`
-
- const list = fixtureEl.querySelector('ul')
- const liList = makeArray(fixtureEl.querySelectorAll('li'))
- const result = makeArray(SelectorEngine.children(list, 'li'))
-
- expect(result).toEqual(liList)
- })
- })
-
- describe('parents', () => {
- it('should return parents', () => {
- expect(SelectorEngine.parents(fixtureEl, 'body').length).toEqual(1)
- })
- })
-
- describe('prev', () => {
- it('should return previous element', () => {
- fixtureEl.innerHTML = '<div class="test"></div><button class="btn"></button>'
-
- const btn = fixtureEl.querySelector('.btn')
- const divTest = fixtureEl.querySelector('.test')
-
- expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
- })
-
- it('should return previous element with an extra element between', () => {
- fixtureEl.innerHTML = [
- '<div class="test"></div>',
- '<span></span>',
- '<button class="btn"></button>'
- ].join('')
-
- const btn = fixtureEl.querySelector('.btn')
- const divTest = fixtureEl.querySelector('.test')
-
- expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
- })
- })
-})
-
diff --git a/js/src/dropdown/dropdown.js b/js/src/dropdown.js
index b84035689..06a271ef8 100644
--- a/js/src/dropdown/dropdown.js
+++ b/js/src/dropdown.js
@@ -12,12 +12,12 @@ import {
makeArray,
noop,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
import Popper from 'popper.js'
-import SelectorEngine from '../dom/selector-engine'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/dropdown/dropdown.spec.js b/js/src/dropdown/dropdown.spec.js
deleted file mode 100644
index 46374453c..000000000
--- a/js/src/dropdown/dropdown.spec.js
+++ /dev/null
@@ -1,1564 +0,0 @@
-import Popper from 'popper.js'
-
-import Dropdown from './dropdown'
-import EventHandler from '../dom/event-handler'
-
-/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Dropdown', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Dropdown.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Dropdown.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('DefaultType', () => {
- it('should return plugin default type config', () => {
- expect(Dropdown.DefaultType).toEqual(jasmine.any(Object))
- })
- })
-
- describe('constructor', () => {
- it('should create offset modifier correctly when offset option is a function', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const getOffset = offsets => offsets
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- offset: getOffset
- })
-
- const offset = dropdown._getOffset()
-
- expect(offset.offset).toBeUndefined()
- expect(typeof offset.fn).toEqual('function')
- })
-
- it('should create offset modifier correctly when offset option is not a function', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const myOffset = 7
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- offset: myOffset
- })
-
- const offset = dropdown._getOffset()
-
- expect(offset.offset).toEqual(myOffset)
- expect(offset.fn).toBeUndefined()
- })
-
- it('should add a listener on trigger which do not have data-toggle="dropdown"', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('.btn')
- const dropdown = new Dropdown(btnDropdown)
-
- spyOn(dropdown, 'toggle')
-
- btnDropdown.click()
-
- expect(dropdown.toggle).toHaveBeenCalled()
- })
-
- it('should allow to pass config to popper.js with `popperConfig`', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown, {
- popperConfig: {
- placement: 'left'
- }
- })
-
- const popperConfig = dropdown._getPopperConfig()
-
- expect(popperConfig.placement).toEqual('left')
- })
- })
-
- describe('toggle', () => {
- it('should toggle a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should destroy old popper references on toggle', done => {
- fixtureEl.innerHTML = [
- '<div class="first dropdown">',
- ' <button href="#" class="firstBtn btn" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>',
- '<div class="second dropdown">',
- ' <button href="#" class="secondBtn btn" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown1 = fixtureEl.querySelector('.firstBtn')
- const btnDropdown2 = fixtureEl.querySelector('.secondBtn')
- const firstDropdownEl = fixtureEl.querySelector('.first')
- const secondDropdownEl = fixtureEl.querySelector('.second')
- const dropdown1 = new Dropdown(btnDropdown1)
- const dropdown2 = new Dropdown(btnDropdown2)
-
- firstDropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(firstDropdownEl.classList.contains('show')).toEqual(true)
- spyOn(dropdown1._popper, 'destroy')
- dropdown2.toggle()
- })
-
- secondDropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdown1._popper.destroy).toHaveBeenCalled()
- done()
- })
-
- dropdown1.toggle()
- })
-
- it('should toggle a dropdown and add/remove event listener on mobile', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const defaultValueOnTouchStart = document.documentElement.ontouchstart
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- document.documentElement.ontouchstart = () => {}
- spyOn(EventHandler, 'on')
- spyOn(EventHandler, 'off')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- expect(EventHandler.on).toHaveBeenCalled()
-
- dropdown.toggle()
- })
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(false)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- expect(EventHandler.off).toHaveBeenCalled()
-
- document.documentElement.ontouchstart = defaultValueOnTouchStart
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropdown at the right', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu dropdown-menu-right">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropup', done => {
- fixtureEl.innerHTML = [
- '<div class="dropup">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropupEl = fixtureEl.querySelector('.dropup')
- const dropdown = new Dropdown(btnDropdown)
-
- dropupEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropupEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropup at the right', done => {
- fixtureEl.innerHTML = [
- '<div class="dropup">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu dropdown-menu-right">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropupEl = fixtureEl.querySelector('.dropup')
- const dropdown = new Dropdown(btnDropdown)
-
- dropupEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropupEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropright', done => {
- fixtureEl.innerHTML = [
- '<div class="dropright">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const droprightEl = fixtureEl.querySelector('.dropright')
- const dropdown = new Dropdown(btnDropdown)
-
- droprightEl.addEventListener('shown.bs.dropdown', () => {
- expect(droprightEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropleft', done => {
- fixtureEl.innerHTML = [
- '<div class="dropleft">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropleftEl = fixtureEl.querySelector('.dropleft')
- const dropdown = new Dropdown(btnDropdown)
-
- dropleftEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropleftEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropdown with parent reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown, {
- reference: 'parent'
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropdown with a dom node reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown, {
- reference: fixtureEl
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should toggle a dropdown with a jquery object reference', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown, {
- reference: { 0: fixtureEl, jquery: 'jQuery' }
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- done()
- })
-
- dropdown.toggle()
- })
-
- it('should not toggle a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.toggle()
-
- setTimeout(() => {
- expect().nothing()
- done()
- })
- })
-
- it('should not toggle a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle disabled" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.toggle()
-
- setTimeout(() => {
- expect().nothing()
- done()
- })
- })
-
- it('should not toggle a dropdown if the menu is shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.toggle()
-
- setTimeout(() => {
- expect().nothing()
- done()
- })
- })
-
- it('should not toggle a dropdown if show event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('show.bs.dropdown', e => {
- e.preventDefault()
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.toggle()
-
- setTimeout(() => {
- expect().nothing()
- done()
- })
- })
- })
-
- describe('show', () => {
- it('should show a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- done()
- })
-
- dropdown.show()
- })
-
- it('should not show a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.show()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
-
- it('should not show a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle disabled" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.show()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
-
- it('should not show a dropdown if the menu is shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.show()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
-
- it('should not show a dropdown if show event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('show.bs.dropdown', e => {
- e.preventDefault()
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- throw new Error('should not throw shown.bs.dropdown event')
- })
-
- dropdown.show()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
- })
-
- describe('hide', () => {
- it('should hide a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownMenu.classList.contains('show')).toEqual(false)
- done()
- })
-
- dropdown.hide()
- })
-
- it('should hide a dropdown and destroy popper', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- spyOn(dropdown._popper, 'destroy')
- dropdown.hide()
- })
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdown._popper.destroy).toHaveBeenCalled()
- done()
- })
-
- dropdown.show()
- })
-
- it('should not hide a dropdown if the element is disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
-
- dropdown.hide()
-
- setTimeout(() => {
- expect(dropdownMenu.classList.contains('show')).toEqual(true)
- done()
- }, 10)
- })
-
- it('should not hide a dropdown if the element contains .disabled', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle disabled" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
-
- dropdown.hide()
-
- setTimeout(() => {
- expect(dropdownMenu.classList.contains('show')).toEqual(true)
- done()
- }, 10)
- })
-
- it('should not hide a dropdown if the menu is not shown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
-
- dropdown.hide()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
-
- it('should not hide a dropdown if hide event is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu show">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdownEl.addEventListener('hide.bs.dropdown', e => {
- e.preventDefault()
- })
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- throw new Error('should not throw hidden.bs.dropdown event')
- })
-
- dropdown.hide()
-
- setTimeout(() => {
- expect(dropdownMenu.classList.contains('show')).toEqual(true)
- done()
- })
- })
- })
-
- describe('dispose', () => {
- it('should dispose dropdown', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
-
- expect(dropdown._popper).toBeNull()
- expect(dropdown._menu).toBeDefined()
- expect(dropdown._element).toBeDefined()
-
- dropdown.dispose()
-
- expect(dropdown._menu).toBeNull()
- expect(dropdown._element).toBeNull()
- })
-
- it('should dispose dropdown with popper.js', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdown.toggle()
-
- expect(dropdown._popper).toBeDefined()
- expect(dropdown._menu).toBeDefined()
- expect(dropdown._element).toBeDefined()
-
- spyOn(Popper.prototype, 'destroy')
-
- dropdown.dispose()
-
- expect(dropdown._popper).toBeNull()
- expect(dropdown._menu).toBeNull()
- expect(dropdown._element).toBeNull()
- expect(Popper.prototype.destroy).toHaveBeenCalled()
- })
- })
-
- describe('update', () => {
- it('should call popper.js and detect navbar on update', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
-
- dropdown.toggle()
-
- expect(dropdown._popper).toBeDefined()
-
- spyOn(dropdown._popper, 'scheduleUpdate')
- spyOn(dropdown, '_detectNavbar')
-
- dropdown.update()
-
- expect(dropdown._popper.scheduleUpdate).toHaveBeenCalled()
- expect(dropdown._detectNavbar).toHaveBeenCalled()
- })
-
- it('should just detect navbar on update', () => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(btnDropdown)
-
- spyOn(dropdown, '_detectNavbar')
-
- dropdown.update()
-
- expect(dropdown._popper).toBeNull()
- expect(dropdown._detectNavbar).toHaveBeenCalled()
- })
- })
-
- describe('data-api', () => {
- it('should not add class position-static to dropdown if boundary not set', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('position-static')).toEqual(false)
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should add class position-static to dropdown if boundary not scrollParent', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" data-boundary="viewport">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('position-static')).toEqual(true)
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should show and hide a dropdown', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- let showEventTriggered = false
- let hideEventTriggered = false
-
- dropdownEl.addEventListener('show.bs.dropdown', () => {
- showEventTriggered = true
- })
-
- dropdownEl.addEventListener('shown.bs.dropdown', e => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
- expect(showEventTriggered).toEqual(true)
- expect(e.relatedTarget).toEqual(btnDropdown)
- document.body.click()
- })
-
- dropdownEl.addEventListener('hide.bs.dropdown', () => {
- hideEventTriggered = true
- })
-
- dropdownEl.addEventListener('hidden.bs.dropdown', e => {
- expect(dropdownEl.classList.contains('show')).toEqual(false)
- expect(btnDropdown.getAttribute('aria-expanded')).toEqual('false')
- expect(hideEventTriggered).toEqual(true)
- expect(e.relatedTarget).toEqual(btnDropdown)
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should not use popper.js in navbar', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar navbar-expand-md navbar-light bg-light">',
- ' <div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- ' </div>',
- '</nav>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownMenu.getAttribute('style')).toEqual(null, 'no inline style applied by popper.js')
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should not use popper.js if display set to static', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown" data-display="static">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
- const dropdownMenu = fixtureEl.querySelector('.dropdown-menu')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- // popper.js add this attribute when we use it
- expect(dropdownMenu.getAttribute('x-placement')).toEqual(null)
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should remove "show" class if tabbing outside of menu', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdownEl = fixtureEl.querySelector('.dropdown')
-
- dropdownEl.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(true)
-
- const keyUp = createEvent('keyup')
-
- keyUp.which = 9 // Tab
- document.dispatchEvent(keyUp)
- })
-
- dropdownEl.addEventListener('hidden.bs.dropdown', () => {
- expect(dropdownEl.classList.contains('show')).toEqual(false)
- done()
- })
-
- btnDropdown.click()
- })
-
- it('should remove "show" class if body is clicked, with multiple dropdowns', done => {
- fixtureEl.innerHTML = [
- '<div class="nav">',
- ' <div class="dropdown" id="testmenu">',
- ' <a class="dropdown-toggle" data-toggle="dropdown" href="#testmenu">Test menu <span class="caret"/></a>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- ' </div>',
- '</div>',
- '<div class="btn-group">',
- ' <button class="btn">Actions</button>',
- ' <button class="btn dropdown-toggle" data-toggle="dropdown"></button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Action 1</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdownList = fixtureEl.querySelectorAll('[data-toggle="dropdown"]')
-
- expect(triggerDropdownList.length).toEqual(2)
-
- const first = triggerDropdownList[0]
- const last = triggerDropdownList[1]
- const dropdownTestMenu = first.parentNode
- const btnGroup = last.parentNode
-
- dropdownTestMenu.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownTestMenu.classList.contains('show')).toEqual(true)
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1)
- document.body.click()
- })
-
- dropdownTestMenu.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0)
- last.click()
- })
-
- btnGroup.addEventListener('shown.bs.dropdown', () => {
- expect(btnGroup.classList.contains('show')).toEqual(true)
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1)
- document.body.click()
- })
-
- btnGroup.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0)
- done()
- })
-
- first.click()
- })
-
- it('should remove "show" class if body if tabbing outside of menu, with multiple dropdowns', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <a class="dropdown-toggle" data-toggle="dropdown" href="#testmenu">Test menu</a>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- '</div>',
- '<div class="btn-group">',
- ' <button class="btn">Actions</button>',
- ' <button class="btn dropdown-toggle" data-toggle="dropdown"></button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Action 1</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdownList = fixtureEl.querySelectorAll('[data-toggle="dropdown"]')
-
- expect(triggerDropdownList.length).toEqual(2)
-
- const first = triggerDropdownList[0]
- const last = triggerDropdownList[1]
- const dropdownTestMenu = first.parentNode
- const btnGroup = last.parentNode
-
- dropdownTestMenu.addEventListener('shown.bs.dropdown', () => {
- expect(dropdownTestMenu.classList.contains('show')).toEqual(true, '"show" class added on click')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1, 'only one dropdown is shown')
-
- const keyUp = createEvent('keyup')
- keyUp.which = 9 // Tab
-
- document.dispatchEvent(keyUp)
- })
-
- dropdownTestMenu.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0, '"show" class removed')
- last.click()
- })
-
- btnGroup.addEventListener('shown.bs.dropdown', () => {
- expect(btnGroup.classList.contains('show')).toEqual(true, '"show" class added on click')
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(1, 'only one dropdown is shown')
-
- const keyUp = createEvent('keyup')
- keyUp.which = 9 // Tab
-
- document.dispatchEvent(keyUp)
- })
-
- btnGroup.addEventListener('hidden.bs.dropdown', () => {
- expect(fixtureEl.querySelectorAll('.dropdown-menu.show').length).toEqual(0, '"show" class removed')
- done()
- })
-
- first.click()
- })
-
- it('should fire hide and hidden event without a clickEvent if event type is not click', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
-
- dropdown.addEventListener('hide.bs.dropdown', e => {
- expect(e.clickEvent).toBeUndefined()
- })
-
- dropdown.addEventListener('hidden.bs.dropdown', e => {
- expect(e.clickEvent).toBeUndefined()
- done()
- })
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- const keyDown = createEvent('keydown')
-
- keyDown.which = 27
- triggerDropdown.dispatchEvent(keyDown)
- })
-
- triggerDropdown.click()
- })
-
- it('should ignore keyboard events within <input>s and <textarea>s', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' <input type="text" />',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
- const input = fixtureEl.querySelector('input')
- const textarea = fixtureEl.querySelector('textarea')
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- input.focus()
- const keyDown = createEvent('keydown')
-
- keyDown.which = 38
- input.dispatchEvent(keyDown)
-
- expect(document.activeElement).toEqual(input, 'input still focused')
-
- textarea.focus()
- textarea.dispatchEvent(keyDown)
-
- expect(document.activeElement).toEqual(textarea, 'textarea still focused')
- done()
- })
-
- triggerDropdown.click()
- })
-
- it('should skip disabled element when using keyboard navigation', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item disabled" href="#sub1">Submenu 1</a>',
- ' <button class="dropdown-item" type="button" disabled>Disabled button</button>',
- ' <a id="item1" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- const keyDown = createEvent('keydown')
- keyDown.which = 40
-
- triggerDropdown.dispatchEvent(keyDown)
- triggerDropdown.dispatchEvent(keyDown)
-
- expect(document.activeElement.classList.contains('disabled')).toEqual(false, '.disabled not focused')
- expect(document.activeElement.hasAttribute('disabled')).toEqual(false, ':disabled not focused')
- done()
- })
-
- triggerDropdown.click()
- })
-
- it('should focus next/previous element when using keyboard navigation', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a id="item1" class="dropdown-item" href="#">A link</a>',
- ' <a id="item2" class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
- const item1 = fixtureEl.querySelector('#item1')
- const item2 = fixtureEl.querySelector('#item2')
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- const keyDown40 = createEvent('keydown')
- keyDown40.which = 40
-
- triggerDropdown.dispatchEvent(keyDown40)
- expect(document.activeElement).toEqual(item1, 'item1 is focused')
-
- document.activeElement.dispatchEvent(keyDown40)
- expect(document.activeElement).toEqual(item2, 'item2 is focused')
-
- const keyDown38 = createEvent('keydown')
- keyDown38.which = 38
-
- document.activeElement.dispatchEvent(keyDown38)
- expect(document.activeElement).toEqual(item1, 'item1 is focused')
-
- done()
- })
-
- triggerDropdown.click()
- })
-
- it('should not close the dropdown if the user clicks on a text field', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <input type="text" />',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
- const input = fixtureEl.querySelector('input')
-
- input.addEventListener('click', () => {
- expect(dropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown')
- done()
- })
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- expect(dropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown')
- input.dispatchEvent(createEvent('click'))
- })
-
- triggerDropdown.click()
- })
-
- it('should not close the dropdown if the user clicks on a textarea', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
- const textarea = fixtureEl.querySelector('textarea')
-
- textarea.addEventListener('click', () => {
- expect(dropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown')
- done()
- })
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- expect(dropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown')
- textarea.dispatchEvent(createEvent('click'))
- })
-
- triggerDropdown.click()
- })
-
- it('should ignore keyboard events for <input>s and <textarea>s within dropdown-menu, except for escape key', done => {
- fixtureEl.innerHTML = [
- '<div class="dropdown">',
- ' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#sub1">Submenu 1</a>',
- ' <input type="text" />',
- ' <textarea></textarea>',
- ' </div>',
- '</div>'
- ].join('')
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = fixtureEl.querySelector('.dropdown')
- const input = fixtureEl.querySelector('input')
- const textarea = fixtureEl.querySelector('textarea')
-
- // Space key
- const keyDownSpace = createEvent('keydown')
- keyDownSpace.which = 32
-
- // Key up
- const keyDownUp = createEvent('keydown')
- keyDownSpace.which = 38
-
- // Key down
- const keyDown = createEvent('keydown')
- keyDownSpace.which = 40
-
- // Key escape
- const keyDownEscape = createEvent('keydown')
- keyDownEscape.which = 27
-
- dropdown.addEventListener('shown.bs.dropdown', () => {
- // Space key
- input.focus()
- input.dispatchEvent(keyDownSpace)
-
- expect(document.activeElement).toEqual(input, 'input still focused')
-
- textarea.focus()
- textarea.dispatchEvent(keyDownSpace)
-
- expect(document.activeElement).toEqual(textarea, 'textarea still focused')
-
- // Key up
- input.focus()
- input.dispatchEvent(keyDownUp)
-
- expect(document.activeElement).toEqual(input, 'input still focused')
-
- textarea.focus()
- textarea.dispatchEvent(keyDownUp)
-
- expect(document.activeElement).toEqual(textarea, 'textarea still focused')
-
- // Key down
- input.focus()
- input.dispatchEvent(keyDown)
-
- expect(document.activeElement).toEqual(input, 'input still focused')
-
- textarea.focus()
- textarea.dispatchEvent(keyDown)
-
- expect(document.activeElement).toEqual(textarea, 'textarea still focused')
-
- // Key escape
- input.focus()
- input.dispatchEvent(keyDownEscape)
-
- expect(dropdown.classList.contains('show')).toEqual(false, 'dropdown menu is not shown')
- done()
- })
-
- triggerDropdown.click()
- })
-
- it('should not open dropdown if escape key was pressed on the toggle', done => {
- fixtureEl.innerHTML = [
- '<div class="tabs">',
- ' <div class="dropdown">',
- ' <button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item" href="#">Secondary link</a>',
- ' <a class="dropdown-item" href="#">Something else here</a>',
- ' <div class="divider"/>',
- ' <a class="dropdown-item" href="#">Another link</a>',
- ' </div>',
- ' </div>',
- '</div>'
- ]
-
- const triggerDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
- const dropdown = new Dropdown(triggerDropdown)
- const button = fixtureEl.querySelector('button[data-toggle="dropdown"]')
-
- spyOn(dropdown, 'toggle')
-
- // Key escape
- button.focus()
- // Key escape
- const keyDownEscape = createEvent('keydown')
- keyDownEscape.which = 27
- button.dispatchEvent(keyDownEscape)
-
- setTimeout(() => {
- expect(dropdown.toggle).not.toHaveBeenCalled()
- expect(triggerDropdown.parentNode.classList.contains('show')).toEqual(false)
- done()
- }, 20)
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a dropdown', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.dropdown = Dropdown.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.dropdown.call(jQueryMock)
-
- expect(Dropdown.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a dropdown', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const dropdown = new Dropdown(div)
-
- jQueryMock.fn.dropdown = Dropdown.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.dropdown.call(jQueryMock)
-
- expect(Dropdown.getInstance(div)).toEqual(dropdown)
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.dropdown = Dropdown.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.dropdown.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('getInstance', () => {
- it('should return dropdown instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const dropdown = new Dropdown(div)
-
- expect(Dropdown.getInstance(div)).toEqual(dropdown)
- })
-
- it('should return null when there is no dropdown instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Dropdown.getInstance(div)).toEqual(null)
- })
- })
-})
diff --git a/js/src/modal/modal.js b/js/src/modal.js
index 4864cad9d..bee5e23f8 100644
--- a/js/src/modal/modal.js
+++ b/js/src/modal.js
@@ -15,11 +15,11 @@ import {
makeArray,
reflow,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/modal/modal.spec.js b/js/src/modal/modal.spec.js
deleted file mode 100644
index 292f61f8b..000000000
--- a/js/src/modal/modal.spec.js
+++ /dev/null
@@ -1,987 +0,0 @@
-import Modal from './modal'
-import EventHandler from '../dom/event-handler'
-import { makeArray } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Modal', () => {
- let fixtureEl
- let style
-
- beforeAll(() => {
- fixtureEl = getFixture()
-
- // Enable the scrollbar measurer
- const css = '.modal-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; }'
-
- style = document.createElement('style')
- style.type = 'text/css'
- style.appendChild(document.createTextNode(css))
-
- document.head.appendChild(style)
-
- // Simulate scrollbars
- document.documentElement.style.paddingRight = '16px'
- })
-
- afterEach(() => {
- clearFixture()
-
- document.body.classList.remove('modal-open')
- document.body.removeAttribute('style')
- document.body.removeAttribute('data-padding-right')
- const backdropList = makeArray(document.querySelectorAll('.modal-backdrop'))
-
- backdropList.forEach(backdrop => {
- document.body.removeChild(backdrop)
- })
-
- document.body.style.paddingRight = '0px'
- })
-
- afterAll(() => {
- document.head.removeChild(style)
- document.documentElement.style.paddingRight = '0px'
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Modal.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Modal.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('toggle', () => {
- it('should toggle a modal', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
- const originalPadding = '0px'
-
- document.body.style.paddingRight = originalPadding
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(document.body.getAttribute('data-padding-right')).toEqual(originalPadding, 'original body padding should be stored in data-padding-right')
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(document.body.getAttribute('data-padding-right')).toBeNull()
- expect().nothing()
- done()
- })
-
- modal.toggle()
- })
-
- it('should adjust the inline padding of fixed elements when opening and restore when closing', done => {
- fixtureEl.innerHTML = [
- '<div class="fixed-top" style="padding-right: 0px"></div>',
- '<div class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const fixedEl = fixtureEl.querySelector('.fixed-top')
- const originalPadding = parseInt(window.getComputedStyle(fixedEl).paddingRight, 10)
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const expectedPadding = originalPadding + modal._getScrollbarWidth()
- const currentPadding = parseInt(window.getComputedStyle(modalEl).paddingRight, 10)
-
- expect(fixedEl.getAttribute('data-padding-right')).toEqual('0px', 'original fixed element padding should be stored in data-padding-right')
- expect(currentPadding).toEqual(expectedPadding, 'fixed element padding should be adjusted while opening')
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- const currentPadding = parseInt(window.getComputedStyle(modalEl).paddingRight, 10)
-
- expect(fixedEl.getAttribute('data-padding-right')).toEqual(null, 'data-padding-right should be cleared after closing')
- expect(currentPadding).toEqual(originalPadding, 'fixed element padding should be reset after closing')
- done()
- })
-
- modal.toggle()
- })
-
- it('should adjust the inline margin of sticky elements when opening and restore when closing', done => {
- fixtureEl.innerHTML = [
- '<div class="sticky-top" style="margin-right: 0px;"></div>',
- '<div class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const stickyTopEl = fixtureEl.querySelector('.sticky-top')
- const originalMargin = parseInt(window.getComputedStyle(stickyTopEl).marginRight, 10)
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const expectedMargin = originalMargin - modal._getScrollbarWidth()
- const currentMargin = parseInt(window.getComputedStyle(stickyTopEl).marginRight, 10)
-
- expect(stickyTopEl.getAttribute('data-margin-right')).toEqual('0px', 'original sticky element margin should be stored in data-margin-right')
- expect(currentMargin).toEqual(expectedMargin, 'sticky element margin should be adjusted while opening')
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- const currentMargin = parseInt(window.getComputedStyle(stickyTopEl).marginRight, 10)
-
- expect(stickyTopEl.getAttribute('data-margin-right')).toEqual(null, 'data-margin-right should be cleared after closing')
- expect(currentMargin).toEqual(originalMargin, 'sticky element margin should be reset after closing')
- done()
- })
-
- modal.toggle()
- })
-
- it('should ignore values set via CSS when trying to restore body padding after closing', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
- const styleTest = document.createElement('style')
-
- styleTest.type = 'text/css'
- styleTest.appendChild(document.createTextNode('body { padding-right: 7px; }'))
- document.head.appendChild(styleTest)
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(window.getComputedStyle(document.body).paddingLeft).toEqual('0px', 'body does not have inline padding set')
- document.head.removeChild(styleTest)
- done()
- })
-
- modal.toggle()
- })
-
- it('should ignore other inline styles when trying to restore body padding after closing', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
- const styleTest = document.createElement('style')
-
- styleTest.type = 'text/css'
- styleTest.appendChild(document.createTextNode('body { padding-right: 7px; }'))
-
- document.head.appendChild(styleTest)
- document.body.style.color = 'red'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- const bodyPaddingRight = document.body.style.paddingRight
-
- expect(bodyPaddingRight === '0px' || bodyPaddingRight === '').toEqual(true, 'body does not have inline padding set')
- expect(document.body.style.color).toEqual('red', 'body still has other inline styles set')
- document.head.removeChild(styleTest)
- document.body.removeAttribute('style')
- done()
- })
-
- modal.toggle()
- })
-
- it('should properly restore non-pixel inline body padding after closing', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- document.body.style.paddingRight = '5%'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modal.toggle()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(document.body.style.paddingRight).toEqual('5%')
- document.body.removeAttribute('style')
- done()
- })
-
- modal.toggle()
- })
- })
-
- describe('show', () => {
- it('should show a modal', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('show.bs.modal', e => {
- expect(e).toBeDefined()
- })
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual('true')
- expect(modalEl.getAttribute('aria-hidden')).toEqual(null)
- expect(modalEl.style.display).toEqual('block')
- expect(document.querySelector('.modal-backdrop')).toBeDefined()
- done()
- })
-
- modal.show()
- })
-
- it('should show a modal without backdrop', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl, {
- backdrop: false
- })
-
- modalEl.addEventListener('show.bs.modal', e => {
- expect(e).toBeDefined()
- })
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual('true')
- expect(modalEl.getAttribute('aria-hidden')).toEqual(null)
- expect(modalEl.style.display).toEqual('block')
- expect(document.querySelector('.modal-backdrop')).toBeNull()
- done()
- })
-
- modal.show()
- })
-
- it('should show a modal and append the element', done => {
- const modalEl = document.createElement('div')
- const id = 'dynamicModal'
-
- modalEl.setAttribute('id', id)
- modalEl.classList.add('modal')
- modalEl.innerHTML = '<div class="modal-dialog"></div>'
-
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const dynamicModal = document.getElementById(id)
- expect(dynamicModal).toBeDefined()
- dynamicModal.parentNode.removeChild(dynamicModal)
- done()
- })
-
- modal.show()
- })
-
- it('should do nothing if a modal is shown', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(EventHandler, 'trigger')
- modal._isShown = true
-
- modal.show()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should do nothing if a modal is transitioning', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(EventHandler, 'trigger')
- modal._isTransitioning = true
-
- modal.show()
-
- expect(EventHandler.trigger).not.toHaveBeenCalled()
- })
-
- it('should not fire shown event when show is prevented', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('show.bs.modal', e => {
- e.preventDefault()
-
- const expectedDone = () => {
- expect().nothing()
- done()
- }
-
- setTimeout(expectedDone, 10)
- })
-
- modalEl.addEventListener('shown.bs.modal', () => {
- throw new Error('shown event triggered')
- })
-
- modal.show()
- })
-
- it('should set is transitioning if fade class is present', done => {
- fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('show.bs.modal', () => {
- expect(modal._isTransitioning).toEqual(true)
- })
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modal._isTransitioning).toEqual(false)
- done()
- })
-
- modal.show()
- })
-
- it('should close modal when a click occurred on data-dismiss="modal"', done => {
- fixtureEl.innerHTML = [
- '<div class="modal fade">',
- ' <div class="modal-dialog">',
- ' <div class="modal-header">',
- ' <button type="button" data-dismiss="modal"></button>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const btnClose = fixtureEl.querySelector('[data-dismiss="modal"]')
- const modal = new Modal(modalEl)
-
- spyOn(modal, 'hide').and.callThrough()
-
- modalEl.addEventListener('shown.bs.modal', () => {
- btnClose.click()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(modal.hide).toHaveBeenCalled()
- done()
- })
-
- modal.show()
- })
-
- it('should set modal body scroll top to 0 if .modal-dialog-scrollable', done => {
- fixtureEl.innerHTML = [
- '<div class="modal fade">',
- ' <div class="modal-dialog modal-dialog-scrollable">',
- ' <div class="modal-body"></div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modalBody = modalEl.querySelector('.modal-body')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalBody.scrollTop).toEqual(0)
- done()
- })
-
- modal.show()
- })
-
- it('should set .modal\'s scroll top to 0 if .modal-dialog-scrollable and modal body do not exists', done => {
- fixtureEl.innerHTML = [
- '<div class="modal fade">',
- ' <div class="modal-dialog modal-dialog-scrollable">',
- ' </div>',
- '</div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalEl.scrollTop).toEqual(0)
- done()
- })
-
- modal.show()
- })
-
- it('should not enforce focus if focus equal to false', done => {
- fixtureEl.innerHTML = '<div class="modal fade"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl, {
- focus: false
- })
-
- spyOn(modal, '_enforceFocus')
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modal._enforceFocus).not.toHaveBeenCalled()
- done()
- })
-
- modal.show()
- })
-
- it('should add listener when escape touch is pressed', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(modal, 'hide').and.callThrough()
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const keydownEscape = createEvent('keydown')
- keydownEscape.which = 27
-
- modalEl.dispatchEvent(keydownEscape)
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(modal.hide).toHaveBeenCalled()
- done()
- })
-
- modal.show()
- })
-
- it('should do nothing when the pressed key is not escape', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(modal, 'hide')
-
- const expectDone = () => {
- expect(modal.hide).not.toHaveBeenCalled()
-
- done()
- }
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const keydownTab = createEvent('keydown')
- keydownTab.which = 9
-
- modalEl.dispatchEvent(keydownTab)
- setTimeout(expectDone, 30)
- })
-
- modal.show()
- })
-
- it('should adjust dialog on resize', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(modal, '_adjustDialog').and.callThrough()
-
- const expectDone = () => {
- expect(modal._adjustDialog).toHaveBeenCalled()
-
- done()
- }
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const resizeEvent = createEvent('resize')
-
- window.dispatchEvent(resizeEvent)
- setTimeout(expectDone, 10)
- })
-
- modal.show()
- })
-
- it('should not close modal when clicking outside of modal-content if backdrop = false', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl, {
- backdrop: false
- })
-
- const shownCallback = () => {
- setTimeout(() => {
- expect(modal._isShown).toEqual(true)
- done()
- }, 10)
- }
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modalEl.click()
- shownCallback()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- throw new Error('Should not hide a modal')
- })
-
- modal.show()
- })
-
- it('should not adjust the inline body padding when it does not overflow', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
- const originalPadding = window.getComputedStyle(document.body).paddingRight
-
- // Hide scrollbars to prevent the body overflowing
- document.body.style.overflow = 'hidden'
- document.documentElement.style.paddingRight = '0px'
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const currentPadding = window.getComputedStyle(document.body).paddingRight
-
- expect(currentPadding).toEqual(originalPadding, 'body padding should not be adjusted')
-
- // Restore scrollbars
- document.body.style.overflow = 'auto'
- document.documentElement.style.paddingRight = '16px'
- done()
- })
-
- modal.show()
- })
-
- it('should enforce focus', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const isIE11 = Boolean(window.MSInputMethodContext) && Boolean(document.documentMode)
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(modal, '_enforceFocus').and.callThrough()
-
- const focusInListener = () => {
- expect(modal._element.focus).toHaveBeenCalled()
- document.removeEventListener('focusin', focusInListener)
- done()
- }
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modal._enforceFocus).toHaveBeenCalled()
-
- if (isIE11) {
- done()
- return
- }
-
- spyOn(modal._element, 'focus')
-
- document.addEventListener('focusin', focusInListener)
-
- const focusInEvent = createEvent('focusin', { bubbles: true })
- Object.defineProperty(focusInEvent, 'target', {
- value: fixtureEl
- })
-
- document.dispatchEvent(focusInEvent)
- })
-
- modal.show()
- })
- })
-
- describe('hide', () => {
- it('should hide a modal', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modal.hide()
- })
-
- modalEl.addEventListener('hide.bs.modal', e => {
- expect(e).toBeDefined()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual(null)
- expect(modalEl.getAttribute('aria-hidden')).toEqual('true')
- expect(modalEl.style.display).toEqual('none')
- expect(document.querySelector('.modal-backdrop')).toBeNull()
- done()
- })
-
- modal.show()
- })
-
- it('should close modal when clicking outside of modal-content', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modalEl.click()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual(null)
- expect(modalEl.getAttribute('aria-hidden')).toEqual('true')
- expect(modalEl.style.display).toEqual('none')
- expect(document.querySelector('.modal-backdrop')).toBeNull()
- done()
- })
-
- modal.show()
- })
-
- it('should do nothing is the modal is not shown', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modal.hide()
-
- expect().nothing()
- })
-
- it('should do nothing is the modal is transitioning', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modal._isTransitioning = true
- modal.hide()
-
- expect().nothing()
- })
-
- it('should not hide a modal if hide is prevented', done => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- modalEl.addEventListener('shown.bs.modal', () => {
- modal.hide()
- })
-
- const hideCallback = () => {
- setTimeout(() => {
- expect(modal._isShown).toEqual(true)
- done()
- }, 10)
- }
-
- modalEl.addEventListener('hide.bs.modal', e => {
- e.preventDefault()
- hideCallback()
- })
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- throw new Error('should not trigger hidden')
- })
-
- modal.show()
- })
- })
-
- describe('dispose', () => {
- it('should dispose a modal', () => {
- fixtureEl.innerHTML = '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- expect(Modal.getInstance(modalEl)).toEqual(modal)
-
- spyOn(EventHandler, 'off')
-
- modal.dispose()
-
- expect(Modal.getInstance(modalEl)).toEqual(null)
- expect(EventHandler.off).toHaveBeenCalledTimes(4)
- })
- })
-
- describe('handleUpdate', () => {
- it('should call adjust dialog', () => {
- fixtureEl.innerHTML = '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
-
- spyOn(modal, '_adjustDialog')
-
- modal.handleUpdate()
-
- expect(modal._adjustDialog).toHaveBeenCalled()
- })
- })
-
- describe('data-api', () => {
- it('should open modal', done => {
- fixtureEl.innerHTML = [
- '<button type="button" data-toggle="modal" data-target="#exampleModal"></button>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual('true')
- expect(modalEl.getAttribute('aria-hidden')).toEqual(null)
- expect(modalEl.style.display).toEqual('block')
- expect(document.querySelector('.modal-backdrop')).toBeDefined()
- done()
- })
-
- trigger.click()
- })
-
- it('should not recreate a new modal', done => {
- fixtureEl.innerHTML = [
- '<button type="button" data-toggle="modal" data-target="#exampleModal"></button>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const modal = new Modal(modalEl)
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- spyOn(modal, 'show').and.callThrough()
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modal.show).toHaveBeenCalled()
- done()
- })
-
- trigger.click()
- })
-
- it('should prevent default when the trigger is <a> or <area>', done => {
- fixtureEl.innerHTML = [
- '<a data-toggle="modal" href="#" data-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- spyOn(Event.prototype, 'preventDefault').and.callThrough()
-
- modalEl.addEventListener('shown.bs.modal', () => {
- expect(modalEl.getAttribute('aria-modal')).toEqual('true')
- expect(modalEl.getAttribute('aria-hidden')).toEqual(null)
- expect(modalEl.style.display).toEqual('block')
- expect(document.querySelector('.modal-backdrop')).toBeDefined()
- expect(Event.prototype.preventDefault).toHaveBeenCalled()
- done()
- })
-
- trigger.click()
- })
-
- it('should focus the trigger on hide', done => {
- fixtureEl.innerHTML = [
- '<a data-toggle="modal" href="#" data-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- spyOn(trigger, 'focus')
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const modal = Modal.getInstance(modalEl)
-
- modal.hide()
- })
-
- const hideListener = () => {
- setTimeout(() => {
- expect(trigger.focus).toHaveBeenCalled()
- done()
- }, 20)
- }
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- hideListener()
- })
-
- trigger.click()
- })
-
- it('should not focus the trigger if the modal is not visible', done => {
- fixtureEl.innerHTML = [
- '<a data-toggle="modal" href="#" data-target="#exampleModal" style="display: none;"></a>',
- '<div id="exampleModal" class="modal" style="display: none;"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- spyOn(trigger, 'focus')
-
- modalEl.addEventListener('shown.bs.modal', () => {
- const modal = Modal.getInstance(modalEl)
-
- modal.hide()
- })
-
- const hideListener = () => {
- setTimeout(() => {
- expect(trigger.focus).not.toHaveBeenCalled()
- done()
- }, 20)
- }
-
- modalEl.addEventListener('hidden.bs.modal', () => {
- hideListener()
- })
-
- trigger.click()
- })
-
- it('should not focus the trigger if the modal is not shown', done => {
- fixtureEl.innerHTML = [
- '<a data-toggle="modal" href="#" data-target="#exampleModal"></a>',
- '<div id="exampleModal" class="modal"><div class="modal-dialog" /></div>'
- ].join('')
-
- const modalEl = fixtureEl.querySelector('.modal')
- const trigger = fixtureEl.querySelector('[data-toggle="modal"]')
-
- spyOn(trigger, 'focus')
-
- const showListener = () => {
- setTimeout(() => {
- expect(trigger.focus).not.toHaveBeenCalled()
- done()
- }, 10)
- }
-
- modalEl.addEventListener('show.bs.modal', e => {
- e.preventDefault()
- showListener()
- })
-
- trigger.click()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a modal', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.modal = Modal.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.modal.call(jQueryMock)
-
- expect(Modal.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a modal', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
- const modal = new Modal(div)
-
- jQueryMock.fn.modal = Modal.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.modal.call(jQueryMock)
-
- expect(Modal.getInstance(div)).toEqual(modal)
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.modal = Modal.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.modal.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
-
- it('should should call show method', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
- const modal = new Modal(div)
-
- jQueryMock.fn.modal = Modal.jQueryInterface
- jQueryMock.elements = [div]
-
- spyOn(modal, 'show')
-
- jQueryMock.fn.modal.call(jQueryMock, 'show')
-
- expect(modal.show).toHaveBeenCalled()
- })
-
- it('should should not call show method', () => {
- fixtureEl.innerHTML = '<div class="modal" data-show="false"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.modal = Modal.jQueryInterface
- jQueryMock.elements = [div]
-
- spyOn(Modal.prototype, 'show')
-
- jQueryMock.fn.modal.call(jQueryMock)
-
- expect(Modal.prototype.show).not.toHaveBeenCalled()
- })
- })
-
- describe('getInstance', () => {
- it('should return modal instance', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
- const modal = new Modal(div)
-
- expect(Modal.getInstance(div)).toEqual(modal)
- })
-
- it('should return null when there is no modal instance', () => {
- fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Modal.getInstance(div)).toEqual(null)
- })
- })
-})
diff --git a/js/src/popover/popover.js b/js/src/popover.js
index 5da7ffe56..a633af4ba 100644
--- a/js/src/popover/popover.js
+++ b/js/src/popover.js
@@ -5,10 +5,10 @@
* --------------------------------------------------------------------------
*/
-import { getjQuery } from '../util/index'
-import Data from '../dom/data'
-import SelectorEngine from '../dom/selector-engine'
-import Tooltip from '../tooltip/tooltip'
+import { getjQuery } from './util/index'
+import Data from './dom/data'
+import SelectorEngine from './dom/selector-engine'
+import Tooltip from './tooltip'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/popover/popover.spec.js b/js/src/popover/popover.spec.js
deleted file mode 100644
index cf82e36ef..000000000
--- a/js/src/popover/popover.spec.js
+++ /dev/null
@@ -1,251 +0,0 @@
-import Popover from './popover'
-import { makeArray } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Popover', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
-
- const popoverList = makeArray(document.querySelectorAll('.popover'))
-
- popoverList.forEach(popoverEl => {
- document.body.removeChild(popoverEl)
- })
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Popover.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Popover.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('NAME', () => {
- it('should return plugin name', () => {
- expect(Popover.NAME).toEqual(jasmine.any(String))
- })
- })
-
- describe('DATA_KEY', () => {
- it('should return plugin data key', () => {
- expect(Popover.DATA_KEY).toEqual('bs.popover')
- })
- })
-
- describe('Event', () => {
- it('should return plugin events', () => {
- expect(Popover.Event).toEqual(jasmine.any(Object))
- })
- })
-
- describe('EVENT_KEY', () => {
- it('should return plugin event key', () => {
- expect(Popover.EVENT_KEY).toEqual('.bs.popover')
- })
- })
-
- describe('DefaultType', () => {
- it('should return plugin default type', () => {
- expect(Popover.DefaultType).toEqual(jasmine.any(Object))
- })
- })
-
- describe('show', () => {
- it('should show a popover', done => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
-
- popoverEl.addEventListener('shown.bs.popover', () => {
- expect(document.querySelector('.popover')).toBeDefined()
- done()
- })
-
- popover.show()
- })
-
- it('should set title and content from functions', done => {
- fixtureEl.innerHTML = '<a href="#">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl, {
- title: () => 'Bootstrap',
- content: () => 'loves writing tests (╯°□°)╯︵ ┻━┻'
- })
-
- popoverEl.addEventListener('shown.bs.popover', () => {
- const popoverDisplayed = document.querySelector('.popover')
-
- expect(popoverDisplayed).toBeDefined()
- expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Bootstrap')
- expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('loves writing tests (╯°□°)╯︵ ┻━┻')
- done()
- })
-
- popover.show()
- })
-
- it('should show a popover with just content', done => {
- fixtureEl.innerHTML = '<a href="#">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl, {
- content: 'Popover content'
- })
-
- popoverEl.addEventListener('shown.bs.popover', () => {
- const popoverDisplayed = document.querySelector('.popover')
-
- expect(popoverDisplayed).toBeDefined()
- expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content')
- done()
- })
-
- popover.show()
- })
- })
-
- describe('hide', () => {
- it('should hide a popover', done => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
-
- popoverEl.addEventListener('shown.bs.popover', () => {
- popover.hide()
- })
-
- popoverEl.addEventListener('hidden.bs.popover', () => {
- expect(document.querySelector('.popover')).toBeNull()
- done()
- })
-
- popover.show()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a popover', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- jQueryMock.fn.popover.call(jQueryMock)
-
- expect(Popover.getInstance(popoverEl)).toBeDefined()
- })
-
- it('should create a popover with a config object', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- jQueryMock.fn.popover.call(jQueryMock, {
- content: 'Popover content'
- })
-
- expect(Popover.getInstance(popoverEl)).toBeDefined()
- })
-
- it('should not re create a popover', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- jQueryMock.fn.popover.call(jQueryMock)
-
- expect(Popover.getInstance(popoverEl)).toEqual(popover)
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- try {
- jQueryMock.fn.popover.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
-
- it('should should call show method', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- spyOn(popover, 'show')
-
- jQueryMock.fn.popover.call(jQueryMock, 'show')
-
- expect(popover.show).toHaveBeenCalled()
- })
-
- it('should do nothing if dipose is called when a popover do not exist', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
-
- jQueryMock.fn.popover = Popover.jQueryInterface
- jQueryMock.elements = [popoverEl]
-
- spyOn(Popover.prototype, 'dispose')
-
- jQueryMock.fn.popover.call(jQueryMock, 'dispose')
-
- expect(Popover.prototype.dispose).not.toHaveBeenCalled()
- })
- })
-
- describe('getInstance', () => {
- it('should return popover instance', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
- const popover = new Popover(popoverEl)
-
- expect(Popover.getInstance(popoverEl)).toEqual(popover)
- })
-
- it('should return null when there is no popover instance', () => {
- fixtureEl.innerHTML = '<a href="#" title="Popover" data-content="https://twitter.com/getbootstrap">BS twitter</a>'
-
- const popoverEl = fixtureEl.querySelector('a')
-
- expect(Popover.getInstance(popoverEl)).toEqual(null)
- })
- })
-})
diff --git a/js/src/scrollspy/scrollspy.js b/js/src/scrollspy.js
index fa52a1289..c379c6223 100644
--- a/js/src/scrollspy/scrollspy.js
+++ b/js/src/scrollspy.js
@@ -11,11 +11,11 @@ import {
getUID,
makeArray,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/scrollspy/scrollspy.spec.js b/js/src/scrollspy/scrollspy.spec.js
deleted file mode 100644
index a019a6d1a..000000000
--- a/js/src/scrollspy/scrollspy.spec.js
+++ /dev/null
@@ -1,653 +0,0 @@
-import ScrollSpy from './scrollspy'
-import Manipulator from '../dom/manipulator'
-import EventHandler from '../dom/event-handler'
-
-/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('ScrollSpy', () => {
- let fixtureEl
-
- const testElementIsActiveAfterScroll = ({ elementSelector, targetSelector, contentEl, scrollSpy, spy, cb }) => {
- const element = fixtureEl.querySelector(elementSelector)
- const target = fixtureEl.querySelector(targetSelector)
-
- // add top padding to fix Chrome on Android failures
- const paddingTop = 5
- const scrollHeight = Math.ceil(contentEl.scrollTop + Manipulator.position(target).top) + paddingTop
-
- function listener() {
- expect(element.classList.contains('active')).toEqual(true)
- contentEl.removeEventListener('scroll', listener)
- expect(scrollSpy._process).toHaveBeenCalled()
- spy.calls.reset()
- cb()
- }
-
- contentEl.addEventListener('scroll', listener)
- contentEl.scrollTop = scrollHeight
- }
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(ScrollSpy.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(ScrollSpy.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('constructor', () => {
- it('should generate an id when there is not one', () => {
- fixtureEl.innerHTML = [
- '<nav></nav>',
- '<div class="content"></div>'
- ].join('')
-
- const navEl = fixtureEl.querySelector('nav')
- const scrollSpy = new ScrollSpy(fixtureEl.querySelector('.content'), {
- target: navEl
- })
-
- expect(scrollSpy).toBeDefined()
- expect(navEl.getAttribute('id')).not.toEqual(null)
- })
-
- it('should not process element without target', () => {
- fixtureEl.innerHTML = [
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item active"><a class="nav-link" id="one-link" href="#">One</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="two" style="height: 300px;"></div>',
- ' <div id="three" style="height: 10px;"></div>',
- '</div>'
- ].join('')
-
- const scrollSpy = new ScrollSpy(fixtureEl.querySelector('#content'), {
- target: '#navigation'
- })
-
- expect(scrollSpy._targets.length).toEqual(2)
- })
-
- it('should only switch "active" class on current target', done => {
- fixtureEl.innerHTML = [
- '<div id="root" class="active" style="display: block">',
- ' <div class="topbar">',
- ' <div class="topbar-inner">',
- ' <div class="container" id="ss-target">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
- ' <li class="nav-item"><a href="#detail">Detail</a></li>',
- ' </ul>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
- ' <div style="height: 200px;">',
- ' <h4 id="masthead">Overview</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' <div style="height: 200px;">',
- ' <h4 id="detail">Detail</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
- const rootEl = fixtureEl.querySelector('#root')
- const scrollSpy = new ScrollSpy(scrollSpyEl, {
- target: 'ss-target'
- })
-
- spyOn(scrollSpy, '_process').and.callThrough()
-
- scrollSpyEl.addEventListener('scroll', () => {
- expect(rootEl.classList.contains('active')).toEqual(true)
- expect(scrollSpy._process).toHaveBeenCalled()
- done()
- })
-
- scrollSpyEl.scrollTop = 350
- })
-
- it('should only switch "active" class on current target specified w element', done => {
- fixtureEl.innerHTML = [
- '<div id="root" class="active" style="display: block">',
- ' <div class="topbar">',
- ' <div class="topbar-inner">',
- ' <div class="container" id="ss-target">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a href="#masthead">Overview</a></li>',
- ' <li class="nav-item"><a href="#detail">Detail</a></li>',
- ' </ul>',
- ' </div>',
- ' </div>',
- ' </div>',
- ' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
- ' <div style="height: 200px;">',
- ' <h4 id="masthead">Overview</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' <div style="height: 200px;">',
- ' <h4 id="detail">Detail</h4>',
- ' <p style="height: 200px;"></p>',
- ' </div>',
- ' </div>',
- '</div>'
- ].join('')
-
- const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
- const rootEl = fixtureEl.querySelector('#root')
- const scrollSpy = new ScrollSpy(scrollSpyEl, {
- target: fixtureEl.querySelector('#ss-target')
- })
-
- spyOn(scrollSpy, '_process').and.callThrough()
-
- scrollSpyEl.addEventListener('scroll', () => {
- expect(rootEl.classList.contains('active')).toEqual(true)
- expect(scrollSpy._process).toHaveBeenCalled()
- done()
- })
-
- scrollSpyEl.scrollTop = 350
- })
-
- it('should correctly select middle navigation option when large offset is used', done => {
- fixtureEl.innerHTML = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item active"><a class="nav-link" id="one-link" href="#one">One</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="one" style="height: 500px;"></div>',
- ' <div id="two" style="height: 300px;"></div>',
- ' <div id="three" style="height: 10px;"></div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('#content')
- const scrollSpy = new ScrollSpy(contentEl, {
- target: '#navigation',
- offset: Manipulator.position(contentEl).top
- })
-
- spyOn(scrollSpy, '_process').and.callThrough()
-
- contentEl.addEventListener('scroll', () => {
- expect(fixtureEl.querySelector('#one-link').classList.contains('active')).toEqual(false)
- expect(fixtureEl.querySelector('#two-link').classList.contains('active')).toEqual(true)
- expect(fixtureEl.querySelector('#three-link').classList.contains('active')).toEqual(false)
- expect(scrollSpy._process).toHaveBeenCalled()
- done()
- })
-
- contentEl.scrollTop = 550
- })
-
- it('should add the active class to the correct element', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
- ' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const scrollSpy = new ScrollSpy(contentEl, {
- offset: 0,
- target: '.navbar'
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- testElementIsActiveAfterScroll({
- elementSelector: '#a-1',
- targetSelector: '#div-1',
- contentEl,
- scrollSpy,
- spy,
- cb: () => {
- testElementIsActiveAfterScroll({
- elementSelector: '#a-2',
- targetSelector: '#div-2',
- contentEl,
- scrollSpy,
- spy,
- cb: () => done()
- })
- }
- })
- })
-
- it('should add the active class to the correct element (nav markup)', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <nav class="nav">',
- ' <a class="nav-link" id="a-1" href="#div-1">div 1</a>',
- ' <a class="nav-link" id="a-2" href="#div-2">div 2</a>',
- ' </nav>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const scrollSpy = new ScrollSpy(contentEl, {
- offset: 0,
- target: '.navbar'
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- testElementIsActiveAfterScroll({
- elementSelector: '#a-1',
- targetSelector: '#div-1',
- contentEl,
- scrollSpy,
- spy,
- cb: () => {
- testElementIsActiveAfterScroll({
- elementSelector: '#a-2',
- targetSelector: '#div-2',
- contentEl,
- scrollSpy,
- spy,
- cb: () => done()
- })
- }
- })
- })
-
- it('should add the active class to the correct element (list-group markup)', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <div class="list-group">',
- ' <a class="list-group-item" id="a-1" href="#div-1">div 1</a>',
- ' <a class="list-group-item" id="a-2" href="#div-2">div 2</a>',
- ' </div>',
- '</nav>',
- '<div class="content" style="overflow: auto; height: 50px">',
- ' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const scrollSpy = new ScrollSpy(contentEl, {
- offset: 0,
- target: '.navbar'
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- testElementIsActiveAfterScroll({
- elementSelector: '#a-1',
- targetSelector: '#div-1',
- contentEl,
- scrollSpy,
- spy,
- cb: () => {
- testElementIsActiveAfterScroll({
- elementSelector: '#a-2',
- targetSelector: '#div-2',
- contentEl,
- scrollSpy,
- spy,
- cb: () => done()
- })
- }
- })
- })
-
- it('should clear selection if above the first section', done => {
- fixtureEl.innerHTML = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
- ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="spacer" style="height: 100px;"></div>',
- ' <div id="one" style="height: 100px;"></div>',
- ' <div id="two" style="height: 100px;"></div>',
- ' <div id="three" style="height: 100px;"></div>',
- ' <div id="spacer" style="height: 100px;"></div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('#content')
- const scrollSpy = new ScrollSpy(contentEl, {
- target: '#navigation',
- offset: Manipulator.position(contentEl).top
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- let firstTime = true
-
- contentEl.addEventListener('scroll', () => {
- const active = fixtureEl.querySelector('.active')
-
- expect(spy).toHaveBeenCalled()
- spy.calls.reset()
- if (firstTime) {
- expect(fixtureEl.querySelectorAll('.active').length).toEqual(1)
- expect(active.getAttribute('id')).toEqual('two-link')
- firstTime = false
- contentEl.scrollTop = 0
- } else {
- expect(active).toBeNull()
- done()
- }
- })
-
- contentEl.scrollTop = 201
- })
-
- it('should not clear selection if above the first section and first section is at the top', done => {
- fixtureEl.innerHTML = [
- '<div id="header" style="height: 500px;"></div>',
- '<nav id="navigation" class="navbar">',
- ' <ul class="navbar-nav">',
- ' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
- ' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
- ' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
- ' </ul>',
- '</nav>',
- '<div id="content" style="height: 200px; overflow-y: auto;">',
- ' <div id="one" style="height: 100px;"></div>',
- ' <div id="two" style="height: 100px;"></div>',
- ' <div id="three" style="height: 100px;"></div>',
- ' <div id="spacer" style="height: 100px;"></div>',
- '</div>'
- ].join('')
-
- const negativeHeight = -10
- const startOfSectionTwo = 101
- const contentEl = fixtureEl.querySelector('#content')
- const scrollSpy = new ScrollSpy(contentEl, {
- target: '#navigation',
- offset: contentEl.offsetTop
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- let firstTime = true
-
- contentEl.addEventListener('scroll', () => {
- const active = fixtureEl.querySelector('.active')
-
- expect(spy).toHaveBeenCalled()
- spy.calls.reset()
- if (firstTime) {
- expect(fixtureEl.querySelectorAll('.active').length).toEqual(1)
- expect(active.getAttribute('id')).toEqual('two-link')
- firstTime = false
- contentEl.scrollTop = negativeHeight
- } else {
- expect(fixtureEl.querySelectorAll('.active').length).toEqual(1)
- expect(active.getAttribute('id')).toEqual('one-link')
- done()
- }
- })
-
- contentEl.scrollTop = startOfSectionTwo
- })
-
- it('should correctly select navigation element on backward scrolling when each target section height is 100%', done => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>',
- ' <li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>',
- ' <li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>',
- ' <li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>',
- ' <li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="position: relative; overflow: auto; height: 100px">',
- ' <div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>',
- ' <div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>',
- ' <div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>',
- ' <div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const scrollSpy = new ScrollSpy(contentEl, {
- offset: 0,
- target: '.navbar'
- })
- const spy = spyOn(scrollSpy, '_process').and.callThrough()
-
- testElementIsActiveAfterScroll({
- elementSelector: '#li-100-5',
- targetSelector: '#div-100-5',
- scrollSpy,
- spy,
- contentEl,
- cb() {
- contentEl.scrollTop = 0
- testElementIsActiveAfterScroll({
- elementSelector: '#li-100-4',
- targetSelector: '#div-100-4',
- scrollSpy,
- spy,
- contentEl,
- cb() {
- contentEl.scrollTop = 0
- testElementIsActiveAfterScroll({
- elementSelector: '#li-100-3',
- targetSelector: '#div-100-3',
- scrollSpy,
- spy,
- contentEl,
- cb() {
- contentEl.scrollTop = 0
- testElementIsActiveAfterScroll({
- elementSelector: '#li-100-2',
- targetSelector: '#div-100-2',
- scrollSpy,
- spy,
- contentEl,
- cb() {
- contentEl.scrollTop = 0
- testElementIsActiveAfterScroll({
- elementSelector: '#li-100-1',
- targetSelector: '#div-100-1',
- scrollSpy,
- spy,
- contentEl,
- cb: done
- })
- }
- })
- }
- })
- }
- })
- }
- })
- })
-
- it('should allow passed in option offset method: offset', () => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a id="li-jsm-1" class="nav-link" href="#div-jsm-1">div 1</a></li>',
- ' <li class="nav-item"><a id="li-jsm-2" class="nav-link" href="#div-jsm-2">div 2</a></li>',
- ' <li class="nav-item"><a id="li-jsm-3" class="nav-link" href="#div-jsm-3">div 3</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="position: relative; overflow: auto; height: 100px">',
- ' <div id="div-jsm-1" style="position: relative; height: 200px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-jsm-2" style="position: relative; height: 150px; padding: 0; margin: 0">div 2</div>',
- ' <div id="div-jsm-3" style="position: relative; height: 250px; padding: 0; margin: 0">div 3</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const targetEl = fixtureEl.querySelector('#div-jsm-2')
- const scrollSpy = new ScrollSpy(contentEl, {
- target: '.navbar',
- offset: 0,
- method: 'offset'
- })
-
- expect(scrollSpy._offsets[1]).toEqual(Manipulator.offset(targetEl).top)
- expect(scrollSpy._offsets[1]).not.toEqual(Manipulator.position(targetEl).top)
- })
-
- it('should allow passed in option offset method: position', () => {
- fixtureEl.innerHTML = [
- '<nav class="navbar">',
- ' <ul class="nav">',
- ' <li class="nav-item"><a id="li-jsm-1" class="nav-link" href="#div-jsm-1">div 1</a></li>',
- ' <li class="nav-item"><a id="li-jsm-2" class="nav-link" href="#div-jsm-2">div 2</a></li>',
- ' <li class="nav-item"><a id="li-jsm-3" class="nav-link" href="#div-jsm-3">div 3</a></li>',
- ' </ul>',
- '</nav>',
- '<div class="content" style="position: relative; overflow: auto; height: 100px">',
- ' <div id="div-jsm-1" style="position: relative; height: 200px; padding: 0; margin: 0">div 1</div>',
- ' <div id="div-jsm-2" style="position: relative; height: 150px; padding: 0; margin: 0">div 2</div>',
- ' <div id="div-jsm-3" style="position: relative; height: 250px; padding: 0; margin: 0">div 3</div>',
- '</div>'
- ].join('')
-
- const contentEl = fixtureEl.querySelector('.content')
- const targetEl = fixtureEl.querySelector('#div-jsm-2')
- const scrollSpy = new ScrollSpy(contentEl, {
- target: '.navbar',
- offset: 0,
- method: 'position'
- })
-
- expect(scrollSpy._offsets[1]).not.toEqual(Manipulator.offset(targetEl).top)
- expect(scrollSpy._offsets[1]).toEqual(Manipulator.position(targetEl).top)
- })
- })
-
- describe('dispose', () => {
- it('should dispose a scrollspy', () => {
- spyOn(EventHandler, 'off')
- fixtureEl.innerHTML = '<div style="display: none;"></div>'
-
- const divEl = fixtureEl.querySelector('div')
- const scrollSpy = new ScrollSpy(divEl)
-
- scrollSpy.dispose()
- expect(EventHandler.off).toHaveBeenCalledWith(divEl, '.bs.scrollspy')
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a scrollspy', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.scrollspy.call(jQueryMock)
-
- expect(ScrollSpy.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a scrollspy', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const scrollSpy = new ScrollSpy(div)
-
- jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.scrollspy.call(jQueryMock)
-
- expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy)
- })
-
- it('should call a scrollspy method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const scrollSpy = new ScrollSpy(div)
-
- spyOn(scrollSpy, 'refresh')
-
- jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.scrollspy.call(jQueryMock, 'refresh')
-
- expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy)
- expect(scrollSpy.refresh).toHaveBeenCalled()
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.scrollspy.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('getInstance', () => {
- it('should return null if there is no instance', () => {
- expect(ScrollSpy.getInstance(fixtureEl)).toEqual(null)
- })
- })
-
- describe('event handler', () => {
- it('should create scrollspy on window load event', () => {
- fixtureEl.innerHTML = '<div data-spy="scroll"></div>'
-
- const scrollSpyEl = fixtureEl.querySelector('div')
-
- window.dispatchEvent(createEvent('load'))
-
- expect(ScrollSpy.getInstance(scrollSpyEl)).not.toBeNull()
- })
- })
-})
diff --git a/js/src/tab/tab.js b/js/src/tab.js
index b356cc0e2..d9bd1fc05 100644
--- a/js/src/tab/tab.js
+++ b/js/src/tab.js
@@ -13,10 +13,10 @@ import {
getTransitionDurationFromElement,
makeArray,
reflow
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import SelectorEngine from '../dom/selector-engine'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/tab/tab.spec.js b/js/src/tab/tab.spec.js
deleted file mode 100644
index 0a678e38e..000000000
--- a/js/src/tab/tab.spec.js
+++ /dev/null
@@ -1,593 +0,0 @@
-import Tab from './tab'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Tab', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Tab.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('show', () => {
- it('should activate element by tab id', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav">',
- ' <li><a href="#home" role="tab">Home</a></li>',
- ' <li><a id="triggerProfile" role="tab" href="#profile">Profile</a></li>',
- '</ul>',
- '<ul><li id="home"/><li id="profile"/></ul>'
- ].join('')
-
- const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
- const tab = new Tab(profileTriggerEl)
-
- profileTriggerEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
- expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true')
- done()
- })
-
- tab.show()
- })
-
- it('should activate element by tab id in ordered list', done => {
- fixtureEl.innerHTML = [
- '<ol class="nav nav-pills">',
- ' <li><a href="#home">Home</a></li>',
- ' <li><a id="triggerProfile" href="#profile">Profile</a></li>',
- '</ol>',
- '<ol><li id="home"/><li id="profile"/></ol>'
- ].join('')
-
- const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
- const tab = new Tab(profileTriggerEl)
-
- profileTriggerEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
- done()
- })
-
- tab.show()
- })
-
- it('should activate element by tab id in nav list', done => {
- fixtureEl.innerHTML = [
- '<nav class="nav">',
- ' <a href="#home">Home</a>',
- ' <a id="triggerProfile" href="#profile">Profile</a>',
- '</nav>',
- '<nav><div id="home"></div><div id="profile"></div></nav>'
- ].join('')
-
- const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
- const tab = new Tab(profileTriggerEl)
-
- profileTriggerEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
- done()
- })
-
- tab.show()
- })
-
- it('should activate element by tab id in list group', done => {
- fixtureEl.innerHTML = [
- '<div class="list-group">',
- ' <a href="#home">Home</a>',
- ' <a id="triggerProfile" href="#profile">Profile</a>',
- '</div>',
- '<nav><div id="home"></div><div id="profile"></div></nav>'
- ].join('')
-
- const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
- const tab = new Tab(profileTriggerEl)
-
- profileTriggerEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
- done()
- })
-
- tab.show()
- })
-
- it('should not fire shown when show is prevented', done => {
- fixtureEl.innerHTML = '<div class="nav"></div>'
-
- const navEl = fixtureEl.querySelector('div')
- const tab = new Tab(navEl)
- const expectDone = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 30)
- }
-
- navEl.addEventListener('show.bs.tab', ev => {
- ev.preventDefault()
- expectDone()
- })
-
- navEl.addEventListener('shown.bs.tab', () => {
- throw new Error('should not trigger shown event')
- })
-
- tab.show()
- })
-
- it('should not fire shown when tab is already active', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item"><a href="#home" class="nav-link active" role="tab">Home</a></li>',
- ' <li class="nav-item"><a href="#profile" class="nav-link" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const triggerActive = fixtureEl.querySelector('a.active')
- const tab = new Tab(triggerActive)
-
- triggerActive.addEventListener('shown.bs.tab', () => {
- throw new Error('should not trigger shown event')
- })
-
- tab.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 30)
- })
-
- it('should not fire shown when tab is disabled', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item"><a href="#home" class="nav-link active" role="tab">Home</a></li>',
- ' <li class="nav-item"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const triggerDisabled = fixtureEl.querySelector('a.disabled')
- const tab = new Tab(triggerDisabled)
-
- triggerDisabled.addEventListener('shown.bs.tab', () => {
- throw new Error('should not trigger shown event')
- })
-
- tab.show()
- setTimeout(() => {
- expect().nothing()
- done()
- }, 30)
- })
-
- it('show and shown events should reference correct relatedTarget', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item"><a href="#home" class="nav-link active" role="tab">Home</a></li>',
- ' <li class="nav-item"><a id="triggerProfile" href="#profile" class="nav-link" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const secondTabTrigger = fixtureEl.querySelector('#triggerProfile')
- const secondTab = new Tab(secondTabTrigger)
-
- secondTabTrigger.addEventListener('show.bs.tab', ev => {
- expect(ev.relatedTarget.hash).toEqual('#home')
- })
-
- secondTabTrigger.addEventListener('shown.bs.tab', ev => {
- expect(ev.relatedTarget.hash).toEqual('#home')
- expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true')
- expect(fixtureEl.querySelector('a:not(.active)').getAttribute('aria-selected')).toEqual('false')
- done()
- })
-
- secondTab.show()
- })
-
- it('should fire hide and hidden events', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav">',
- ' <li><a href="#home">Home</a></li>',
- ' <li><a href="#profile">Profile</a></li>',
- '</ul>'
- ].join('')
-
- const triggerList = fixtureEl.querySelectorAll('a')
- const firstTab = new Tab(triggerList[0])
- const secondTab = new Tab(triggerList[1])
-
- let hideCalled = false
- triggerList[0].addEventListener('shown.bs.tab', () => {
- secondTab.show()
- })
-
- triggerList[0].addEventListener('hide.bs.tab', ev => {
- hideCalled = true
- expect(ev.relatedTarget.hash).toEqual('#profile')
- })
-
- triggerList[0].addEventListener('hidden.bs.tab', ev => {
- expect(hideCalled).toEqual(true)
- expect(ev.relatedTarget.hash).toEqual('#profile')
- done()
- })
-
- firstTab.show()
- })
-
- it('should not fire hidden when hide is prevented', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav">',
- ' <li><a href="#home">Home</a></li>',
- ' <li><a href="#profile">Profile</a></li>',
- '</ul>'
- ].join('')
-
- const triggerList = fixtureEl.querySelectorAll('a')
- const firstTab = new Tab(triggerList[0])
- const secondTab = new Tab(triggerList[1])
- const expectDone = () => {
- setTimeout(() => {
- expect().nothing()
- done()
- }, 30)
- }
-
- triggerList[0].addEventListener('shown.bs.tab', () => {
- secondTab.show()
- })
-
- triggerList[0].addEventListener('hide.bs.tab', ev => {
- ev.preventDefault()
- expectDone()
- })
-
- triggerList[0].addEventListener('hidden.bs.tab', () => {
- throw new Error('should not trigger hidden')
- })
-
- firstTab.show()
- })
-
- it('should handle removed tabs', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item">',
- ' <a class="nav-link nav-tab" href="#profile" role="tab" data-toggle="tab">',
- ' <button class="close"><span aria-hidden="true">&times;</span></button>',
- ' </a>',
- ' </li>',
- ' <li class="nav-item">',
- ' <a id="secondNav" class="nav-link nav-tab" href="#buzz" role="tab" data-toggle="tab">',
- ' <button class="close"><span aria-hidden="true">&times;</span></button>',
- ' </a>',
- ' </li>',
- ' <li class="nav-item">',
- ' <a class="nav-link nav-tab" href="#references" role="tab" data-toggle="tab">',
- ' <button id="btnClose" class="close"><span aria-hidden="true">&times;</span></button>',
- ' </a>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane fade show active" id="profile">test 1</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="buzz">test 2</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="references">test 3</div>',
- '</div>'
- ].join('')
-
- const secondNavEl = fixtureEl.querySelector('#secondNav')
- const btnCloseEl = fixtureEl.querySelector('#btnClose')
- const secondNavTab = new Tab(secondNavEl)
-
- secondNavEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelectorAll('.nav-tab').length).toEqual(2)
- done()
- })
-
- btnCloseEl.addEventListener('click', () => {
- const linkEl = btnCloseEl.parentNode
- const liEl = linkEl.parentNode
- const tabId = linkEl.getAttribute('href')
- const tabIdEl = fixtureEl.querySelector(tabId)
-
- liEl.parentNode.removeChild(liEl)
- tabIdEl.parentNode.removeChild(tabIdEl)
- secondNavTab.show()
- })
-
- btnCloseEl.click()
- })
- })
-
- describe('dispose', () => {
- it('should dispose a tab', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = fixtureEl.querySelector('div')
- const tab = new Tab(fixtureEl.querySelector('div'))
-
- expect(Tab.getInstance(el)).not.toBeNull()
-
- tab.dispose()
-
- expect(Tab.getInstance(el)).toBeNull()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a tab', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.tab = Tab.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tab.call(jQueryMock)
-
- expect(Tab.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a tab', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const tab = new Tab(div)
-
- jQueryMock.fn.tab = Tab.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tab.call(jQueryMock)
-
- expect(Tab.getInstance(div)).toEqual(tab)
- })
-
- it('should call a tab method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const tab = new Tab(div)
-
- spyOn(tab, 'show')
-
- jQueryMock.fn.tab = Tab.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tab.call(jQueryMock, 'show')
-
- expect(Tab.getInstance(div)).toEqual(tab)
- expect(tab.show).toHaveBeenCalled()
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.tab = Tab.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.tab.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('getInstance', () => {
- it('should return null if there is no instance', () => {
- expect(Tab.getInstance(fixtureEl)).toEqual(null)
- })
-
- it('should return this instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const divEl = fixtureEl.querySelector('div')
- const tab = new Tab(divEl)
-
- expect(Tab.getInstance(divEl)).toEqual(tab)
- })
- })
-
- describe('data-api', () => {
- it('should create dynamically a tab', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item"><a href="#home" class="nav-link active" role="tab">Home</a></li>',
- ' <li class="nav-item"><a id="triggerProfile" data-toggle="tab" href="#profile" class="nav-link" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane active" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const secondTabTrigger = fixtureEl.querySelector('#triggerProfile')
-
- secondTabTrigger.addEventListener('shown.bs.tab', () => {
- expect(secondTabTrigger.classList.contains('active')).toEqual(true)
- expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
- done()
- })
-
- secondTabTrigger.click()
- })
-
- it('selected tab should deactivate previous selected link in dropdown', () => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs">',
- ' <li class="nav-item"><a class="nav-link" href="#home" data-toggle="tab">Home</a></li>',
- ' <li class="nav-item"><a class="nav-link" href="#profile" data-toggle="tab">Profile</a></li>',
- ' <li class="nav-item dropdown">',
- ' <a class="nav-link dropdown-toggle active" data-toggle="dropdown" href="#">Dropdown</>',
- ' <div class="dropdown-menu">',
- ' <a class="dropdown-item active" href="#dropdown1" id="dropdown1-tab" data-toggle="tab">@fat</a>',
- ' <a class="dropdown-item" href="#dropdown2" id="dropdown2-tab" data-toggle="tab">@mdo</a>',
- ' </div>',
- ' </li>',
- '</ul>'
- ].join('')
-
- const firstLiLinkEl = fixtureEl.querySelector('li:first-child a')
-
- firstLiLinkEl.click()
- expect(firstLiLinkEl.classList.contains('active')).toEqual(true)
- expect(fixtureEl.querySelector('li:last-child a').classList.contains('active')).toEqual(false)
- expect(fixtureEl.querySelector('li:last-child .dropdown-menu a:first-child').classList.contains('active')).toEqual(false)
- })
-
- it('should handle nested tabs', done => {
- fixtureEl.innerHTML = [
- '<nav class="nav nav-tabs" role="tablist">',
- ' <a id="tab1" href="#x-tab1" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</a>',
- ' <a href="#x-tab2" class="nav-item nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</a>',
- ' <a href="#x-tab3" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</a>',
- '</nav>',
- '<div class="tab-content">',
- ' <div class="tab-pane" id="x-tab1" role="tabpanel">',
- ' <nav class="nav nav-tabs" role="tablist">',
- ' <a href="#nested-tab1" class="nav-item nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</a>',
- ' <a id="tabNested2" href="#nested-tab2" class="nav-item nav-link" data-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</a>',
- ' </nav>',
- ' <div class="tab-content">',
- ' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>',
- ' <div class="tab-pane" id="nested-tab2" role="tabpanel">Nested Tab2 Content</div>',
- ' </div>',
- ' </div>',
- ' <div class="tab-pane active" id="x-tab2" role="tabpanel">Tab2 Content</div>',
- ' <div class="tab-pane" id="x-tab3" role="tabpanel">Tab3 Content</div>',
- '</div>'
- ].join('')
-
- const tab1El = fixtureEl.querySelector('#tab1')
- const tabNested2El = fixtureEl.querySelector('#tabNested2')
- const xTab1El = fixtureEl.querySelector('#x-tab1')
-
- tabNested2El.addEventListener('shown.bs.tab', () => {
- expect(xTab1El.classList.contains('active')).toEqual(true)
- done()
- })
-
- tab1El.addEventListener('shown.bs.tab', () => {
- expect(xTab1El.classList.contains('active')).toEqual(true)
- tabNested2El.click()
- })
-
- tab1El.click()
- })
-
- it('should not remove fade class if no active pane is present', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item"><a id="tab-home" href="#home" class="nav-link" data-toggle="tab" role="tab">Home</a></li>',
- ' <li class="nav-item"><a id="tab-profile" href="#profile" class="nav-link" data-toggle="tab" role="tab">Profile</a></li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div class="tab-pane fade" id="home" role="tabpanel"></div>',
- ' <div class="tab-pane fade" id="profile" role="tabpanel"></div>',
- '</div>'
- ].join('')
-
- const triggerTabProfileEl = fixtureEl.querySelector('#tab-profile')
- const triggerTabHomeEl = fixtureEl.querySelector('#tab-home')
- const tabProfileEl = fixtureEl.querySelector('#profile')
- const tabHomeEl = fixtureEl.querySelector('#home')
-
- triggerTabProfileEl.addEventListener('shown.bs.tab', () => {
- expect(tabProfileEl.classList.contains('fade')).toEqual(true)
- expect(tabProfileEl.classList.contains('show')).toEqual(true)
-
- triggerTabHomeEl.addEventListener('shown.bs.tab', () => {
- expect(tabProfileEl.classList.contains('fade')).toEqual(true)
- expect(tabProfileEl.classList.contains('show')).toEqual(false)
-
- expect(tabHomeEl.classList.contains('fade')).toEqual(true)
- expect(tabHomeEl.classList.contains('show')).toEqual(true)
-
- done()
- })
-
- triggerTabHomeEl.click()
- })
-
- triggerTabProfileEl.click()
- })
-
- it('should not add show class to tab panes if there is no `.fade` class', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item">',
- ' <a class="nav-link nav-tab" href="#home" role="tab" data-toggle="tab">Home</a>',
- ' </li>',
- ' <li class="nav-item">',
- ' <a id="secondNav" class="nav-link nav-tab" href="#profile" role="tab" data-toggle="tab">Profile</a>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane" id="home">test 1</div>',
- ' <div role="tabpanel" class="tab-pane" id="profile">test 2</div>',
- '</div>'
- ].join('')
-
- const secondNavEl = fixtureEl.querySelector('#secondNav')
-
- secondNavEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelectorAll('.show').length).toEqual(0)
- done()
- })
-
- secondNavEl.click()
- })
-
- it('should add show class to tab panes if there is a `.fade` class', done => {
- fixtureEl.innerHTML = [
- '<ul class="nav nav-tabs" role="tablist">',
- ' <li class="nav-item">',
- ' <a class="nav-link nav-tab" href="#home" role="tab" data-toggle="tab">Home</a>',
- ' </li>',
- ' <li class="nav-item">',
- ' <a id="secondNav" class="nav-link nav-tab" href="#profile" role="tab" data-toggle="tab">Profile</a>',
- ' </li>',
- '</ul>',
- '<div class="tab-content">',
- ' <div role="tabpanel" class="tab-pane fade" id="home">test 1</div>',
- ' <div role="tabpanel" class="tab-pane fade" id="profile">test 2</div>',
- '</div>'
- ].join('')
-
- const secondNavEl = fixtureEl.querySelector('#secondNav')
-
- secondNavEl.addEventListener('shown.bs.tab', () => {
- expect(fixtureEl.querySelectorAll('.show').length).toEqual(1)
- done()
- })
-
- secondNavEl.click()
- })
- })
-})
diff --git a/js/src/toast/toast.js b/js/src/toast.js
index 4de7db1cd..e0d2a8b3f 100644
--- a/js/src/toast/toast.js
+++ b/js/src/toast.js
@@ -12,10 +12,10 @@ import {
getTransitionDurationFromElement,
reflow,
typeCheckConfig
-} from '../util/index'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
+} from './util/index'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/toast/toast.spec.js b/js/src/toast/toast.spec.js
deleted file mode 100644
index b00b86085..000000000
--- a/js/src/toast/toast.spec.js
+++ /dev/null
@@ -1,374 +0,0 @@
-import Toast from './toast'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock } from '../../tests/helpers/fixture'
-
-describe('Toast', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Toast.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('constructor', () => {
- it('should allow to config in js', done => {
- fixtureEl.innerHTML = [
- '<div class="toast">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl, {
- delay: 1
- })
-
- toastEl.addEventListener('shown.bs.toast', () => {
- expect(toastEl.classList.contains('show')).toEqual(true)
- done()
- })
-
- toast.show()
- })
-
- it('should close toast when close element with data-dismiss attribute is set', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1" data-autohide="false" data-animation="false">',
- ' <button type="button" class="ml-2 mb-1 close" data-dismiss="toast">',
- ' close',
- ' </button>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl)
-
- toastEl.addEventListener('shown.bs.toast', () => {
- expect(toastEl.classList.contains('show')).toEqual(true)
-
- const button = toastEl.querySelector('.close')
-
- button.click()
- })
-
- toastEl.addEventListener('hidden.bs.toast', () => {
- expect(toastEl.classList.contains('show')).toEqual(false)
- done()
- })
-
- toast.show()
- })
- })
-
- describe('Default', () => {
- it('should expose default setting to allow to override them', () => {
- const defaultDelay = 1000
-
- Toast.Default.delay = defaultDelay
-
- fixtureEl.innerHTML = [
- '<div class="toast" data-autohide="false" data-animation="false">',
- ' <button type="button" class="ml-2 mb-1 close" data-dismiss="toast">',
- ' close',
- ' </button>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl)
-
- expect(toast._config.delay).toEqual(defaultDelay)
- })
- })
-
- describe('DefaultType', () => {
- it('should expose default setting types for read', () => {
- expect(Toast.DefaultType).toEqual(jasmine.any(Object))
- })
- })
-
- describe('show', () => {
- it('should auto hide', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
-
- toastEl.addEventListener('hidden.bs.toast', () => {
- expect(toastEl.classList.contains('show')).toEqual(false)
- done()
- })
-
- toast.show()
- })
-
- it('should not add fade class', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1" data-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
-
- toastEl.addEventListener('shown.bs.toast', () => {
- expect(toastEl.classList.contains('fade')).toEqual(false)
- done()
- })
-
- toast.show()
- })
-
- it('should not trigger shown if show is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1" data-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
-
- const assertDone = () => {
- setTimeout(() => {
- expect(toastEl.classList.contains('show')).toEqual(false)
- done()
- }, 20)
- }
-
- toastEl.addEventListener('show.bs.toast', event => {
- event.preventDefault()
- assertDone()
- })
-
- toastEl.addEventListener('shown.bs.toast', () => {
- throw new Error('shown event should not be triggered if show is prevented')
- })
-
- toast.show()
- })
- })
-
- describe('hide', () => {
- it('should allow to hide toast manually', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1" data-autohide="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- ' </div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
-
- toastEl.addEventListener('shown.bs.toast', () => {
- toast.hide()
- })
-
- toastEl.addEventListener('hidden.bs.toast', () => {
- expect(toastEl.classList.contains('show')).toEqual(false)
- done()
- })
-
- toast.show()
- })
-
- it('should do nothing when we call hide on a non shown toast', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl)
-
- spyOn(toastEl.classList, 'contains')
-
- toast.hide()
-
- expect(toastEl.classList.contains).toHaveBeenCalled()
- })
-
- it('should not trigger hidden if hide is prevented', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="1" data-animation="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('.toast')
- const toast = new Toast(toastEl)
-
- const assertDone = () => {
- setTimeout(() => {
- expect(toastEl.classList.contains('show')).toEqual(true)
- done()
- }, 20)
- }
-
- toastEl.addEventListener('shown.bs.toast', () => {
- toast.hide()
- })
-
- toastEl.addEventListener('hide.bs.toast', event => {
- event.preventDefault()
- assertDone()
- })
-
- toastEl.addEventListener('hidden.bs.toast', () => {
- throw new Error('hidden event should not be triggered if hide is prevented')
- })
-
- toast.show()
- })
- })
-
- describe('dispose', () => {
- it('should allow to destroy toast', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl)
-
- expect(Toast.getInstance(toastEl)).toBeDefined()
-
- toast.dispose()
-
- expect(Toast.getInstance(toastEl)).toBeNull()
- })
-
- it('should allow to destroy toast and hide it before that', done => {
- fixtureEl.innerHTML = [
- '<div class="toast" data-delay="0" data-autohide="false">',
- ' <div class="toast-body">',
- ' a simple toast',
- ' </div>',
- '</div>'
- ].join('')
-
- const toastEl = fixtureEl.querySelector('div')
- const toast = new Toast(toastEl)
- const expected = () => {
- expect(toastEl.classList.contains('show')).toEqual(true)
- expect(Toast.getInstance(toastEl)).toBeDefined()
-
- toast.dispose()
-
- expect(Toast.getInstance(toastEl)).toBeNull()
- expect(toastEl.classList.contains('show')).toEqual(false)
-
- done()
- }
-
- toastEl.addEventListener('shown.bs.toast', () => {
- setTimeout(expected, 1)
- })
-
- toast.show()
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a toast', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.toast = Toast.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.toast.call(jQueryMock)
-
- expect(Toast.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a toast', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const toast = new Toast(div)
-
- jQueryMock.fn.toast = Toast.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.toast.call(jQueryMock)
-
- expect(Toast.getInstance(div)).toEqual(toast)
- })
-
- it('should call a toast method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const toast = new Toast(div)
-
- spyOn(toast, 'show')
-
- jQueryMock.fn.toast = Toast.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.toast.call(jQueryMock, 'show')
-
- expect(Toast.getInstance(div)).toEqual(toast)
- expect(toast.show).toHaveBeenCalled()
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.toast = Toast.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.toast.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-
- describe('getInstance', () => {
- it('should return collapse instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const toast = new Toast(div)
-
- expect(Toast.getInstance(div)).toEqual(toast)
- })
-
- it('should return null when there is no collapse instance', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Toast.getInstance(div)).toEqual(null)
- })
- })
-})
diff --git a/js/src/tooltip/tooltip.js b/js/src/tooltip.js
index 99ac29af6..b4f047b70 100644
--- a/js/src/tooltip/tooltip.js
+++ b/js/src/tooltip.js
@@ -16,16 +16,16 @@ import {
makeArray,
noop,
typeCheckConfig
-} from '../util/index'
+} from './util/index'
import {
DefaultWhitelist,
sanitizeHtml
-} from '../util/sanitizer'
-import Data from '../dom/data'
-import EventHandler from '../dom/event-handler'
-import Manipulator from '../dom/manipulator'
+} from './util/sanitizer'
+import Data from './dom/data'
+import EventHandler from './dom/event-handler'
+import Manipulator from './dom/manipulator'
import Popper from 'popper.js'
-import SelectorEngine from '../dom/selector-engine'
+import SelectorEngine from './dom/selector-engine'
/**
* ------------------------------------------------------------------------
diff --git a/js/src/tooltip/tooltip.spec.js b/js/src/tooltip/tooltip.spec.js
deleted file mode 100644
index a6cbd7847..000000000
--- a/js/src/tooltip/tooltip.spec.js
+++ /dev/null
@@ -1,1020 +0,0 @@
-import Tooltip from './tooltip'
-import EventHandler from '../dom/event-handler'
-import { makeArray, noop } from '../util/index'
-
-/** Test helpers */
-import { getFixture, clearFixture, jQueryMock, createEvent } from '../../tests/helpers/fixture'
-
-describe('Tooltip', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
-
- const tooltipList = makeArray(document.querySelectorAll('.tooltip'))
-
- tooltipList.forEach(tooltipEl => {
- document.body.removeChild(tooltipEl)
- })
- })
-
- describe('VERSION', () => {
- it('should return plugin version', () => {
- expect(Tooltip.VERSION).toEqual(jasmine.any(String))
- })
- })
-
- describe('Default', () => {
- it('should return plugin default config', () => {
- expect(Tooltip.Default).toEqual(jasmine.any(Object))
- })
- })
-
- describe('NAME', () => {
- it('should return plugin name', () => {
- expect(Tooltip.NAME).toEqual(jasmine.any(String))
- })
- })
-
- describe('DATA_KEY', () => {
- it('should return plugin data key', () => {
- expect(Tooltip.DATA_KEY).toEqual('bs.tooltip')
- })
- })
-
- describe('Event', () => {
- it('should return plugin events', () => {
- expect(Tooltip.Event).toEqual(jasmine.any(Object))
- })
- })
-
- describe('EVENT_KEY', () => {
- it('should return plugin event key', () => {
- expect(Tooltip.EVENT_KEY).toEqual('.bs.tooltip')
- })
- })
-
- describe('DefaultType', () => {
- it('should return plugin default type', () => {
- expect(Tooltip.DefaultType).toEqual(jasmine.any(Object))
- })
- })
-
- describe('constructor', () => {
- it('should not take care of disallowed data attributes', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" data-sanitize="false" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(tooltip.config.sanitize).toEqual(true)
- })
-
- it('should convert title and content to string if numbers', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- title: 1,
- content: 7
- })
-
- expect(tooltip.config.title).toEqual('1')
- expect(tooltip.config.content).toEqual('7')
- })
-
- it('should enable selector delegation', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const containerEl = fixtureEl.querySelector('div')
- const tooltipContainer = new Tooltip(containerEl, {
- selector: 'a[rel="tooltip"]',
- trigger: 'click'
- })
-
- containerEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipInContainerEl = containerEl.querySelector('a')
-
- tooltipInContainerEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).not.toBeNull()
- tooltipContainer.dispose()
- done()
- })
-
- tooltipInContainerEl.click()
- })
-
- it('should allow to pass config to popper.js with `popperConfig`', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- popperConfig: {
- placement: 'left'
- }
- })
-
- const popperConfig = tooltip._getPopperConfig('top')
-
- expect(popperConfig.placement).toEqual('left')
- })
- })
-
- describe('enable', () => {
- it('should enable a tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.enable()
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeDefined()
- done()
- })
-
- tooltip.show()
- })
- })
-
- describe('disable', () => {
- it('should disable tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.disable()
-
- tooltipEl.addEventListener('show.bs.tooltip', () => {
- throw new Error('should not show a disabled tooltip')
- })
-
- tooltip.show()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
- })
-
- describe('toggleEnabled', () => {
- it('should toggle enabled', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(tooltip._isEnabled).toEqual(true)
-
- tooltip.toggleEnabled()
-
- expect(tooltip._isEnabled).toEqual(false)
- })
- })
-
- describe('toggle', () => {
- it('should do nothing if disabled', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.disable()
-
- tooltipEl.addEventListener('show.bs.tooltip', () => {
- throw new Error('should not show a disabled tooltip')
- })
-
- tooltip.toggle()
-
- setTimeout(() => {
- expect().nothing()
- done()
- }, 10)
- })
-
- it('should show a tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeDefined()
- done()
- })
-
- tooltip.toggle()
- })
-
- it('should call toggle and show the tooltip when trigger is "click"', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- trigger: 'click'
- })
-
- spyOn(tooltip, 'toggle').and.callThrough()
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(tooltip.toggle).toHaveBeenCalled()
- done()
- })
-
- tooltipEl.click()
- })
-
- it('should hide a tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- tooltip.toggle()
- })
-
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeNull()
- done()
- })
-
- tooltip.toggle()
- })
-
- it('should call toggle and hide the tooltip when trigger is "click"', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- trigger: 'click'
- })
-
- spyOn(tooltip, 'toggle').and.callThrough()
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- tooltipEl.click()
- })
-
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- expect(tooltip.toggle).toHaveBeenCalled()
- done()
- })
-
- tooltipEl.click()
- })
- })
-
- describe('dispose', () => {
- it('should destroy a tooltip', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(Tooltip.getInstance(tooltipEl)).toEqual(tooltip)
-
- tooltip.dispose()
-
- expect(Tooltip.getInstance(tooltipEl)).toEqual(null)
- })
-
- it('should destroy a tooltip and remove it from the dom', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeDefined()
-
- tooltip.dispose()
-
- expect(document.querySelector('.tooltip')).toBeNull()
- done()
- })
-
- tooltip.show()
- })
- })
-
- describe('show', () => {
- it('should show a tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- const tooltipShown = document.querySelector('.tooltip')
-
- expect(tooltipShown).toBeDefined()
- expect(tooltipEl.getAttribute('aria-describedby')).toEqual(tooltipShown.getAttribute('id'))
- expect(tooltipShown.getAttribute('id').indexOf('tooltip') !== -1).toEqual(true)
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip on mobile', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
- document.documentElement.ontouchstart = noop
-
- spyOn(EventHandler, 'on')
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).not.toBeNull()
- expect(EventHandler.on).toHaveBeenCalled()
- document.documentElement.ontouchstart = undefined
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip relative to placement option', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- placement: 'bottom'
- })
-
- tooltipEl.addEventListener('inserted.bs.tooltip', () => {
- expect(tooltip.getTipElement().classList.contains('bs-tooltip-bottom')).toEqual(true)
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- const tooltipShown = document.querySelector('.tooltip')
-
- expect(tooltipShown.classList.contains('bs-tooltip-bottom')).toEqual(true)
- done()
- })
-
- tooltip.show()
- })
-
- it('should not error when trying to show a tooltip that has been removed from the dom', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- const firstCallback = () => {
- tooltipEl.removeEventListener('shown.bs.tooltip', firstCallback)
- let tooltipShown = document.querySelector('.tooltip')
-
- tooltipShown.parentNode.removeChild(tooltipShown)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- tooltipShown = document.querySelector('.tooltip')
-
- expect(tooltipShown).not.toBeNull()
- done()
- })
-
- tooltip.show()
- }
-
- tooltipEl.addEventListener('shown.bs.tooltip', firstCallback)
-
- tooltip.show()
- })
-
- it('should show a tooltip with a dom element container', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- container: fixtureEl
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(fixtureEl.querySelector('.tooltip')).toBeDefined()
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip with a jquery element container', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- container: {
- 0: fixtureEl,
- jquery: 'jQuery'
- }
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(fixtureEl.querySelector('.tooltip')).toBeDefined()
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip with a selector in container', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- container: '#fixture'
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(fixtureEl.querySelector('.tooltip')).toBeDefined()
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip with placement as a function', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const spy = jasmine.createSpy('placement').and.returnValue('top')
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- placement: spy
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeDefined()
- expect(spy).toHaveBeenCalled()
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip with offset as a function', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const spy = jasmine.createSpy('offset').and.returnValue({})
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- offset: spy
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeDefined()
- expect(spy).toHaveBeenCalled()
- done()
- })
-
- tooltip.show()
- })
-
- it('should show a tooltip without the animation', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- animation: false
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- const tip = document.querySelector('.tooltip')
-
- expect(tip).toBeDefined()
- expect(tip.classList.contains('fade')).toEqual(false)
- done()
- })
-
- tooltip.show()
- })
-
- it('should throw an error the element is not visible', () => {
- fixtureEl.innerHTML = '<a href="#" style="display: none" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- try {
- tooltip.show()
- } catch (error) {
- expect(error.message).toEqual('Please use show on visible elements')
- }
- })
-
- it('should not show a tooltip if show.bs.tooltip is prevented', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- const expectedDone = () => {
- setTimeout(() => {
- expect(document.querySelector('.tooltip')).toBeNull()
- done()
- }, 10)
- }
-
- tooltipEl.addEventListener('show.bs.tooltip', ev => {
- ev.preventDefault()
- expectedDone()
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- throw new Error('Tooltip should not be shown')
- })
-
- tooltip.show()
- })
-
- it('should show tooltip if leave event hasn\'t occurred before delay expires', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- delay: 150
- })
-
- spyOn(tooltip, 'show')
-
- setTimeout(() => {
- expect(tooltip.show).not.toHaveBeenCalled()
- }, 100)
-
- setTimeout(() => {
- expect(tooltip.show).toHaveBeenCalled()
- done()
- }, 200)
-
- tooltipEl.dispatchEvent(createEvent('mouseover'))
- })
-
- it('should not show tooltip if leave event occurs before delay expires', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- delay: 150
- })
-
- spyOn(tooltip, 'show')
-
- setTimeout(() => {
- expect(tooltip.show).not.toHaveBeenCalled()
- tooltipEl.dispatchEvent(createEvent('mouseover'))
- }, 100)
-
- setTimeout(() => {
- expect(tooltip.show).toHaveBeenCalled()
- expect(document.querySelectorAll('.tooltip').length).toEqual(0)
- done()
- }, 200)
-
- tooltipEl.dispatchEvent(createEvent('mouseover'))
- })
-
- it('should not hide tooltip if leave event occurs and enter event occurs within the hide delay', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- delay: {
- show: 0,
- hide: 150
- }
- })
-
- setTimeout(() => {
- expect(tooltip.getTipElement().classList.contains('show')).toEqual(true)
- tooltipEl.dispatchEvent(createEvent('mouseout'))
-
- setTimeout(() => {
- expect(tooltip.getTipElement().classList.contains('show')).toEqual(true)
- tooltipEl.dispatchEvent(createEvent('mouseover'))
- }, 100)
-
- setTimeout(() => {
- expect(tooltip.getTipElement().classList.contains('show')).toEqual(true)
- done()
- }, 200)
- }, 0)
-
- tooltipEl.dispatchEvent(createEvent('mouseover'))
- })
- })
-
- describe('hide', () => {
- it('should hide a tooltip', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide())
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeNull()
- expect(tooltipEl.getAttribute('aria-describedby')).toBeNull()
- done()
- })
-
- tooltip.show()
- })
-
- it('should hide a tooltip on mobile', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- document.documentElement.ontouchstart = noop
- spyOn(EventHandler, 'off')
- tooltip.hide()
- })
-
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeNull()
- expect(EventHandler.off).toHaveBeenCalled()
- document.documentElement.ontouchstart = undefined
- done()
- })
-
- tooltip.show()
- })
-
- it('should hide a tooltip without animation', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- animation: false
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide())
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- expect(document.querySelector('.tooltip')).toBeNull()
- expect(tooltipEl.getAttribute('aria-describedby')).toBeNull()
- done()
- })
-
- tooltip.show()
- })
-
- it('should not hide a tooltip if hide event is prevented', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const assertDone = () => {
- setTimeout(() => {
- expect(document.querySelector('.tooltip')).not.toBeNull()
- done()
- }, 20)
- }
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- animation: false
- })
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => tooltip.hide())
- tooltipEl.addEventListener('hide.bs.tooltip', event => {
- event.preventDefault()
- assertDone()
- })
- tooltipEl.addEventListener('hidden.bs.tooltip', () => {
- throw new Error('should not trigger hidden event')
- })
-
- tooltip.show()
- })
- })
-
- describe('update', () => {
- it('should call popper schedule update', done => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltipEl.addEventListener('shown.bs.tooltip', () => {
- spyOn(tooltip._popper, 'scheduleUpdate')
-
- tooltip.update()
-
- expect(tooltip._popper.scheduleUpdate).toHaveBeenCalled()
- done()
- })
-
- tooltip.show()
- })
-
- it('should do nothing if the tooltip is not shown', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.update()
- expect().nothing()
- })
- })
-
- describe('isWithContent', () => {
- it('should return true if there is content', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(tooltip.isWithContent()).toEqual(true)
- })
-
- it('should return false if there is no content', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title=""/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(tooltip.isWithContent()).toEqual(false)
- })
- })
-
- describe('getTipElement', () => {
- it('should create the tip element and return it', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- spyOn(document, 'createElement').and.callThrough()
-
- expect(tooltip.getTipElement()).toBeDefined()
- expect(document.createElement).toHaveBeenCalled()
- })
-
- it('should return the created tip element', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- const spy = spyOn(document, 'createElement').and.callThrough()
-
- expect(tooltip.getTipElement()).toBeDefined()
- expect(spy).toHaveBeenCalled()
-
- spy.calls.reset()
-
- expect(tooltip.getTipElement()).toBeDefined()
- expect(spy).not.toHaveBeenCalled()
- })
- })
-
- describe('setContent', () => {
- it('should set tip content', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.setContent()
-
- const tip = tooltip.getTipElement()
-
- expect(tip.classList.contains('show')).toEqual(false)
- expect(tip.classList.contains('fade')).toEqual(false)
- expect(tip.querySelector('.tooltip-inner').textContent).toEqual('Another tooltip')
- })
- })
-
- describe('setElementContent', () => {
- it('should do nothing if the element is null', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.setElementContent(null, null)
- expect().nothing()
- })
-
- it('should add the content as a child of the element', () => {
- fixtureEl.innerHTML = [
- '<a href="#" rel="tooltip" title="Another tooltip"/>',
- '<div id="childContent"></div>'
- ].join('')
-
- const tooltipEl = fixtureEl.querySelector('a')
- const childContent = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(tooltipEl, {
- html: true
- })
-
- tooltip.setElementContent(tooltip.getTipElement(), childContent)
-
- expect(childContent.parentNode).toEqual(tooltip.getTipElement())
- })
-
- it('should do nothing if the content is a child of the element', () => {
- fixtureEl.innerHTML = [
- '<a href="#" rel="tooltip" title="Another tooltip"/>',
- '<div id="childContent"></div>'
- ].join('')
-
- const tooltipEl = fixtureEl.querySelector('a')
- const childContent = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(tooltipEl, {
- html: true
- })
-
- tooltip.getTipElement().appendChild(childContent)
- tooltip.setElementContent(tooltip.getTipElement(), childContent)
-
- expect().nothing()
- })
-
- it('should add the content as a child of the element for jQuery elements', () => {
- fixtureEl.innerHTML = [
- '<a href="#" rel="tooltip" title="Another tooltip"/>',
- '<div id="childContent"></div>'
- ].join('')
-
- const tooltipEl = fixtureEl.querySelector('a')
- const childContent = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(tooltipEl, {
- html: true
- })
-
- tooltip.setElementContent(tooltip.getTipElement(), { 0: childContent, jquery: 'jQuery' })
-
- expect(childContent.parentNode).toEqual(tooltip.getTipElement())
- })
-
- it('should add the child text content in the element', () => {
- fixtureEl.innerHTML = [
- '<a href="#" rel="tooltip" title="Another tooltip"/>',
- '<div id="childContent">Tooltip</div>'
- ].join('')
-
- const tooltipEl = fixtureEl.querySelector('a')
- const childContent = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.setElementContent(tooltip.getTipElement(), childContent)
-
- expect(childContent.textContent).toEqual(tooltip.getTipElement().textContent)
- })
-
- it('should add html without sanitize it', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- sanitize: false,
- html: true
- })
-
- tooltip.setElementContent(tooltip.getTipElement(), '<div id="childContent">Tooltip</div>')
-
- expect(tooltip.getTipElement().querySelector('div').id).toEqual('childContent')
- })
-
- it('should add html sanitized', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- html: true
- })
-
- tooltip.setElementContent(tooltip.getTipElement(), [
- '<div id="childContent">',
- ' <button type="button">test btn</button>',
- '</div>'
- ].join(''))
-
- expect(tooltip.getTipElement().querySelector('div').id).toEqual('childContent')
- expect(tooltip.getTipElement().querySelector('button')).toEqual(null)
- })
-
- it('should add text content', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- tooltip.setElementContent(tooltip.getTipElement(), 'test')
-
- expect(tooltip.getTipElement().innerText).toEqual('test')
- })
- })
-
- describe('getTitle', () => {
- it('should return the title', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl)
-
- expect(tooltip.getTitle()).toEqual('Another tooltip')
- })
-
- it('should call title function', () => {
- fixtureEl.innerHTML = '<a href="#" rel="tooltip" />'
-
- const tooltipEl = fixtureEl.querySelector('a')
- const tooltip = new Tooltip(tooltipEl, {
- title: () => 'test'
- })
-
- expect(tooltip.getTitle()).toEqual('test')
- })
- })
-
- describe('jQueryInterface', () => {
- it('should create a tooltip', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- jQueryMock.fn.tooltip = Tooltip.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tooltip.call(jQueryMock)
-
- expect(Tooltip.getInstance(div)).toBeDefined()
- })
-
- it('should not re create a tooltip', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(div)
-
- jQueryMock.fn.tooltip = Tooltip.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tooltip.call(jQueryMock)
-
- expect(Tooltip.getInstance(div)).toEqual(tooltip)
- })
-
- it('should call a tooltip method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const tooltip = new Tooltip(div)
-
- spyOn(tooltip, 'show')
-
- jQueryMock.fn.tooltip = Tooltip.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tooltip.call(jQueryMock, 'show')
-
- expect(Tooltip.getInstance(div)).toEqual(tooltip)
- expect(tooltip.show).toHaveBeenCalled()
- })
-
- it('should do nothing when we call dispose or hide if there is no tooltip created', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- spyOn(Tooltip.prototype, 'dispose')
-
- jQueryMock.fn.tooltip = Tooltip.jQueryInterface
- jQueryMock.elements = [div]
-
- jQueryMock.fn.tooltip.call(jQueryMock, 'dispose')
-
- expect(Tooltip.prototype.dispose).not.toHaveBeenCalled()
- })
-
- it('should throw error on undefined method', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const action = 'undefinedMethod'
-
- jQueryMock.fn.tooltip = Tooltip.jQueryInterface
- jQueryMock.elements = [div]
-
- try {
- jQueryMock.fn.tooltip.call(jQueryMock, action)
- } catch (error) {
- expect(error.message).toEqual(`No method named "${action}"`)
- }
- })
- })
-})
diff --git a/js/src/util/index.spec.js b/js/src/util/index.spec.js
deleted file mode 100644
index 9512c2fe0..000000000
--- a/js/src/util/index.spec.js
+++ /dev/null
@@ -1,382 +0,0 @@
-import * as Util from './index'
-
-/** Test helpers */
-import { getFixture, clearFixture } from '../../tests/helpers/fixture'
-
-describe('Util', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('getUID', () => {
- it('should generate uid', () => {
- const uid = Util.getUID('bs')
- const uid2 = Util.getUID('bs')
-
- expect(uid).not.toEqual(uid2)
- })
- })
-
- describe('getSelectorFromElement', () => {
- it('should get selector from data-target', () => {
- fixtureEl.innerHTML = [
- '<div id="test" data-target=".target"></div>',
- '<div class="target"></div>'
- ].join('')
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getSelectorFromElement(testEl)).toEqual('.target')
- })
-
- it('should get selector from href if no data-target set', () => {
- fixtureEl.innerHTML = [
- '<a id="test" href=".target"></a>',
- '<div class="target"></div>'
- ].join('')
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getSelectorFromElement(testEl)).toEqual('.target')
- })
-
- it('should get selector from href if data-target equal to #', () => {
- fixtureEl.innerHTML = [
- '<a id="test" data-target="#" href=".target"></a>',
- '<div class="target"></div>'
- ].join('')
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getSelectorFromElement(testEl)).toEqual('.target')
- })
-
- it('should return null if selector not found', () => {
- fixtureEl.innerHTML = '<a id="test" href=".target"></a>'
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getSelectorFromElement(testEl)).toBeNull()
- })
-
- it('should return null if no selector', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const testEl = fixtureEl.querySelector('div')
-
- expect(Util.getSelectorFromElement(testEl)).toBeNull()
- })
- })
-
- describe('getElementFromSelector', () => {
- it('should get element from data-target', () => {
- fixtureEl.innerHTML = [
- '<div id="test" data-target=".target"></div>',
- '<div class="target"></div>'
- ].join('')
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target'))
- })
-
- it('should get element from href if no data-target set', () => {
- fixtureEl.innerHTML = [
- '<a id="test" href=".target"></a>',
- '<div class="target"></div>'
- ].join('')
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target'))
- })
-
- it('should return null if element not found', () => {
- fixtureEl.innerHTML = '<a id="test" href=".target"></a>'
-
- const testEl = fixtureEl.querySelector('#test')
-
- expect(Util.getElementFromSelector(testEl)).toBeNull()
- })
-
- it('should return null if no selector', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const testEl = fixtureEl.querySelector('div')
-
- expect(Util.getElementFromSelector(testEl)).toBeNull()
- })
- })
-
- describe('getTransitionDurationFromElement', () => {
- it('should get transition from element', () => {
- fixtureEl.innerHTML = '<div style="transition: all 300ms ease-out;"></div>'
-
- expect(Util.getTransitionDurationFromElement(fixtureEl.querySelector('div'))).toEqual(300)
- })
-
- it('should return 0 if the element is undefined or null', () => {
- expect(Util.getTransitionDurationFromElement(null)).toEqual(0)
- expect(Util.getTransitionDurationFromElement(undefined)).toEqual(0)
- })
-
- it('should return 0 if the element do not possess transition', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- expect(Util.getTransitionDurationFromElement(fixtureEl.querySelector('div'))).toEqual(0)
- })
- })
-
- describe('triggerTransitionEnd', () => {
- it('should trigger transitionend event', done => {
- fixtureEl.innerHTML = '<div style="transition: all 300ms ease-out;"></div>'
-
- const el = fixtureEl.querySelector('div')
-
- el.addEventListener('transitionend', () => {
- expect().nothing()
- done()
- })
-
- Util.triggerTransitionEnd(el)
- })
- })
-
- describe('isElement', () => {
- it('should detect if the parameter is an element or not', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = document.querySelector('div')
-
- expect(Util.isElement(el)).toEqual(el.nodeType)
- expect(Util.isElement({})).toEqual(undefined)
- })
-
- it('should detect jQuery element', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = document.querySelector('div')
- const fakejQuery = {
- 0: el
- }
-
- expect(Util.isElement(fakejQuery)).toEqual(el.nodeType)
- })
- })
-
- describe('emulateTransitionEnd', () => {
- it('should emulate transition end', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = document.querySelector('div')
- const spy = spyOn(window, 'setTimeout')
-
- Util.emulateTransitionEnd(el, 10)
- expect(spy).toHaveBeenCalled()
- })
-
- it('should not emulate transition end if already triggered', done => {
- fixtureEl.innerHTML = '<div></div>'
-
- const el = fixtureEl.querySelector('div')
- const spy = spyOn(el, 'removeEventListener')
-
- Util.emulateTransitionEnd(el, 10)
- Util.triggerTransitionEnd(el)
-
- setTimeout(() => {
- expect(spy).toHaveBeenCalled()
- done()
- }, 20)
- })
- })
-
- describe('typeCheckConfig', () => {
- it('should check type of the config object', () => {
- const namePlugin = 'collapse'
- const defaultType = {
- toggle: 'boolean',
- parent: '(string|element)'
- }
- const config = {
- toggle: true,
- parent: 777
- }
-
- expect(() => {
- Util.typeCheckConfig(namePlugin, config, defaultType)
- }).toThrow(new Error('COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".'))
- })
- })
-
- describe('makeArray', () => {
- it('should convert node list to array', () => {
- const nodeList = document.querySelectorAll('div')
-
- expect(Array.isArray(nodeList)).toEqual(false)
- expect(Array.isArray(Util.makeArray(nodeList))).toEqual(true)
- })
-
- it('should return an empty array if the nodeList is undefined', () => {
- expect(Util.makeArray(null)).toEqual([])
- expect(Util.makeArray(undefined)).toEqual([])
- })
- })
-
- describe('isVisible', () => {
- it('should return false if the element is not defined', () => {
- expect(Util.isVisible(null)).toEqual(false)
- expect(Util.isVisible(undefined)).toEqual(false)
- })
-
- it('should return false if the element provided is not a dom element', () => {
- expect(Util.isVisible({})).toEqual(false)
- })
-
- it('should return false if the element is not visible with display none', () => {
- fixtureEl.innerHTML = '<div style="display: none;"></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Util.isVisible(div)).toEqual(false)
- })
-
- it('should return false if the element is not visible with visibility hidden', () => {
- fixtureEl.innerHTML = '<div style="visibility: hidden;"></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Util.isVisible(div)).toEqual(false)
- })
-
- it('should return false if the parent element is not visible', () => {
- fixtureEl.innerHTML = [
- '<div style="display: none;">',
- ' <div class="content"></div>',
- '</div>'
- ].join('')
-
- const div = fixtureEl.querySelector('.content')
-
- expect(Util.isVisible(div)).toEqual(false)
- })
-
- it('should return true if the element is visible', () => {
- fixtureEl.innerHTML = [
- '<div>',
- ' <div id="element"></div>',
- '</div>'
- ].join('')
-
- const div = fixtureEl.querySelector('#element')
-
- expect(Util.isVisible(div)).toEqual(true)
- })
- })
-
- describe('findShadowRoot', () => {
- it('should return null if shadow dom is not available', () => {
- // Only for newer browsers
- if (!document.documentElement.attachShadow) {
- expect().nothing()
- return
- }
-
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- spyOn(document.documentElement, 'attachShadow').and.returnValue(null)
-
- expect(Util.findShadowRoot(div)).toEqual(null)
- })
-
- it('should return null when we do not find a shadow root', () => {
- // Only for newer browsers
- if (!document.documentElement.attachShadow) {
- expect().nothing()
- return
- }
-
- spyOn(document, 'getRootNode').and.returnValue(undefined)
-
- expect(Util.findShadowRoot(document)).toEqual(null)
- })
-
- it('should return the shadow root when found', () => {
- // Only for newer browsers
- if (!document.documentElement.attachShadow) {
- expect().nothing()
- return
- }
-
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const shadowRoot = div.attachShadow({
- mode: 'open'
- })
-
- expect(Util.findShadowRoot(shadowRoot)).toEqual(shadowRoot)
-
- shadowRoot.innerHTML = '<button>Shadow Button</button>'
-
- expect(Util.findShadowRoot(shadowRoot.firstChild)).toEqual(shadowRoot)
- })
- })
-
- describe('noop', () => {
- it('should return a function', () => {
- expect(typeof Util.noop()).toEqual('function')
- })
- })
-
- describe('reflow', () => {
- it('should return element offset height to force the reflow', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Util.reflow(div)).toEqual(0)
- })
- })
-
- describe('getjQuery', () => {
- const fakejQuery = { trigger() {} }
-
- beforeEach(() => {
- Object.defineProperty(window, 'jQuery', {
- value: fakejQuery,
- writable: true
- })
- })
-
- afterEach(() => {
- window.jQuery = undefined
- })
-
- it('should return jQuery object when present', () => {
- expect(Util.getjQuery()).toEqual(fakejQuery)
- })
-
- it('should not return jQuery object when present if data-no-jquery', () => {
- document.body.setAttribute('data-no-jquery', '')
-
- expect(window.jQuery).toEqual(fakejQuery)
- expect(Util.getjQuery()).toEqual(null)
-
- document.body.removeAttribute('data-no-jquery')
- })
-
- it('should not return jQuery if not present', () => {
- window.jQuery = undefined
- expect(Util.getjQuery()).toEqual(null)
- })
- })
-})
diff --git a/js/src/util/sanitizer.spec.js b/js/src/util/sanitizer.spec.js
deleted file mode 100644
index 6dadd29a5..000000000
--- a/js/src/util/sanitizer.spec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import { DefaultWhitelist, sanitizeHtml } from './sanitizer'
-
-describe('Sanitizer', () => {
- describe('sanitizeHtml', () => {
- it('should return the same on empty string', () => {
- const empty = ''
-
- const result = sanitizeHtml(empty, DefaultWhitelist, null)
-
- expect(result).toEqual(empty)
- })
-
- it('should sanitize template by removing tags with XSS', () => {
- const template = [
- '<div>',
- ' <a href="javascript:alert(7)">Click me</a>',
- ' <span>Some content</span>',
- '</div>'
- ].join('')
-
- const result = sanitizeHtml(template, DefaultWhitelist, null)
-
- expect(result.indexOf('script') === -1).toEqual(true)
- })
-
- it('should allow aria attributes and safe attributes', () => {
- const template = [
- '<div aria-pressed="true">',
- ' <span class="test">Some content</span>',
- '</div>'
- ].join('')
-
- const result = sanitizeHtml(template, DefaultWhitelist, null)
-
- expect(result.indexOf('aria-pressed') !== -1).toEqual(true)
- expect(result.indexOf('class="test"') !== -1).toEqual(true)
- })
-
- it('should remove not whitelist tags', () => {
- const template = [
- '<div>',
- ' <script>alert(7)</script>',
- '</div>'
- ].join('')
-
- const result = sanitizeHtml(template, DefaultWhitelist, null)
-
- expect(result.indexOf('<script>') === -1).toEqual(true)
- })
-
- it('should not use native api to sanitize if a custom function passed', () => {
- const template = [
- '<div>',
- ' <span>Some content</span>',
- '</div>'
- ].join('')
-
- function mySanitize(htmlUnsafe) {
- return htmlUnsafe
- }
-
- spyOn(DOMParser.prototype, 'parseFromString')
-
- const result = sanitizeHtml(template, DefaultWhitelist, mySanitize)
-
- expect(result).toEqual(template)
- expect(DOMParser.prototype.parseFromString).not.toHaveBeenCalled()
- })
- })
-})