Skip to content

Commit 6f13e04

Browse files
committed
Merge pull request react-bootstrap#1172 from react-bootstrap/dom-utils
Dom utils
2 parents 136d442 + 653d2ff commit 6f13e04

File tree

10 files changed

+61
-211
lines changed

10 files changed

+61
-211
lines changed

docs/src/ComponentsPage.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* eslint react/no-did-mount-set-state: 0 */
22

33
import React from 'react';
4+
import getOffset from 'dom-helpers/query/offset';
5+
import css from 'dom-helpers/style';
46

57
import Affix from '../../src/Affix';
68
import Nav from '../../src/Nav';
@@ -33,9 +35,8 @@ const ComponentsPage = React.createClass({
3335

3436
componentDidMount() {
3537
let elem = React.findDOMNode(this.refs.sideNav);
36-
let domUtils = Affix.domUtils;
37-
let sideNavOffsetTop = domUtils.getOffset(elem).top;
38-
let sideNavMarginTop = parseInt(domUtils.getComputedStyles(elem.firstChild).marginTop, 10);
38+
let sideNavOffsetTop = getOffset(elem).top;
39+
let sideNavMarginTop = parseInt(css(elem.firstChild, 'marginTop'), 10);
3940
let topNavHeight = React.findDOMNode(this.refs.topNav).offsetHeight;
4041

4142
this.setState({

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
},
109109
"dependencies": {
110110
"babel-runtime": "^5.8.19",
111-
"lodash": "^3.10.0",
112-
"classnames": "^2.1.3"
111+
"classnames": "^2.1.3",
112+
"dom-helpers": "^2.2.4",
113+
"lodash": "^3.10.0"
113114
}
114115
}

src/Affix.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import React from 'react';
22
import classNames from 'classnames';
33
import AffixMixin from './AffixMixin';
4-
import domUtils from './utils/domUtils';
54

65
const Affix = React.createClass({
7-
statics: {
8-
domUtils
9-
},
106

117
mixins: [AffixMixin],
128

src/Collapse.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ const MARGINS = {
1616

1717
function getDimensionValue(dimension, elem){
1818
let value = elem[`offset${capitalize(dimension)}`];
19-
let computedStyles = domUtils.getComputedStyles(elem);
2019
let margins = MARGINS[dimension];
2120

2221
return (value +
23-
parseInt(computedStyles[margins[0]], 10) +
24-
parseInt(computedStyles[margins[1]], 10)
22+
parseInt(domUtils.css(elem, margins[0]), 10) +
23+
parseInt(domUtils.css(elem, margins[1]), 10)
2524
);
2625
}
2726

src/Modal.js

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import React, { cloneElement } from 'react';
33
import classNames from 'classnames';
44
import domUtils from './utils/domUtils';
5+
import getScrollbarSize from 'dom-helpers/util/scrollbarSize';
56
import EventListener from './utils/EventListener';
67
import createChainedFunction from './utils/createChainedFunction';
78
import CustomPropTypes from './utils/CustomPropTypes';
@@ -67,28 +68,6 @@ function onFocus(context, handler) {
6768
return currentFocusListener;
6869
}
6970

70-
let scrollbarSize;
71-
72-
function getScrollbarSize() {
73-
if (scrollbarSize !== undefined) {
74-
return scrollbarSize;
75-
}
76-
77-
let scrollDiv = document.createElement('div');
78-
79-
scrollDiv.style.position = 'absolute';
80-
scrollDiv.style.top = '-9999px';
81-
scrollDiv.style.width = '50px';
82-
scrollDiv.style.height = '50px';
83-
scrollDiv.style.overflow = 'scroll';
84-
85-
document.body.appendChild(scrollDiv);
86-
scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
87-
document.body.removeChild(scrollDiv);
88-
89-
scrollDiv = null;
90-
return scrollbarSize;
91-
}
9271

9372
const Modal = React.createClass({
9473
propTypes: {
@@ -377,18 +356,16 @@ const Modal = React.createClass({
377356

378357
checkForFocus() {
379358
if (domUtils.canUseDom) {
380-
try {
381-
this.lastFocus = document.activeElement;
382-
}
383-
catch (e) {} // eslint-disable-line no-empty
359+
this.lastFocus = domUtils.activeElement(document);
384360
}
385361
},
386362

387363
focusModalContent() {
388364
let modalContent = React.findDOMNode(this.refs.dialog);
389-
let current = domUtils.activeElement(this);
365+
let current = domUtils.activeElement(domUtils.ownerDocument(this));
390366
let focusInModal = current && domUtils.contains(modalContent, current);
391367

368+
392369
if (modalContent && this.props.autoFocus && !focusInModal) {
393370
this.lastFocus = current;
394371
modalContent.focus();
@@ -407,7 +384,7 @@ const Modal = React.createClass({
407384
return;
408385
}
409386

410-
let active = domUtils.activeElement(this);
387+
let active = domUtils.activeElement(domUtils.ownerDocument(this));
411388
let modal = React.findDOMNode(this.refs.dialog);
412389

413390
if (modal && modal !== active && !domUtils.contains(modal, active)) {

src/index.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import deprecationWarning from './utils/deprecationWarning';
2+
13
export Accordion from './Accordion';
24
export Affix from './Affix';
35
export AffixMixin from './AffixMixin';
@@ -70,16 +72,36 @@ export Fade from './Collapse';
7072

7173
export * as FormControls from './FormControls';
7274

75+
import domUtils from './utils/domUtils';
7376
import childrenValueInputValidation from './utils/childrenValueInputValidation';
7477
import createChainedFunction from './utils/createChainedFunction';
75-
import domUtils from './utils/domUtils';
7678
import ValidComponentChildren from './utils/ValidComponentChildren';
7779
import CustomPropTypes from './utils/CustomPropTypes';
7880

7981
export const utils = {
8082
childrenValueInputValidation,
8183
createChainedFunction,
82-
domUtils,
8384
ValidComponentChildren,
84-
CustomPropTypes
85+
CustomPropTypes,
86+
domUtils: createDeprecationWrapper(domUtils, 'utils/domUtils', 'npm install dom-helpers'),
8587
};
88+
89+
function createDeprecationWrapper(obj, deprecated, instead, link){
90+
let wrapper = {};
91+
92+
if (process.env.NODE_ENV === 'production'){
93+
return obj;
94+
}
95+
96+
Object.keys(obj).forEach(key => {
97+
Object.defineProperty(wrapper, key, {
98+
get(){
99+
deprecationWarning(deprecated, instead, link);
100+
return obj[key];
101+
},
102+
set(x){ obj[key] = x; }
103+
});
104+
});
105+
106+
return wrapper;
107+
}

src/utils/domUtils.js

Lines changed: 17 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,33 @@
11
import React from 'react';
2+
import canUseDom from 'dom-helpers/util/inDOM';
23

4+
import getOwnerDocument from 'dom-helpers/ownerDocument';
5+
import getOwnerWindow from 'dom-helpers/ownerWindow';
36

4-
let canUseDom = !!(
5-
typeof window !== 'undefined' &&
6-
window.document &&
7-
window.document.createElement
8-
);
7+
import contains from 'dom-helpers/query/contains';
8+
import activeElement from 'dom-helpers/activeElement';
99

10+
import getOffset from 'dom-helpers/query/offset';
11+
import offsetParent from 'dom-helpers/query/offsetParent';
12+
import getPosition from 'dom-helpers/query/position';
13+
14+
import css from 'dom-helpers/style';
1015

11-
/**
12-
* Get elements owner document
13-
*
14-
* @param {ReactComponent|HTMLElement} componentOrElement
15-
* @returns {HTMLElement}
16-
*/
1716
function ownerDocument(componentOrElement) {
1817
let elem = React.findDOMNode(componentOrElement);
19-
return (elem && elem.ownerDocument) || document;
18+
return getOwnerDocument((elem && elem.ownerDocument) || document);
2019
}
2120

2221
function ownerWindow(componentOrElement) {
2322
let doc = ownerDocument(componentOrElement);
24-
return doc.defaultView
25-
? doc.defaultView
26-
: doc.parentWindow;
27-
}
28-
29-
/**
30-
* get the active element, safe in IE
31-
* @return {HTMLElement}
32-
*/
33-
function getActiveElement(componentOrElement){
34-
let doc = ownerDocument(componentOrElement);
35-
36-
try {
37-
return doc.activeElement || doc.body;
38-
} catch (e) {
39-
return doc.body;
40-
}
23+
return getOwnerWindow(doc);
4124
}
4225

43-
/**
44-
* Shortcut to compute element style
45-
*
46-
* @param {HTMLElement} elem
47-
* @returns {CssStyle}
48-
*/
26+
//TODO remove in 0.26
4927
function getComputedStyles(elem) {
5028
return ownerDocument(elem).defaultView.getComputedStyle(elem, null);
5129
}
5230

53-
/**
54-
* Get elements offset
55-
*
56-
* TODO: REMOVE JQUERY!
57-
*
58-
* @param {HTMLElement} DOMNode
59-
* @returns {{top: number, left: number}}
60-
*/
61-
function getOffset(DOMNode) {
62-
if (window.jQuery) {
63-
return window.jQuery(DOMNode).offset();
64-
}
65-
66-
let docElem = ownerDocument(DOMNode).documentElement;
67-
let box = { top: 0, left: 0 };
68-
69-
// If we don't have gBCR, just use 0,0 rather than error
70-
// BlackBerry 5, iOS 3 (original iPhone)
71-
if ( typeof DOMNode.getBoundingClientRect !== 'undefined' ) {
72-
box = DOMNode.getBoundingClientRect();
73-
}
74-
75-
return {
76-
top: box.top + window.pageYOffset - docElem.clientTop,
77-
left: box.left + window.pageXOffset - docElem.clientLeft
78-
};
79-
}
80-
81-
/**
82-
* Get elements position
83-
*
84-
* TODO: REMOVE JQUERY!
85-
*
86-
* @param {HTMLElement} elem
87-
* @param {HTMLElement?} offsetParent
88-
* @returns {{top: number, left: number}}
89-
*/
90-
function getPosition(elem, offsetParent) {
91-
let offset,
92-
parentOffset;
93-
94-
if (window.jQuery) {
95-
if (!offsetParent) {
96-
return window.jQuery(elem).position();
97-
}
98-
99-
offset = window.jQuery(elem).offset();
100-
parentOffset = window.jQuery(offsetParent).offset();
101-
102-
// Get element offset relative to offsetParent
103-
return {
104-
top: offset.top - parentOffset.top,
105-
left: offset.left - parentOffset.left
106-
};
107-
}
108-
109-
parentOffset = {top: 0, left: 0};
110-
111-
// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
112-
if (getComputedStyles(elem).position === 'fixed' ) {
113-
// We assume that getBoundingClientRect is available when computed position is fixed
114-
offset = elem.getBoundingClientRect();
115-
116-
} else {
117-
if (!offsetParent) {
118-
// Get *real* offsetParent
119-
offsetParent = offsetParentFunc(elem);
120-
}
121-
122-
// Get correct offsets
123-
offset = getOffset(elem);
124-
if ( offsetParent.nodeName !== 'HTML') {
125-
parentOffset = getOffset(offsetParent);
126-
}
127-
128-
// Add offsetParent borders
129-
parentOffset.top += parseInt(getComputedStyles(offsetParent).borderTopWidth, 10);
130-
parentOffset.left += parseInt(getComputedStyles(offsetParent).borderLeftWidth, 10);
131-
}
132-
133-
// Subtract parent offsets and element margins
134-
return {
135-
top: offset.top - parentOffset.top - parseInt(getComputedStyles(elem).marginTop, 10),
136-
left: offset.left - parentOffset.left - parseInt(getComputedStyles(elem).marginLeft, 10)
137-
};
138-
}
139-
14031
/**
14132
* Get an element's size
14233
*
@@ -156,57 +47,16 @@ function getSize(elem) {
15647
return rect;
15748
}
15849

159-
/**
160-
* Get parent element
161-
*
162-
* @param {HTMLElement?} elem
163-
* @returns {HTMLElement}
164-
*/
165-
function offsetParentFunc(elem) {
166-
let docElem = ownerDocument(elem).documentElement;
167-
let offsetParent = elem.offsetParent || docElem;
168-
169-
while ( offsetParent && ( offsetParent.nodeName !== 'HTML' &&
170-
getComputedStyles(offsetParent).position === 'static' ) ) {
171-
offsetParent = offsetParent.offsetParent;
172-
}
173-
174-
return offsetParent || docElem;
175-
}
176-
177-
/**
178-
* Cross browser .contains() polyfill
179-
* @param {HTMLElement} elem
180-
* @param {HTMLElement} inner
181-
* @return {bool}
182-
*/
183-
function contains(elem, inner){
184-
function ie8Contains(root, node) {
185-
while (node) {
186-
if (node === root) {
187-
return true;
188-
}
189-
node = node.parentNode;
190-
}
191-
return false;
192-
}
193-
194-
return (elem && elem.contains)
195-
? elem.contains(inner)
196-
: (elem && elem.compareDocumentPosition)
197-
? elem === inner || !!(elem.compareDocumentPosition(inner) & 16)
198-
: ie8Contains(elem, inner);
199-
}
200-
20150
export default {
20251
canUseDom,
52+
css,
53+
getComputedStyles,
20354
contains,
20455
ownerWindow,
20556
ownerDocument,
206-
getComputedStyles,
20757
getOffset,
20858
getPosition,
20959
getSize,
210-
activeElement: getActiveElement,
211-
offsetParent: offsetParentFunc
60+
activeElement,
61+
offsetParent
21262
};

0 commit comments

Comments
 (0)