Skip to content

Commit 5ca9fe3

Browse files
authored
feat: Use dom utils (bootstrap-vue#1017)
* feat: dom utility methods * Update index.js * [tooltip.js] Use dom utils * [dropdown.js] Use dom utils * [scrollspy.js] Use dom utils * feat(array mixin): Add polyfill for Array.find for IE * [modal] use dom utils * [popover.vue] Use dom utils * [tooltip.vue] Use dom utils
1 parent 7ed199d commit 5ca9fe3

File tree

4 files changed

+57
-22
lines changed

4 files changed

+57
-22
lines changed

lib/components/modal.vue

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@
9393
<script>
9494
import bBtn from './button';
9595
import { listenOnRootMixin } from '../mixins';
96-
import { from as arrayFrom } from '../utils/array'
96+
import { from as arrayFrom, arrayFind } from '../utils/array';
97+
import { isElement, isVisible, selectAll, select } from '../utils/dom';
9798
9899
const FOCUS_SELECTOR = [
99100
'button:not([disabled])',
@@ -104,27 +105,12 @@
104105
'[tabindex]:not([disabled]):not(.disabled)'
105106
].join(',');
106107
107-
// Determine if an HTML element is visible - Faster than CSS check
108-
function isVisible(el) {
109-
return el && (el.offsetWidth > 0 || el.offsetHeight > 0);
110-
}
111-
112108
// Find the first visible element contained in a given root element
113109
function findFirstVisible(root, selector) {
114-
if (!root || !root.querySelectorAll || !selector) {
110+
if (!isElement(root) || !selector) {
115111
return null;
116112
}
117-
let els = arrayFrom(root.querySelectorAll(selector));
118-
119-
// IE 10 & 11 do not support native array.find()
120-
// So we try native find first, then fall back to a loop
121-
let el = els.find ? els.find(el => isVisible(el)) : null;
122-
for (let i = 0; !el && i < els.length; i++) {
123-
if (isVisible(els[i])) {
124-
el = els[i];
125-
}
126-
}
127-
return el;
113+
return arrayFind(selectAll(selector, root), isVisible) || null;
128114
}
129115
130116
export default {
@@ -143,7 +129,7 @@
143129
computed: {
144130
body() {
145131
if (typeof document !== 'undefined') {
146-
return document.querySelector('body');
132+
return document.body;
147133
}
148134
}
149135
},
@@ -357,7 +343,7 @@
357343
if (el) {
358344
if (typeof el === 'string') {
359345
// CSS Selector
360-
el = document.querySelector(el);
346+
el = select(el);
361347
}
362348
if (el && el.$el && typeof el.$el.focus === 'function') {
363349
// Component vm reference

lib/components/popover.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import PopOver from '../classes/popover';
1111
import { isArray } from '../utils/array';
1212
import { assign } from '../utils/object';
13+
import { isElement } from '../utils/dom';
1314
import { observeDom, warn } from '../utils';
1415
1516
export default {
@@ -160,7 +161,7 @@
160161
} else if (typeof target === 'object' && target.$el) {
161162
// Component reference
162163
return target.$el;
163-
} else if (typeof target === 'object' && target.tagName) {
164+
} else if (typeof target === 'object' && isElement(target)) {
164165
// Element reference
165166
return target;
166167
}

lib/components/tooltip.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import ToolTip from '../classes/tooltip';
1010
import { isArray } from '../utils/array';
1111
import { assign } from '../utils/object';
12+
import { isElement } from '../utils/dom';
1213
import { observeDom, warn } from '../utils';
1314
1415
export default {
@@ -150,7 +151,7 @@
150151
} else if (typeof target === 'object' && target.$el) {
151152
// Component reference
152153
return target.$el;
153-
} else if (typeof target === 'object' && target.tagName) {
154+
} else if (typeof target === 'object' && isElement(target)) {
154155
// Element reference
155156
return target;
156157
}

lib/utils/array.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,52 @@ if (!Array.from) {
7878
})();
7979
}
8080

81+
// https://tc39.github.io/ecma262/#sec-array.prototype.find
82+
// Needed for IE support
83+
if (!Array.prototype.find) {
84+
Object.defineProperty(Array.prototype, 'find', {
85+
value: function(predicate) {
86+
// 1. Let O be ? ToObject(this value).
87+
if (this == null) {
88+
throw new TypeError('"this" is null or not defined');
89+
}
90+
91+
const o = Object(this);
92+
93+
// 2. Let len be ? ToLength(? Get(O, "length")).
94+
const len = o.length >>> 0;
95+
96+
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
97+
if (typeof predicate !== 'function') {
98+
throw new TypeError('predicate must be a function');
99+
}
100+
101+
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
102+
const thisArg = arguments[1];
103+
104+
// 5. Let k be 0.
105+
let k = 0;
106+
107+
// 6. Repeat, while k < len
108+
while (k < len) {
109+
// a. Let Pk be ! ToString(k).
110+
// b. Let kValue be ? Get(O, Pk).
111+
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
112+
// d. If testResult is true, return kValue.
113+
const kValue = o[k];
114+
if (predicate.call(thisArg, kValue, k, o)) {
115+
return kValue;
116+
}
117+
// e. Increase k by 1.
118+
k++;
119+
}
120+
121+
// 7. Return undefined.
122+
return undefined;
123+
}
124+
});
125+
}
126+
81127
if (!Array.isArray) {
82128
Array.isArray = arg => Object.prototype.toString.call(arg) === "[object Array]";
83129
}
@@ -88,6 +134,7 @@ export const isArray = Array.isArray;
88134

89135
// Instance
90136
export const arrayIncludes = (array, value) => array.indexOf(value) !== -1;
137+
export const arrayFind = (array, fn, thisArg) => array.find(fn, thisArg);
91138
export function concat() {
92139
return Array.prototype.concat.apply([], arguments);
93140
}

0 commit comments

Comments
 (0)