Commit 64591b37 authored by Johann-S's avatar Johann-S Committed by XhmikosR
Browse files

fix(manipulator): increase coverage for manipulator

parent 4d6e41de
main cleanup-floating-forms cssvar-function dependabot/npm_and_yarn/stylelint-and-stylelint-config-twbs-bootstrap-15.3.0 extend-snippets feat/data-target floating-always-visible floating-labels-icons fod-main-banner form-controls-with-icons github/fork/719media/patch-13 github/fork/719media/patch-14 github/fork/719media/patch-9 github/fork/ChellyAhmed/fix-typo-reboot.md github/fork/ChellyAhmed/offcanvas-scroll-back github/fork/CtrlAltLilith/main github/fork/Elysiome/offcanvas-optional-window-resizing github/fork/JanSargsyan/main github/fork/LunicLynx/support-different-line-height-for-buttons github/fork/Psixodelik/main github/fork/Ronid1/ronid1/offcanvas_static_backdrop github/fork/RyanBerliner/tooltip-accessibility github/fork/SantiagoPVazquez/Feature-default-border-bottom-to-dropdown-item github/fork/Sir-Genius/utils github/fork/Sumit-Singh-8/main github/fork/Viktor-VERA2020/offcanvas-slide github/fork/Zivangu9/input-group-for-form-control-plaintext github/fork/alpadev/alpadev/call-dispose-on-component-reinstantiation github/fork/astagi/fix/tree-shake-modules github/fork/compnerd/dark-accordion-icon github/fork/derSascha/dropdown-dont-close-on-input-click github/fork/dev-ph1l/main github/fork/donquixote/issue-33861-utl-mixin github/fork/florianlacreuse/mixin-make-row-gutter-y github/fork/gregorw/main github/fork/iteggmbh/transitionend-dispose-race github/fork/jdelStrother/patch-1 github/fork/jonnysp/form-floating github/fork/jonnysp/independent-offcanvas github/fork/jonnysp/theme-dark-on-card-and-modal-fix github/fork/josefdlange/floating-label-placeholder-opacity github/fork/julien-deramond/enhance-change-version.js github/fork/julien-deramond/main-jd-fix-offset-content github/fork/julien-deramond/main-jd-issue-with-utitlies github/fork/julien-deramond/main-xmr-pa11y-ci-jd-add-hideElements github/fork/kyletsang/fix-tooltip-padding github/fork/lacutah/CheckboxCenteringDocumentation github/fork/lekoala/patch-3 github/fork/louismaximepiton/main-kld-lmp-collapse-proposal github/fork/louismaximepiton/main-lmp-card-inner-border-radius-fix github/fork/louismaximepiton/main-lmp-carousel-multiple-images github/fork/louismaximepiton/main-lmp-css-var-init github/fork/louismaximepiton/main-lmp-disabled-floating-label-fix github/fork/louismaximepiton/main-lmp-input-range-fix github/fork/louismaximepiton/main-lmp-shift-color github/fork/louismaximepiton/main-lmp-table-active-tr-fix github/fork/maciek-szn/switch github/fork/michael-roth/feature/19964-multiple-tab-targets github/fork/mistic100/dom-utils github/fork/nkdas91/accordion github/fork/nstungcom/fix-missing-modal-open-class github/fork/oraliahdz/animation-utilities github/fork/pine3ree/patch-7 github/fork/pouwerkerk/unindent-scss-docs-shortcode github/fork/smares/smares-no-scolling-on-modal-close github/fork/tgm-git/patch-1 gs-forms gs-toasts-with-animated-progress-bar gs/add-history-helper gs/change-version-dir-on-docs gs/data-must-set-onlu-one-instance gs/docs/fix-drop-down-error gs/event-handler-2 gs/make-docs-js-build gs/make-simple-attribute-toggler gs/popover-fix-doc gs/provide-steConfig-method gs/scrollspy-smoothscroll-option-use-browser-history gs/streamline-jqueryInterface gs/support-drop-down-in-navbar gs/test-js-generic-trigger gs/try-web-components gs/tweak-collapse-js-selector gs/use-event-handler-in-cocmponent gs/use-rollup-replace-for-version jo-docs-thanks-page jo-ssr-friendly logical-props-spacing-utils main-fod-disabled-form-check-label main-fod-nested-accordion main-fod-simpler-table-structure main-fod-table-separator main-fod-utilities-contrast main-jd-abbr-title main-jd-add-chips main-jd-add-doc-for-sass-custom-colors main-jd-add-enable-host-to-handle-web-components main-jd-browserstack-fine-tune main-jd-browserstack-updates main-jd-docs-consistent-usage-of-css-sections-step-2 main-jd-fix-docs-headers-in-white main-jd-fix-highlight-docs-border-radius main-jd-fix-placeholder-color-background-params-for-img-markup main-jd-glossary-experiment main-jd-postcss-drop-empty-css-vars main-jd-proto-doc-astro main-jd-skip-navigation-component main-jd-stackblitz-for-examples main-jd-upgrade-browserlistrc main-jd-use-host main-lmp-dark-theme-customization main-lmp-handle-scroll-target main-lmp-tab-fix main-mc-opensearch main-xmr-bundlewatch-action main-xmr-eslint-plugin-compat main-xmr-hugo-docs-vendor main-xmr-hugo-rm-ver main-xmr-linkinator-prod main-xmr-min-mangle main-xmr-pa11y-ci more-darkmode-examples nested-dropdowns patrickhlauke-issue37428 patrickhlauke-use-of-color-tweaks pr/34102 pr/37590 previous-next-docs-links sticky-thead utilities-functions-mixin v530-dev v6-postcss-custom-media v6-spinner-dots v6/gs/use-floating-ui-in-place-of-popper xmr/dev xmr/docs-png xmr/docs-svgs xmr/hugo-reorg-files xmr/js-2 xmr/markdownlint xmr/prepare-530-alpha2 xmr/xo v5.3.0-alpha1 v5.2.3 v5.2.2 v5.2.1 v5.2.0 v5.2.0-beta1 v5.1.3 v5.1.2 v5.1.1 v5.1.0 v5.0.2 v5.0.1 v5.0.0 v5.0.0-beta3 v5.0.0-beta2 v5.0.0-beta1 v5.0.0-alpha3 v5.0.0-alpha2 v5.0.0-alpha1
5 merge requests!31948Examples/Floating-labels: fix bad behavior with autofill,!30064test,!29779Responsive sizing,!28882fix custom-select-indicator in IE10,!28721Hot test
Showing with 286 additions and 87 deletions
+286 -87
......@@ -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')
......
......@@ -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))
......
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) {
......
......@@ -267,7 +267,7 @@ class Dropdown {
_getConfig(config) {
config = {
...this.constructor.Default,
...Util.getDataAttributes(this._element),
...Manipulator.getDataAttributes(this._element),
...config
}
......
......@@ -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') {
......
......@@ -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)))
})
/**
......
......@@ -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)
}
}
/**
......
......@@ -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
......
......@@ -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>
......
......@@ -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
}
}
}
}
}
......
$(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)
})
})
......@@ -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()
})
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment