v-react-pivottable/node_modules/react-draggable/lib/utils/domFns.js

201 lines
7.3 KiB
JavaScript
Raw Permalink Normal View History

2024-12-16 20:19:32 -06:00
// @flow
import {findInArray, isFunction, int} from './shims';
import browserPrefix, {browserPrefixToKey} from './getPrefix';
import type {ControlPosition, PositionOffsetControlPosition, MouseTouchEvent} from './types';
let matchesSelectorFunc = '';
export function matchesSelector(el: Node, selector: string): boolean {
if (!matchesSelectorFunc) {
matchesSelectorFunc = findInArray([
'matches',
'webkitMatchesSelector',
'mozMatchesSelector',
'msMatchesSelector',
'oMatchesSelector'
], function(method){
// $FlowIgnore: Doesn't think elements are indexable
return isFunction(el[method]);
});
}
// Might not be found entirely (not an Element?) - in that case, bail
// $FlowIgnore: Doesn't think elements are indexable
if (!isFunction(el[matchesSelectorFunc])) return false;
// $FlowIgnore: Doesn't think elements are indexable
return el[matchesSelectorFunc](selector);
}
// Works up the tree to the draggable itself attempting to match selector.
export function matchesSelectorAndParentsTo(el: Node, selector: string, baseNode: Node): boolean {
let node = el;
do {
if (matchesSelector(node, selector)) return true;
if (node === baseNode) return false;
node = node.parentNode;
} while (node);
return false;
}
export function addEvent(el: ?Node, event: string, handler: Function): void {
if (!el) { return; }
if (el.attachEvent) {
el.attachEvent('on' + event, handler);
} else if (el.addEventListener) {
el.addEventListener(event, handler, true);
} else {
// $FlowIgnore: Doesn't think elements are indexable
el['on' + event] = handler;
}
}
export function removeEvent(el: ?Node, event: string, handler: Function): void {
if (!el) { return; }
if (el.detachEvent) {
el.detachEvent('on' + event, handler);
} else if (el.removeEventListener) {
el.removeEventListener(event, handler, true);
} else {
// $FlowIgnore: Doesn't think elements are indexable
el['on' + event] = null;
}
}
export function outerHeight(node: HTMLElement): number {
// This is deliberately excluding margin for our calculations, since we are using
// offsetTop which is including margin. See getBoundPosition
let height = node.clientHeight;
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
height += int(computedStyle.borderTopWidth);
height += int(computedStyle.borderBottomWidth);
return height;
}
export function outerWidth(node: HTMLElement): number {
// This is deliberately excluding margin for our calculations, since we are using
// offsetLeft which is including margin. See getBoundPosition
let width = node.clientWidth;
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
width += int(computedStyle.borderLeftWidth);
width += int(computedStyle.borderRightWidth);
return width;
}
export function innerHeight(node: HTMLElement): number {
let height = node.clientHeight;
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
height -= int(computedStyle.paddingTop);
height -= int(computedStyle.paddingBottom);
return height;
}
export function innerWidth(node: HTMLElement): number {
let width = node.clientWidth;
const computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
width -= int(computedStyle.paddingLeft);
width -= int(computedStyle.paddingRight);
return width;
}
// Get from offsetParent
export function offsetXYFromParent(evt: {clientX: number, clientY: number}, offsetParent: HTMLElement): ControlPosition {
const isBody = offsetParent === offsetParent.ownerDocument.body;
const offsetParentRect = isBody ? {left: 0, top: 0} : offsetParent.getBoundingClientRect();
const x = evt.clientX + offsetParent.scrollLeft - offsetParentRect.left;
const y = evt.clientY + offsetParent.scrollTop - offsetParentRect.top;
return {x, y};
}
export function createCSSTransform(controlPos: ControlPosition, positionOffset: PositionOffsetControlPosition): Object {
const translation = getTranslation(controlPos, positionOffset, 'px');
return {[browserPrefixToKey('transform', browserPrefix)]: translation };
}
export function createSVGTransform(controlPos: ControlPosition, positionOffset: PositionOffsetControlPosition): string {
const translation = getTranslation(controlPos, positionOffset, '');
return translation;
}
export function getTranslation({x, y}: ControlPosition, positionOffset: PositionOffsetControlPosition, unitSuffix: string): string {
let translation = `translate(${x}${unitSuffix},${y}${unitSuffix})`;
if (positionOffset) {
const defaultX = `${(typeof positionOffset.x === 'string') ? positionOffset.x : positionOffset.x + unitSuffix}`;
const defaultY = `${(typeof positionOffset.y === 'string') ? positionOffset.y : positionOffset.y + unitSuffix}`;
translation = `translate(${defaultX}, ${defaultY})` + translation;
}
return translation;
}
export function getTouch(e: MouseTouchEvent, identifier: number): ?{clientX: number, clientY: number} {
return (e.targetTouches && findInArray(e.targetTouches, t => identifier === t.identifier)) ||
(e.changedTouches && findInArray(e.changedTouches, t => identifier === t.identifier));
}
export function getTouchIdentifier(e: MouseTouchEvent): ?number {
if (e.targetTouches && e.targetTouches[0]) return e.targetTouches[0].identifier;
if (e.changedTouches && e.changedTouches[0]) return e.changedTouches[0].identifier;
}
// User-select Hacks:
//
// Useful for preventing blue highlights all over everything when dragging.
// Note we're passing `document` b/c we could be iframed
export function addUserSelectStyles(doc: ?Document) {
if (!doc) return;
let styleEl = doc.getElementById('react-draggable-style-el');
if (!styleEl) {
styleEl = doc.createElement('style');
styleEl.type = 'text/css';
styleEl.id = 'react-draggable-style-el';
styleEl.innerHTML = '.react-draggable-transparent-selection *::-moz-selection {all: inherit;}\n';
styleEl.innerHTML += '.react-draggable-transparent-selection *::selection {all: inherit;}\n';
doc.getElementsByTagName('head')[0].appendChild(styleEl);
}
if (doc.body) addClassName(doc.body, 'react-draggable-transparent-selection');
}
export function removeUserSelectStyles(doc: ?Document) {
try {
if (doc && doc.body) removeClassName(doc.body, 'react-draggable-transparent-selection');
// $FlowIgnore: IE
if (doc.selection) {
// $FlowIgnore: IE
doc.selection.empty();
} else {
window.getSelection().removeAllRanges(); // remove selection caused by scroll
}
} catch (e) {
// probably IE
}
}
export function styleHacks(childStyle: Object = {}): Object {
// Workaround IE pointer events; see #51
// https://github.com/mzabriskie/react-draggable/issues/51#issuecomment-103488278
return {
touchAction: 'none',
...childStyle
};
}
export function addClassName(el: HTMLElement, className: string) {
if (el.classList) {
el.classList.add(className);
} else {
if (!el.className.match(new RegExp(`(?:^|\\s)${className}(?!\\S)`))) {
el.className += ` ${className}`;
}
}
}
export function removeClassName(el: HTMLElement, className: string) {
if (el.classList) {
el.classList.remove(className);
} else {
el.className = el.className.replace(new RegExp(`(?:^|\\s)${className}(?!\\S)`, 'g'), '');
}
}