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

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorJohann-S <johann.servoire@gmail.com>2018-06-09 22:11:05 +0300
committerXhmikosR <xhmikosr@gmail.com>2019-02-20 23:05:45 +0300
commit64591b3722128d89252b8f1c840cd846940b7f5c (patch)
tree971c65a6fd9f506da55e4be31d1fece7f9b20b89 /js
parent4d6e41dea6492f18029f0dd70b118217c02f27d8 (diff)
fix(manipulator): increase coverage for manipulator
Diffstat (limited to 'js')
-rw-r--r--js/src/carousel.js4
-rw-r--r--js/src/collapse.js5
-rw-r--r--js/src/dom/manipulator.js80
-rw-r--r--js/src/dropdown.js2
-rw-r--r--js/src/modal.js20
-rw-r--r--js/src/scrollspy.js2
-rw-r--r--js/src/tooltip.js11
-rw-r--r--js/src/util.js49
-rw-r--r--js/tests/index.html5
-rw-r--r--js/tests/karma.conf.js10
-rw-r--r--js/tests/unit/dom/manipulator.js179
-rw-r--r--js/tests/unit/modal.js6
12 files changed, 286 insertions, 87 deletions
diff --git a/js/src/carousel.js b/js/src/carousel.js
index 15a56bd76a..352b238490 100644
--- a/js/src/carousel.js
+++ b/js/src/carousel.js
@@ -562,8 +562,8 @@ class Carousel {
}
const config = {
- ...Util.getDataAttributes(target),
- ...Util.getDataAttributes(this)
+ ...Manipulator.getDataAttributes(target),
+ ...Manipulator.getDataAttributes(this)
}
const slideIndex = this.getAttribute('data-slide-to')
diff --git a/js/src/collapse.js b/js/src/collapse.js
index d04743d039..eebac13bbf 100644
--- a/js/src/collapse.js
+++ b/js/src/collapse.js
@@ -7,6 +7,7 @@
import Data from './dom/data'
import EventHandler from './dom/eventHandler'
+import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selectorEngine'
import Util from './util'
@@ -347,7 +348,7 @@ class Collapse {
let data = Data.getData(element, DATA_KEY)
const _config = {
...Default,
- ...Util.getDataAttributes(element),
+ ...Manipulator.getDataAttributes(element),
...typeof config === 'object' && config ? config : {}
}
@@ -391,7 +392,7 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
event.preventDefault()
}
- const triggerData = Util.getDataAttributes(this)
+ const triggerData = Manipulator.getDataAttributes(this)
const selector = Util.getSelectorFromElement(this)
const selectorElements = Util.makeArray(SelectorEngine.find(selector))
diff --git a/js/src/dom/manipulator.js b/js/src/dom/manipulator.js
index 201902b77e..db3113f88d 100644
--- a/js/src/dom/manipulator.js
+++ b/js/src/dom/manipulator.js
@@ -1,12 +1,32 @@
-import Util from '../util'
-
/**
* --------------------------------------------------------------------------
- * Bootstrap (v4.0.0-beta): dom/manipulator.js
+ * Bootstrap (v4.1.1): dom/manipulator.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
+const regexDataKey = /[A-Z]/g
+
+function normalizeData(val) {
+ if (val === 'true') {
+ return true
+ } else if (val === 'false') {
+ return false
+ } else if (val === 'null') {
+ return null
+ } else if (val === Number(val).toString()) {
+ return Number(val)
+ } else if (val === '') {
+ return null
+ }
+
+ return val
+}
+
+function normalizeDataKey(key) {
+ return key.replace(regexDataKey, (chr) => chr.toLowerCase())
+}
+
const Manipulator = {
setChecked(input, val) {
if (input instanceof HTMLInputElement) {
@@ -23,21 +43,55 @@ const Manipulator = {
},
setDataAttribute(element, key, value) {
- const $ = Util.jQuery
- if (typeof $ !== 'undefined') {
- $(element).data(key, value)
- }
-
- element.setAttribute(`data-${key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`)}`, value)
+ element.setAttribute(`data-${normalizeDataKey(key)}`, value)
},
removeDataAttribute(element, key) {
- const $ = Util.jQuery
- if (typeof $ !== 'undefined') {
- $(element).removeData(key)
+ element.removeAttribute(`data-${normalizeDataKey(key)}`)
+ },
+
+ getDataAttributes(element) {
+ if (typeof element === 'undefined' || element === null) {
+ return {}
+ }
+
+ let attributes
+ if (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset')) {
+ attributes = {
+ ...element.dataset
+ }
+ } else {
+ attributes = {}
+ for (let i = 0; i < element.attributes.length; i++) {
+ const attribute = element.attributes[i]
+
+ if (attribute.nodeName.indexOf('data-') !== -1) {
+ // remove 'data-' part of the attribute name
+ const attributeName = attribute
+ .nodeName
+ .substring('data-'.length)
+ .replace(/-./g, (str) => str.charAt(1).toUpperCase())
+
+ attributes[attributeName] = attribute.nodeValue
+ }
+ }
}
- element.removeAttribute(`data-${key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`)}`)
+ for (const key in attributes) {
+ if (!Object.prototype.hasOwnProperty.call(attributes, key)) {
+ continue
+ }
+
+ attributes[key] = normalizeData(attributes[key])
+ }
+
+ return attributes
+ },
+
+ getDataAttribute(element, key) {
+ return normalizeData(element
+ .getAttribute(`data-${normalizeDataKey(key)}`)
+ )
},
offset(element) {
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 282e7645ff..b1487b64ad 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -267,7 +267,7 @@ class Dropdown {
_getConfig(config) {
config = {
...this.constructor.Default,
- ...Util.getDataAttributes(this._element),
+ ...Manipulator.getDataAttributes(this._element),
...config
}
diff --git a/js/src/modal.js b/js/src/modal.js
index 4f23fff741..0ecd6948f2 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -473,7 +473,7 @@ class Modal {
// Restore fixed content padding
Util.makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
.forEach((element) => {
- const padding = Util.getDataAttribute(element, 'padding-right')
+ const padding = Manipulator.getDataAttribute(element, 'padding-right')
if (typeof padding !== 'undefined') {
Manipulator.removeDataAttribute(element, 'padding-right')
element.style.paddingRight = padding
@@ -483,7 +483,7 @@ class Modal {
// Restore sticky content and navbar-toggler margin
Util.makeArray(SelectorEngine.find(`${Selector.STICKY_CONTENT}`))
.forEach((element) => {
- const margin = Util.getDataAttribute(element, 'margin-right')
+ const margin = Manipulator.getDataAttribute(element, 'margin-right')
if (typeof margin !== 'undefined') {
Manipulator.removeDataAttribute(element, 'margin-right')
element.style.marginRight = margin
@@ -491,17 +491,13 @@ class Modal {
})
// Restore body padding
- const padding = Util.getDataAttribute(document.body, 'padding-right')
+ const padding = Manipulator.getDataAttribute(document.body, 'padding-right')
if (typeof padding !== 'undefined') {
Manipulator.removeDataAttribute(document.body, 'padding-right')
document.body.style.paddingRight = padding
} else {
document.body.style.paddingRight = ''
}
-
- static _getInstance(element) {
- return Data.getData(element, DATA_KEY)
- }
}
_getScrollbarWidth() { // thx d.walsh
@@ -520,7 +516,7 @@ class Modal {
let data = Data.getData(this, DATA_KEY)
const _config = {
...Default,
- ...Util.getDataAttributes(this),
+ ...Manipulator.getDataAttributes(this),
...typeof config === 'object' && config ? config : {}
}
@@ -539,6 +535,10 @@ class Modal {
}
})
}
+
+ static _getInstance(element) {
+ return Data.getData(element, DATA_KEY)
+ }
}
/**
@@ -557,8 +557,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
const config = Data.getData(target, DATA_KEY)
? 'toggle' : {
- ...Util.getDataAttributes(target),
- ...Util.getDataAttributes(this)
+ ...Manipulator.getDataAttributes(target),
+ ...Manipulator.getDataAttributes(this)
}
if (this.tagName === 'A' || this.tagName === 'AREA') {
diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js
index 458f5170e9..f317284c9c 100644
--- a/js/src/scrollspy.js
+++ b/js/src/scrollspy.js
@@ -322,7 +322,7 @@ class ScrollSpy {
EventHandler.on(window, Event.LOAD_DATA_API, () => {
Util.makeArray(SelectorEngine.find(Selector.DATA_SPY))
- .forEach((spy) => new ScrollSpy(spy, Util.getDataAttributes(spy)))
+ .forEach((spy) => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
})
/**
diff --git a/js/src/tooltip.js b/js/src/tooltip.js
index 9b8b8263a9..fbe9ed856a 100644
--- a/js/src/tooltip.js
+++ b/js/src/tooltip.js
@@ -11,6 +11,7 @@ import {
} from './tools/sanitizer'
import Data from './dom/data'
import EventHandler from './dom/eventHandler'
+import Manipulator from './dom/manipulator'
import Popper from 'popper.js'
import SelectorEngine from './dom/selectorEngine'
import Util from './util'
@@ -671,7 +672,7 @@ class Tooltip {
}
_getConfig(config) {
- const dataAttributes = Util.getDataAttributes(this.element)
+ const dataAttributes = Manipulator.getDataAttributes(this.element)
Object.keys(dataAttributes)
.forEach((dataAttr) => {
@@ -741,10 +742,6 @@ class Tooltip {
.map((token) => token.trim())
.forEach((tClass) => tip.classList.remove(tClass))
}
-
- static _getInstance(element) {
- return Data.getData(element, DATA_KEY)
- }
}
_handlePopperPlacementChange(popperData) {
@@ -793,6 +790,10 @@ class Tooltip {
}
})
}
+
+ static _getInstance(element) {
+ return Data.getData(element, DATA_KEY)
+ }
}
/**
diff --git a/js/src/util.js b/js/src/util.js
index 78f5fe3fbe..0b7f492fee 100644
--- a/js/src/util.js
+++ b/js/src/util.js
@@ -22,20 +22,6 @@ function toType(obj) {
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
}
-function normalizeData(val) {
- if (val === 'true') {
- return true
- } else if (val === 'false') {
- return false
- } else if (val === 'null') {
- return null
- } else if (val === Number(val).toString()) {
- return Number(val)
- }
-
- return val
-}
-
const Util = {
TRANSITION_END: 'bsTransitionEnd',
@@ -164,41 +150,6 @@ const Util = {
return [nodeList]
},
- getDataAttributes(element) {
- if (typeof element === 'undefined' || element === null) {
- return {}
- }
-
- let attributes
- if (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset')) {
- attributes = this.extend({}, element.dataset)
- } else {
- attributes = {}
- for (let i = 0; i < element.attributes.length; i++) {
- const attribute = element.attributes[i]
- if (attribute.nodeName.indexOf('data-') !== -1) {
- // remove 'data-' part of the attribute name
- const attributeName = attribute.nodeName.substring('data-'.length).replace(/-./g, (str) => str.charAt(1).toUpperCase())
- attributes[attributeName] = attribute.nodeValue
- }
- }
- }
-
- for (const key in attributes) {
- if (!Object.prototype.hasOwnProperty.call(attributes, key)) {
- continue
- }
-
- attributes[key] = normalizeData(attributes[key])
- }
-
- return attributes
- },
-
- getDataAttribute(element, key) {
- return normalizeData(element.getAttribute(`data-${key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`)}`))
- },
-
isVisible(element) {
if (typeof element === 'undefined' || element === null) {
return false
diff --git a/js/tests/index.html b/js/tests/index.html
index 19ff53ce8a..f4a99df44e 100644
--- a/js/tests/index.html
+++ b/js/tests/index.html
@@ -97,10 +97,11 @@
</script>
<!-- Transpiled Plugins -->
+ <script src="../dist/dom/polyfill.js"></script>
+ <script src="../dist/dom/manipulator.js"></script>
<script src="../dist/dom/eventHandler.js"></script>
<script src="../dist/dom/selectorEngine.js"></script>
<script src="../dist/dom/data.js"></script>
- <script src="../dist/dom/manipulator.js"></script>
<script src="../dist/util.js"></script>
<script src="../dist/alert.js"></script>
<script src="../dist/button.js"></script>
@@ -116,6 +117,8 @@
<!-- Unit Tests -->
<script src="unit/dom/eventHandler.js"></script>
+ <script src="unit/dom/manipulator.js"></script>
+ <script src="unit/dom/data.js"></script>
<script src="unit/alert.js"></script>
<script src="unit/button.js"></script>
<script src="unit/carousel.js"></script>
diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js
index 066165a14d..469a95561f 100644
--- a/js/tests/karma.conf.js
+++ b/js/tests/karma.conf.js
@@ -140,6 +140,16 @@ if (bundle) {
branches: 86,
functions: 89,
lines: 90
+ },
+ each: {
+ overrides: {
+ 'js/src/dom/polyfill.js': {
+ statements: 39,
+ lines: 37,
+ branches: 19,
+ functions: 50
+ }
+ }
}
}
}
diff --git a/js/tests/unit/dom/manipulator.js b/js/tests/unit/dom/manipulator.js
new file mode 100644
index 0000000000..19effa4231
--- /dev/null
+++ b/js/tests/unit/dom/manipulator.js
@@ -0,0 +1,179 @@
+$(function () {
+ 'use strict'
+
+ QUnit.module('manipulator')
+
+ QUnit.test('should be defined', function (assert) {
+ assert.expect(1)
+ assert.ok(Manipulator, 'Manipulator is defined')
+ })
+
+ QUnit.test('should set checked for input', function (assert) {
+ assert.expect(2)
+
+ var $input = $('<input type="checkbox" />').appendTo('#qunit-fixture')
+ Manipulator.setChecked($input[0], true)
+
+ assert.ok($input[0].checked)
+
+ Manipulator.setChecked($input[0], false)
+
+ assert.ok(!$input[0].checked)
+ })
+
+ QUnit.test('should not set checked for non input element', function (assert) {
+ assert.expect(1)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+ Manipulator.setChecked($div[0], true)
+
+ assert.ok(typeof $div[0].checked === 'undefined')
+ })
+
+ QUnit.test('should verify if an element is checked', function (assert) {
+ assert.expect(2)
+
+ var $input = $('<input type="checkbox" />').appendTo('#qunit-fixture')
+ Manipulator.setChecked($input[0], true)
+
+ assert.ok(Manipulator.isChecked($input[0]))
+
+ Manipulator.setChecked($input[0], false)
+
+ assert.ok(!Manipulator.isChecked($input[0]))
+ })
+
+ QUnit.test('should throw an error when the element is not an input', function (assert) {
+ assert.expect(1)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+ try {
+ Manipulator.isChecked($div[0])
+ } catch (e) {
+ assert.strictEqual(e.message, 'INPUT parameter is not an HTMLInputElement')
+ }
+ })
+
+ QUnit.test('should set data attribute', function (assert) {
+ assert.expect(1)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ Manipulator.setDataAttribute($div[0], 'test', 'test')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), 'test')
+ })
+
+ QUnit.test('should set data attribute in lower case', function (assert) {
+ assert.expect(1)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ Manipulator.setDataAttribute($div[0], 'tEsT', 'test')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), 'test')
+ })
+
+ QUnit.test('should get data attribute', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div data-test="null" />').appendTo('#qunit-fixture')
+
+ assert.strictEqual(Manipulator.getDataAttribute($div[0], 'test'), null)
+
+ var $div2 = $('<div data-test2="js" />').appendTo('#qunit-fixture')
+
+ assert.strictEqual(Manipulator.getDataAttribute($div2[0], 'tEst2'), 'js')
+ })
+
+ QUnit.test('should get data attributes', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div data-test="js" data-test2="js2" />').appendTo('#qunit-fixture')
+ var $div2 = $('<div data-test3="js" data-test4="js2" />').appendTo('#qunit-fixture')
+
+ assert.propEqual(Manipulator.getDataAttributes($div[0]), {
+ test: 'js',
+ test2: 'js2'
+ })
+
+ var stub = sinon
+ .stub(Object, 'getOwnPropertyDescriptor')
+ .callsFake(function () {
+ return false
+ })
+
+ assert.propEqual(Manipulator.getDataAttributes($div2[0]), {
+ test3: 'js',
+ test4: 'js2'
+ })
+
+ stub.restore()
+ })
+
+ QUnit.test('should remove data attribute', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ Manipulator.setDataAttribute($div[0], 'test', 'test')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), 'test')
+
+ Manipulator.removeDataAttribute($div[0], 'test')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), null)
+ })
+
+ QUnit.test('should remove data attribute in lower case', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ Manipulator.setDataAttribute($div[0], 'test', 'test')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), 'test')
+
+ Manipulator.removeDataAttribute($div[0], 'tESt')
+
+ assert.strictEqual($div[0].getAttribute('data-test'), null)
+ })
+
+ QUnit.test('should return element offsets', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ var offset = Manipulator.offset($div[0])
+
+ assert.ok(typeof offset.top === 'number')
+ assert.ok(typeof offset.left === 'number')
+ })
+
+ QUnit.test('should return element position', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div />').appendTo('#qunit-fixture')
+
+ var offset = Manipulator.position($div[0])
+
+ assert.ok(typeof offset.top === 'number')
+ assert.ok(typeof offset.left === 'number')
+ })
+
+ QUnit.test('should toggle class', function (assert) {
+ assert.expect(2)
+
+ var $div = $('<div class="test" />').appendTo('#qunit-fixture')
+
+ Manipulator.toggleClass($div[0], 'test')
+
+ assert.ok(!$div.hasClass('test'))
+
+ Manipulator.toggleClass($div[0], 'test')
+
+ assert.ok($div.hasClass('test'))
+
+ Manipulator.toggleClass(null)
+ })
+})
diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js
index 7aa7a95b3c..0739f03782 100644
--- a/js/tests/unit/modal.js
+++ b/js/tests/unit/modal.js
@@ -422,7 +422,7 @@ $(function () {
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
- assert.strictEqual(typeof $body.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing')
+ assert.strictEqual(document.body.getAttribute('data-padding-right'), null, 'data-padding-right should be cleared after closing')
$body.removeAttr('style')
done()
})
@@ -488,7 +488,7 @@ $(function () {
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
- assert.strictEqual(typeof $element.data('padding-right'), 'undefined', 'data-padding-right should be cleared after closing')
+ assert.strictEqual($element[0].getAttribute('data-padding-right'), null, 'data-padding-right should be cleared after closing')
$element.remove()
done()
})
@@ -530,7 +530,7 @@ $(function () {
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
- assert.strictEqual(typeof $element.data('margin-right'), 'undefined', 'data-margin-right should be cleared after closing')
+ assert.strictEqual($element[0].getAttribute('data-margin-right'), null, 'data-margin-right should be cleared after closing')
$element.remove()
done()
})