Skip to content

Commit ef126bc

Browse files
acustiSTRML
authored andcommitted
Use window/document relative to DOM element
Use the ownerDocument and window of the DOM element being manipulated rather than the global window and document objects. This makes react-draggable work with a tool like https://github.com/ryanseddon/react-frame-component
1 parent 003e1a4 commit ef126bc

File tree

3 files changed

+39
-32
lines changed

3 files changed

+39
-32
lines changed

lib/DraggableCore.es6

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,12 @@ export default class DraggableCore extends React.Component {
182182
componentWillUnmount() {
183183
// Remove any leftover event handlers. Remove both touch and mouse handlers in case
184184
// some browser quirk caused a touch event to fire during a mouse move, or vice versa.
185-
removeEvent(document, eventsFor.mouse.move, this.handleDrag);
186-
removeEvent(document, eventsFor.touch.move, this.handleDrag);
187-
removeEvent(document, eventsFor.mouse.stop, this.handleDragStop);
188-
removeEvent(document, eventsFor.touch.stop, this.handleDragStop);
189-
if (this.props.enableUserSelectHack) removeUserSelectStyles();
185+
const {ownerDocument} = ReactDOM.findDOMNode(this);
186+
removeEvent(ownerDocument, eventsFor.mouse.move, this.handleDrag);
187+
removeEvent(ownerDocument, eventsFor.touch.move, this.handleDrag);
188+
removeEvent(ownerDocument, eventsFor.mouse.stop, this.handleDragStop);
189+
removeEvent(ownerDocument, eventsFor.touch.stop, this.handleDragStop);
190+
if (this.props.enableUserSelectHack) removeUserSelectStyles(ownerDocument.body);
190191
}
191192

192193
handleDragStart: EventHandler<MouseEvent> = (e) => {
@@ -196,11 +197,15 @@ export default class DraggableCore extends React.Component {
196197
// Only accept left-clicks.
197198
if (!this.props.allowAnyClick && typeof e.button === 'number' && e.button !== 0) return false;
198199

200+
// Get nodes. Be sure to grab relative document (could be iframed)
201+
const domNode = ReactDOM.findDOMNode(this);
202+
const {ownerDocument} = domNode;
203+
199204
// Short circuit if handle or cancel prop was provided and selector doesn't match.
200205
if (this.props.disabled ||
201-
(!(e.target instanceof Node)) ||
202-
(this.props.handle && !matchesSelectorAndParentsTo(e.target, this.props.handle, ReactDOM.findDOMNode(this))) ||
203-
(this.props.cancel && matchesSelectorAndParentsTo(e.target, this.props.cancel, ReactDOM.findDOMNode(this)))) {
206+
(!(e.target instanceof ownerDocument.defaultView.Node)) ||
207+
(this.props.handle && !matchesSelectorAndParentsTo(e.target, this.props.handle, domNode)) ||
208+
(this.props.cancel && matchesSelectorAndParentsTo(e.target, this.props.cancel, domNode))) {
204209
return;
205210
}
206211

@@ -227,7 +232,7 @@ export default class DraggableCore extends React.Component {
227232

228233
// Add a style to the body to disable user-select. This prevents text from
229234
// being selected all over the page.
230-
if (this.props.enableUserSelectHack) addUserSelectStyles();
235+
if (this.props.enableUserSelectHack) addUserSelectStyles(ownerDocument.body);
231236

232237
// Initiate dragging. Set the current x and y as offsets
233238
// so we know how much we've moved during the drag. This allows us
@@ -242,8 +247,8 @@ export default class DraggableCore extends React.Component {
242247
// Add events to the document directly so we catch when the user's mouse/touch moves outside of
243248
// this element. We use different events depending on whether or not we have detected that this
244249
// is a touch-capable device.
245-
addEvent(document, dragEventFor.move, this.handleDrag);
246-
addEvent(document, dragEventFor.stop, this.handleDragStop);
250+
addEvent(ownerDocument, dragEventFor.move, this.handleDrag);
251+
addEvent(ownerDocument, dragEventFor.stop, this.handleDragStop);
247252
};
248253

249254
handleDrag: EventHandler<MouseEvent> = (e) => {
@@ -298,7 +303,7 @@ export default class DraggableCore extends React.Component {
298303
const coreEvent = createCoreData(this, x, y);
299304

300305
// Remove user-select hack
301-
if (this.props.enableUserSelectHack) removeUserSelectStyles();
306+
if (this.props.enableUserSelectHack) removeUserSelectStyles(ReactDOM.findDOMNode(this).ownerDocument.body);
302307

303308
log('DraggableCore: handleDragStop: %j', coreEvent);
304309

@@ -313,9 +318,10 @@ export default class DraggableCore extends React.Component {
313318
this.props.onStop(e, coreEvent);
314319

315320
// Remove event handlers
321+
const {ownerDocument} = ReactDOM.findDOMNode(this);
316322
log('DraggableCore: Removing handlers');
317-
removeEvent(document, dragEventFor.move, this.handleDrag);
318-
removeEvent(document, dragEventFor.stop, this.handleDragStop);
323+
removeEvent(ownerDocument, dragEventFor.move, this.handleDrag);
324+
removeEvent(ownerDocument, dragEventFor.stop, this.handleDragStop);
319325
};
320326

321327
onMouseDown: EventHandler<MouseEvent> = (e) => {

lib/utils/domFns.es6

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function outerHeight(node: HTMLElement): number {
6363
// This is deliberately excluding margin for our calculations, since we are using
6464
// offsetTop which is including margin. See getBoundPosition
6565
let height = node.clientHeight;
66-
const computedStyle = window.getComputedStyle(node);
66+
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
6767
height += int(computedStyle.borderTopWidth);
6868
height += int(computedStyle.borderBottomWidth);
6969
return height;
@@ -73,30 +73,29 @@ export function outerWidth(node: HTMLElement): number {
7373
// This is deliberately excluding margin for our calculations, since we are using
7474
// offsetLeft which is including margin. See getBoundPosition
7575
let width = node.clientWidth;
76-
const computedStyle = window.getComputedStyle(node);
76+
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
7777
width += int(computedStyle.borderLeftWidth);
7878
width += int(computedStyle.borderRightWidth);
7979
return width;
8080
}
8181
export function innerHeight(node: HTMLElement): number {
8282
let height = node.clientHeight;
83-
const computedStyle = window.getComputedStyle(node);
83+
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
8484
height -= int(computedStyle.paddingTop);
8585
height -= int(computedStyle.paddingBottom);
8686
return height;
8787
}
8888

8989
export function innerWidth(node: HTMLElement): number {
9090
let width = node.clientWidth;
91-
const computedStyle = window.getComputedStyle(node);
91+
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
9292
width -= int(computedStyle.paddingLeft);
9393
width -= int(computedStyle.paddingRight);
9494
return width;
9595
}
9696

9797
// Get from offsetParent
98-
export function offsetXYFromParent(evt: {clientX: number, clientY: number}, offsetParent: ?HTMLElement): ControlPosition {
99-
if (!offsetParent) offsetParent = document.body;
98+
export function offsetXYFromParent(evt: {clientX: number, clientY: number}, offsetParent: HTMLElement): ControlPosition {
10099
const isBody = offsetParent === offsetParent.ownerDocument.body;
101100
const offsetParentRect = isBody ? {left: 0, top: 0} : offsetParent.getBoundingClientRect();
102101

@@ -132,14 +131,15 @@ const userSelectPrefix = getPrefix('user-select');
132131
const userSelect = browserPrefixToStyle('user-select', userSelectPrefix);
133132
const userSelectStyle = `;${userSelect}: none;`;
134133

135-
export function addUserSelectStyles() {
136-
const style = document.body.getAttribute('style') || '';
137-
document.body.setAttribute('style', style + userSelectStyle);
134+
// Note we're passing `document` b/c we could be iframed
135+
export function addUserSelectStyles(body: HTMLElement) {
136+
const style = body.getAttribute('style') || '';
137+
body.setAttribute('style', style + userSelectStyle);
138138
}
139139

140-
export function removeUserSelectStyles() {
141-
const style = document.body.getAttribute('style') || '';
142-
document.body.setAttribute('style', style.replace(userSelectStyle, ''));
140+
export function removeUserSelectStyles(body: HTMLElement) {
141+
const style = body.getAttribute('style') || '';
142+
body.setAttribute('style', style.replace(userSelectStyle, ''));
143143
}
144144

145145
export function styleHacks(childStyle: Object = {}): Object {

lib/utils/positionFns.es6

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ export function getBoundPosition(draggable: Draggable, x: number, y: number): [n
1717
const node = ReactDOM.findDOMNode(draggable);
1818

1919
if (typeof bounds === 'string') {
20+
const {currentDocument} = node;
21+
const currentWindow = node.defaultView;
2022
let boundNode;
2123
if (bounds === 'parent') {
2224
boundNode = node.parentNode;
2325
} else {
24-
boundNode = document.querySelector(bounds);
26+
boundNode = currentDocument.querySelector(bounds);
2527
if (!boundNode) throw new Error('Bounds selector "' + bounds + '" could not find an element.');
2628
}
27-
const nodeStyle = window.getComputedStyle(node);
28-
const boundNodeStyle = window.getComputedStyle(boundNode);
29+
const nodeStyle = currentWindow.getComputedStyle(node);
30+
const boundNodeStyle = currentWindow.getComputedStyle(boundNode);
2931
// Compute bounds. This is a pain with padding and offsets but this gets it exactly right.
3032
bounds = {
3133
left: -node.offsetLeft + int(boundNodeStyle.paddingLeft) +
@@ -66,10 +68,9 @@ export function canDragY(draggable: Draggable): boolean {
6668
export function getControlPosition(e: MouseEvent, touchIdentifier: ?number, draggableCore: DraggableCore): ?ControlPosition {
6769
const touchObj = typeof touchIdentifier === 'number' ? getTouch(e, touchIdentifier) : null;
6870
if (typeof touchIdentifier === 'number' && !touchObj) return null; // not the right touch
71+
const node = ReactDOM.findDOMNode(draggableCore);
6972
// User can provide an offsetParent if desired.
70-
const offsetParent = draggableCore.props.offsetParent ||
71-
ReactDOM.findDOMNode(draggableCore).offsetParent ||
72-
document.body;
73+
const offsetParent = draggableCore.props.offsetParent || node.offsetParent || node.ownerDocument.body;
7374
return offsetXYFromParent(touchObj || e, offsetParent);
7475
}
7576

0 commit comments

Comments
 (0)