"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.proxyMouse = proxyMouse; exports.clone = clone; // import 'babelify/polyfill'; // needed for Object.assign exports.default = { proxyMouse: proxyMouse }; /** * Start proxying all mouse events that occur on the target node to each node in * a set of tracked nodes. * * The items in tracked do not strictly have to be DOM Nodes, but they do have * to have dispatchEvent, getBoundingClientRect, and getClientRects methods. * * @param target {Node} The node on which to listen for mouse events. * @param tracked {Node[]} A (possibly mutable) array of nodes to which to proxy * events. */ function proxyMouse(target, tracked) { function dispatch(e) { // We walk through the set of tracked elements in reverse order so that // events are sent to those most recently added first. // // This is the least surprising behaviour as it simulates the way the // browser would work if items added later were drawn "on top of" // earlier ones. for (var i = tracked.length - 1; i >= 0; i--) { var t = tracked[i]; var x = e.clientX; var y = e.clientY; if (e.touches && e.touches.length) { x = e.touches[0].clientX; y = e.touches[0].clientY; } if (!contains(t, target, x, y)) { continue; } // The event targets this mark, so dispatch a cloned event: t.dispatchEvent(clone(e)); // We only dispatch the cloned event to the first matching mark. break; } } if (target.nodeName === "iframe" || target.nodeName === "IFRAME") { try { // Try to get the contents if same domain this.target = target.contentDocument; } catch (err) { this.target = target; } } else { this.target = target; } var _arr = ['mouseup', 'mousedown', 'click', 'touchstart']; for (var _i = 0; _i < _arr.length; _i++) { var ev = _arr[_i]; this.target.addEventListener(ev, function (e) { return dispatch(e); }, false); } } /** * Clone a mouse event object. * * @param e {MouseEvent} A mouse event object to clone. * @returns {MouseEvent} */ function clone(e) { var opts = Object.assign({}, e, { bubbles: false }); try { return new MouseEvent(e.type, opts); } catch (err) { // compat: webkit var copy = document.createEvent('MouseEvents'); copy.initMouseEvent(e.type, false, opts.cancelable, opts.view, opts.detail, opts.screenX, opts.screenY, opts.clientX, opts.clientY, opts.ctrlKey, opts.altKey, opts.shiftKey, opts.metaKey, opts.button, opts.relatedTarget); return copy; } } /** * Check if the item contains the point denoted by the passed coordinates * @param item {Object} An object with getBoundingClientRect and getClientRects * methods. * @param x {Number} * @param y {Number} * @returns {Boolean} */ function contains(item, target, x, y) { // offset var offset = target.getBoundingClientRect(); function rectContains(r, x, y) { var top = r.top - offset.top; var left = r.left - offset.left; var bottom = top + r.height; var right = left + r.width; return top <= y && left <= x && bottom > y && right > x; } // Check overall bounding box first var rect = item.getBoundingClientRect(); if (!rectContains(rect, x, y)) { return false; } // Then continue to check each child rect var rects = item.getClientRects(); for (var i = 0, len = rects.length; i < len; i++) { if (rectContains(rects[i], x, y)) { return true; } } return false; }