react-fastclick
Advanced tools
+1
| 6.9.4 |
Sorry, the diff of this file is not supported yet
| machine: | ||
| node: | ||
| version: 6.9.4 | ||
| general: | ||
| branches: | ||
| ignore: | ||
| - gh-pages |
+267
| 'use strict'; | ||
| (function () { | ||
| var getReactFCInitializer = function (React) { | ||
| return function initializeReactFastclick () { | ||
| var originalCreateElement = React.createElement; | ||
| // Moved if Math.abs(downX - upX) > MOVE_THRESHOLD; | ||
| var MOVE_THRESHOLD = 8; | ||
| var TOUCH_DELAY = 1000; | ||
| var touchKeysToStore = [ | ||
| 'clientX', | ||
| 'clientY', | ||
| 'pageX', | ||
| 'pageY', | ||
| 'screenX', | ||
| 'screenY', | ||
| 'radiusX', | ||
| 'radiusY' | ||
| ]; | ||
| var touchEvents = { | ||
| downPos: {}, | ||
| lastPos: {} | ||
| }; | ||
| var isDisabled = function (element) { | ||
| if (!element) { | ||
| return false; | ||
| } | ||
| var disabled = element.getAttribute('disabled'); | ||
| return disabled !== false && disabled !== null; | ||
| }; | ||
| var focus = function (event, target) { | ||
| var myTarget = target || event.currentTarget; | ||
| if (!myTarget || isDisabled(myTarget)) { | ||
| return; | ||
| } | ||
| myTarget.focus(); | ||
| }; | ||
| var handleType = { | ||
| input: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| textarea: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| select: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| label: function (event) { | ||
| var input; | ||
| var forTarget = event.currentTarget.getAttribute('for'); | ||
| if (forTarget) { | ||
| input = document.getElementById(forTarget); | ||
| } else { | ||
| input = event.currentTarget.querySelectorAll('input, textarea, select')[0]; | ||
| } | ||
| if (input) { | ||
| focus(event, input); | ||
| } | ||
| } | ||
| }; | ||
| var fakeClickEvent = function (event) { | ||
| if (typeof event.persist === 'function') { | ||
| event.persist(); | ||
| } | ||
| event.fastclick = true; | ||
| event.type = 'click'; | ||
| event.button = 0; | ||
| }; | ||
| var copyTouchKeys = function (touch, target) { | ||
| if (typeof target.persist === 'function') { | ||
| target.persist(); | ||
| } | ||
| if (touch) { | ||
| for (var i = 0; i < touchKeysToStore.length; i += 1) { | ||
| var key = touchKeysToStore[i]; | ||
| target[key] = touch[key]; | ||
| } | ||
| } | ||
| }; | ||
| var noTouchHappened = function () { | ||
| return !touchEvents.touched && ( | ||
| !touchEvents.lastTouchDate || new Date().getTime() > touchEvents.lastTouchDate + TOUCH_DELAY | ||
| ); | ||
| }; | ||
| var invalidateIfMoreThanOneTouch = function (event) { | ||
| touchEvents.invalid = event.touches && event.touches.length > 1 || touchEvents.invalid; | ||
| }; | ||
| var onMouseEvent = function (callback, event) { | ||
| // Prevent any mouse events if we touched recently | ||
| if (typeof callback === 'function' && noTouchHappened()) { | ||
| callback(event); | ||
| } | ||
| if (event.type === 'click') { | ||
| touchEvents.invalid = false; | ||
| touchEvents.touched = false; | ||
| touchEvents.moved = false; | ||
| } | ||
| }; | ||
| var onTouchStart = function (callback, event) { | ||
| touchEvents.invalid = false; | ||
| touchEvents.moved = false; | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| copyTouchKeys(event.touches[0], touchEvents.downPos); | ||
| copyTouchKeys(event.touches[0], touchEvents.lastPos); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| }; | ||
| var onTouchMove = function (callback, event) { | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| copyTouchKeys(event.touches[0], touchEvents.lastPos); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (Math.abs(touchEvents.downPos.clientX - touchEvents.lastPos.clientX) > MOVE_THRESHOLD || | ||
| Math.abs(touchEvents.downPos.clientY - touchEvents.lastPos.clientY) > MOVE_THRESHOLD) { | ||
| touchEvents.moved = true; | ||
| } | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| }; | ||
| var onTouchEnd = function (callback, onClick, type, event) { | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| if (!touchEvents.invalid && !touchEvents.moved) { | ||
| var box = event.currentTarget.getBoundingClientRect(); | ||
| if (touchEvents.lastPos.clientX - (touchEvents.lastPos.radiusX || 0) <= box.right && | ||
| touchEvents.lastPos.clientX + (touchEvents.lastPos.radiusX || 0) >= box.left && | ||
| touchEvents.lastPos.clientY - (touchEvents.lastPos.radiusY || 0) <= box.bottom && | ||
| touchEvents.lastPos.clientY + (touchEvents.lastPos.radiusY || 0) >= box.top) { | ||
| if (!isDisabled(event.currentTarget)) { | ||
| if (typeof onClick === 'function') { | ||
| copyTouchKeys(touchEvents.lastPos, event); | ||
| fakeClickEvent(event); | ||
| onClick(event); | ||
| } | ||
| if (!event.defaultPrevented && handleType[type]) { | ||
| handleType[type](event); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| var propsWithFastclickEvents = function (type, props) { | ||
| var newProps = {}; | ||
| // Loop over props | ||
| for (var key in props) { | ||
| // Copy props to newProps | ||
| newProps[key] = props[key]; | ||
| } | ||
| // Apply our wrapped mouse and touch handlers | ||
| newProps.onClick = onMouseEvent.bind(null, props.onClick); | ||
| newProps.onMouseDown = onMouseEvent.bind(null, props.onMouseDown); | ||
| newProps.onMouseMove = onMouseEvent.bind(null, props.onMouseMove); | ||
| newProps.onMouseUp = onMouseEvent.bind(null, props.onMouseUp); | ||
| newProps.onTouchStart = onTouchStart.bind(null, props.onTouchStart); | ||
| newProps.onTouchMove = onTouchMove.bind(null, props.onTouchMove); | ||
| newProps.onTouchEnd = onTouchEnd.bind(null, props.onTouchEnd, props.onClick, type); | ||
| if (typeof Object.freeze === 'function') { | ||
| Object.freeze(newProps); | ||
| } | ||
| return newProps; | ||
| }; | ||
| React.createElement = function () { | ||
| // Convert arguments to array | ||
| var args = Array.prototype.slice.call(arguments); | ||
| var type = args[0]; | ||
| var props = args[1]; | ||
| // Check if basic element & has onClick prop | ||
| if (type && typeof type === 'string' && ( | ||
| (props && typeof props.onClick === 'function') || handleType[type] | ||
| )) { | ||
| // Add our own events to props | ||
| args[1] = propsWithFastclickEvents(type, props || {}); | ||
| } | ||
| // Apply args to original createElement function | ||
| return originalCreateElement.apply(null, args); | ||
| }; | ||
| if (typeof React.DOM === 'object') { | ||
| for (var key in React.DOM) { | ||
| React.DOM[key] = React.createElement.bind(null, key); | ||
| } | ||
| } | ||
| }; | ||
| }; | ||
| /* istanbul ignore next */ | ||
| // Export for commonjs / browserify | ||
| if (typeof exports === 'object' && typeof module !== 'undefined') { | ||
| var React = require('react'); | ||
| module.exports = getReactFCInitializer(React); | ||
| // Export for amd / require | ||
| } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef | ||
| define(['react'], function (ReactAMD) { // eslint-disable-line no-undef | ||
| return getReactFCInitializer(ReactAMD); | ||
| }); | ||
| // Export globally | ||
| } else { | ||
| var root; | ||
| if (typeof window !== 'undefined') { | ||
| root = window; | ||
| } else if (typeof global !== 'undefined') { | ||
| root = global; | ||
| } else if (typeof self !== 'undefined') { | ||
| root = self; | ||
| } else { | ||
| root = this; | ||
| } | ||
| root.Reorder = getReactFCInitializer(root.React); | ||
| } | ||
| })(); |
| 'use strict'; | ||
| var expect = require('chai').expect; | ||
| var sinon = require('sinon'); | ||
| var spy = sinon.spy; | ||
| var stub = sinon.stub; | ||
| var TestUtils = require('react-addons-test-utils'); | ||
| var renderIntoApp = require('./helpers/render-into-app'); | ||
| describe('react-fastclick', function () { | ||
| var originalCreateElement, fastclickCreateElement; | ||
| function handlerKeyToSimulatedEventKey (key) { | ||
| var simulatedEventKey = key.replace(/^on/, ''); | ||
| return simulatedEventKey.charAt(0).toLowerCase() + simulatedEventKey.substring(1); | ||
| } | ||
| function getBoundingClientRect () { | ||
| return { | ||
| top: 25, | ||
| left: 25, | ||
| right: 75, | ||
| bottom: 75, | ||
| width: 50, | ||
| height: 50 | ||
| }; | ||
| } | ||
| var touches = [ | ||
| { | ||
| clientX: 50, | ||
| clientY: 50 | ||
| } | ||
| ]; | ||
| var specialTypes = [ | ||
| 'input', | ||
| 'textarea', | ||
| 'select', | ||
| 'label' | ||
| ]; | ||
| var additionalProps = { | ||
| onClick: function () {}, | ||
| onMouseDown: function () {}, | ||
| onMouseMove: function () {}, | ||
| onMouseUp: function () {}, | ||
| onTouchStart: function () {}, | ||
| onTouchMove: function () {}, | ||
| onTouchEnd: function () {} | ||
| }; | ||
| beforeEach(function () { | ||
| // Clear module cache | ||
| delete require.cache[require.resolve('react')]; | ||
| delete require.cache[require.resolve('../src/index')]; | ||
| }); | ||
| it('should redefine React.createElement', function () { | ||
| originalCreateElement = require('react').createElement; | ||
| var theSameCreateElement = require('react').createElement; | ||
| expect(originalCreateElement).to.equal(theSameCreateElement); | ||
| require('../src/index')(); | ||
| fastclickCreateElement = require('react').createElement; | ||
| expect(originalCreateElement).not.to.equal(fastclickCreateElement); | ||
| }); | ||
| describe('createElement', function () { | ||
| it('should create a regular React element', function () { | ||
| var element = fastclickCreateElement('div'); | ||
| expect(element).to.exist; | ||
| expect(element.ref).to.be.null; | ||
| expect(element.key).to.be.null; | ||
| expect(element.type).to.equal('div'); | ||
| expect(element.props).to.eql({}); | ||
| }); | ||
| it('should add events if it is a special element', function () { | ||
| var element; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| element = fastclickCreateElement(specialTypes[i]); | ||
| for (var key in additionalProps) { | ||
| expect(typeof element.props[key]).to.equal('function'); | ||
| } | ||
| } | ||
| }); | ||
| it('should add events if it has an onClick handler', function () { | ||
| var element = fastclickCreateElement('div', {onClick: function () {}}); | ||
| for (var key in additionalProps) { | ||
| expect(typeof element.props[key]).to.equal('function'); | ||
| } | ||
| }); | ||
| }); | ||
| describe('mouse events', function () { | ||
| it('should trigger standard mouse event handlers', function () { | ||
| var props = { | ||
| onMouseDown: spy(), | ||
| onMouseMove: spy(), | ||
| onMouseUp: spy(), | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| for (var key in props) { | ||
| var mouseEvent = handlerKeyToSimulatedEventKey(key); | ||
| TestUtils.Simulate[mouseEvent](node); | ||
| expect(props[key]).to.have.been.calledOnce; | ||
| } | ||
| }); | ||
| }); | ||
| describe('touch events', function () { | ||
| it('should trigger standard touch event handlers', function () { | ||
| var props = { | ||
| onClick: function () {}, | ||
| onTouchStart: spy(), | ||
| onTouchMove: spy(), | ||
| onTouchEnd: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| for (var key in props) { | ||
| if (key !== 'onClick') { | ||
| var touchEvent = handlerKeyToSimulatedEventKey(key); | ||
| TestUtils.Simulate[touchEvent](node, {touches: [{}]}); | ||
| expect(props[key]).to.have.been.calledOnce; | ||
| } | ||
| } | ||
| }); | ||
| it('should trigger the click handler when a fastclick happens', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if multiple touches', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: [touches[0], touches[0]] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if touch moves', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchMove( | ||
| node, | ||
| { | ||
| type: 'touchmove', | ||
| touches: [ | ||
| { | ||
| clientX: 60, | ||
| clientY: 50 | ||
| } | ||
| ] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if touch is outside of the element', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: [ | ||
| { | ||
| clientX: 80, | ||
| clientY: 80 | ||
| } | ||
| ] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| describe('special elements', function () { | ||
| it('should focus inputs, selects, and textareas when a fastclick is triggered', function () { | ||
| var node, getBoundingClientRectStub, focusSpy; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| var type = specialTypes[i]; | ||
| if (type !== 'label') { | ||
| node = renderIntoApp(fastclickCreateElement(type)); | ||
| getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| focusSpy = spy(node, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| } | ||
| } | ||
| }); | ||
| it('should not focus inputs, selects, and textareas if they are disabled', function () { | ||
| var node, getBoundingClientRectStub, focusSpy; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| var type = specialTypes[i]; | ||
| if (type !== 'label') { | ||
| node = renderIntoApp(fastclickCreateElement(type, {disabled: true})); | ||
| getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| focusSpy = spy(node, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| } | ||
| } | ||
| }); | ||
| it('should focus an input inside a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement('label', null, fastclickCreateElement('input')) | ||
| ); | ||
| var label = node; | ||
| var input = label.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should not focus a disabled input inside a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement('label', null, fastclickCreateElement('input', {disabled: true})) | ||
| ); | ||
| var label = node; | ||
| var input = label.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should focus an input for a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement( | ||
| 'div', | ||
| null, | ||
| fastclickCreateElement('label', {htmlFor: 'my-input'}), | ||
| fastclickCreateElement('input', {id: 'my-input'}) | ||
| ) | ||
| ); | ||
| var label = node.getElementsByTagName('label')[0]; | ||
| var input = node.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should not focus a disabled input for a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement( | ||
| 'div', | ||
| null, | ||
| fastclickCreateElement('label', {htmlFor: 'my-input'}), | ||
| fastclickCreateElement('input', {id: 'my-input', disabled: true}) | ||
| ) | ||
| ); | ||
| var label = node.getElementsByTagName('label')[0]; | ||
| var input = node.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should gracefully handle no input inside a label', function () { | ||
| var node = renderIntoApp(fastclickCreateElement('label')); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should gracefully handle no input for a label', function () { | ||
| var node = renderIntoApp(fastclickCreateElement('label', {htmlFor: 'my-input'})); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| describe('events', function () { | ||
| it('should persist events if they are to be mutated', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| var persistSpy = spy(); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches, | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| expect(persistSpy).not.to.have.been.called; | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null, | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| // Properties copied onto event from stored positions, and fake click event properties | ||
| expect(persistSpy).to.have.been.calledTwice; | ||
| persistSpy.reset(); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click', | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| expect(persistSpy).not.to.have.been.called; | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| }); |
+16
-10
| { | ||
| "name": "react-fastclick", | ||
| "version": "2.1.2", | ||
| "version": "3.0.0", | ||
| "description": "Fast Touch Events for React", | ||
| "main": "lib/index.js", | ||
| "main": "src/index.js", | ||
| "scripts": { | ||
| "mocha": "istanbul cover node_modules/mocha/bin/_mocha -- --require tests/helpers/test-setup.js --bail --recursive tests", | ||
| "eslint": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib tests/helpers && eslint -c node_modules/eslintrc/.eslintrc-es5-mocha tests", | ||
| "test": "npm run eslint && npm run mocha" | ||
| "mocha": "nyc mocha --bail --recursive 'tests/**/*.test.js'", | ||
| "lint-tests": "eslint -c node_modules/eslintrc/.eslintrc-es5-mocha tests/", | ||
| "lint-src": "eslint -c node_modules/eslintrc/.eslintrc-es5 src/", | ||
| "test": "npm run lint-src && npm run lint-tests && npm run mocha" | ||
| }, | ||
@@ -31,16 +32,21 @@ "repository": { | ||
| "homepage": "https://github.com/JakeSidSmith/react-fastclick", | ||
| "dependencies": { | ||
| "react": ">=0.12.0" | ||
| "peerDependencies": { | ||
| "react": "*" | ||
| }, | ||
| "dependencies": {}, | ||
| "devDependencies": { | ||
| "chai": "=3.5.0", | ||
| "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.1", | ||
| "istanbul": "=1.0.0-alpha.2", | ||
| "jsdom": "=8.4.1", | ||
| "mocha": "=2.4.5", | ||
| "react-addons-test-utils": ">=0.12.0", | ||
| "react-dom": ">=0.12.0", | ||
| "nyc": "=10.1.2", | ||
| "react": "=15.4.2", | ||
| "react-addons-test-utils": "=15.4.2", | ||
| "react-dom": "=15.4.2", | ||
| "sinon": "=1.17.3", | ||
| "sinon-chai": "=2.8.0" | ||
| }, | ||
| "engines": { | ||
| "node": "6.9.4" | ||
| } | ||
| } |
+7
-9
@@ -1,4 +0,2 @@ | ||
| # React Fastclick | ||
| [](https://travis-ci.org/JakeSidSmith/react-fastclick) | ||
| # React Fastclick [](https://circleci.com/gh/JakeSidSmith/react-fastclick) | ||
| **Instantly make your desktop / hybrid apps more responsive on touch devices.** | ||
@@ -18,3 +16,3 @@ | ||
| Include `react-fastclick` in your main javascript file before any of your components are created, and you're done. | ||
| Initialize `react-fastclick` in your main javascript file before any of your components are created, and you're done. | ||
@@ -26,3 +24,4 @@ Now any calls to onClick or elements with special functionality, such as inputs, will have fast touch events added automatically - no need to write any additional listeners. | ||
| ```javascript | ||
| import 'react-fastclick'; | ||
| import initReactFastclick from 'react-fastclick'; | ||
| initReactFastclick(); | ||
| ``` | ||
@@ -33,3 +32,4 @@ | ||
| ```javascript | ||
| require('react-fastclick'); | ||
| var initReactFastclick = require('react-fastclick'); | ||
| initReactFastclick(); | ||
| ``` | ||
@@ -72,4 +72,2 @@ | ||
| React Fastclick 2.1.2 has been tested with React 15, and should support older versions listed below. | ||
| React Fastclick version 2.x.x has been tested with React 0.12, 0.13 and 0.14, and should work with even older versions. | ||
| React Fastclick 3.x.x has been tested with React 15, but should support older versions also. |
| verbose: false | ||
| instrumentation: | ||
| root: 'lib' | ||
| extensions: | ||
| - .js | ||
| default-excludes: true | ||
| excludes: [] | ||
| include-all-sources: true |
-10
| language: node_js | ||
| node_js: | ||
| - '5.9.0' | ||
| install: | ||
| - npm install | ||
| script: | ||
| - npm test |
-240
| 'use strict'; | ||
| (function () { | ||
| var React = require('react'); | ||
| var originalCreateElement = React.createElement; | ||
| // Moved if Math.abs(downX - upX) > MOVE_THRESHOLD; | ||
| var MOVE_THRESHOLD = 8; | ||
| var TOUCH_DELAY = 1000; | ||
| var touchKeysToStore = [ | ||
| 'clientX', | ||
| 'clientY', | ||
| 'pageX', | ||
| 'pageY', | ||
| 'screenX', | ||
| 'screenY', | ||
| 'radiusX', | ||
| 'radiusY' | ||
| ]; | ||
| var touchEvents = { | ||
| downPos: {}, | ||
| lastPos: {} | ||
| }; | ||
| var isDisabled = function (element) { | ||
| if (!element) { | ||
| return false; | ||
| } | ||
| var disabled = element.getAttribute('disabled'); | ||
| return disabled !== false && disabled !== null; | ||
| }; | ||
| var focus = function (event, target) { | ||
| var myTarget = target || event.currentTarget; | ||
| if (!myTarget || isDisabled(myTarget)) { | ||
| return; | ||
| } | ||
| myTarget.focus(); | ||
| }; | ||
| var handleType = { | ||
| input: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| textarea: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| select: function (event) { | ||
| focus(event); | ||
| event.stopPropagation(); | ||
| }, | ||
| label: function (event) { | ||
| var input; | ||
| var forTarget = event.currentTarget.getAttribute('for'); | ||
| if (forTarget) { | ||
| input = document.getElementById(forTarget); | ||
| } else { | ||
| input = event.currentTarget.querySelectorAll('input, textarea, select')[0]; | ||
| } | ||
| if (input) { | ||
| focus(event, input); | ||
| } | ||
| } | ||
| }; | ||
| var fakeClickEvent = function (event) { | ||
| if (typeof event.persist === 'function') { | ||
| event.persist(); | ||
| } | ||
| event.fastclick = true; | ||
| event.type = 'click'; | ||
| event.button = 0; | ||
| }; | ||
| var copyTouchKeys = function (touch, target) { | ||
| if (typeof target.persist === 'function') { | ||
| target.persist(); | ||
| } | ||
| if (touch) { | ||
| for (var i = 0; i < touchKeysToStore.length; i += 1) { | ||
| var key = touchKeysToStore[i]; | ||
| target[key] = touch[key]; | ||
| } | ||
| } | ||
| }; | ||
| var noTouchHappened = function () { | ||
| return !touchEvents.touched && ( | ||
| !touchEvents.lastTouchDate || new Date().getTime() > touchEvents.lastTouchDate + TOUCH_DELAY | ||
| ); | ||
| }; | ||
| var invalidateIfMoreThanOneTouch = function (event) { | ||
| touchEvents.invalid = event.touches && event.touches.length > 1 || touchEvents.invalid; | ||
| }; | ||
| var onMouseEvent = function (callback, event) { | ||
| // Prevent any mouse events if we touched recently | ||
| if (typeof callback === 'function' && noTouchHappened()) { | ||
| callback(event); | ||
| } | ||
| if (event.type === 'click') { | ||
| touchEvents.invalid = false; | ||
| touchEvents.touched = false; | ||
| touchEvents.moved = false; | ||
| } | ||
| }; | ||
| var onTouchStart = function (callback, event) { | ||
| touchEvents.invalid = false; | ||
| touchEvents.moved = false; | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| copyTouchKeys(event.touches[0], touchEvents.downPos); | ||
| copyTouchKeys(event.touches[0], touchEvents.lastPos); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| }; | ||
| var onTouchMove = function (callback, event) { | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| copyTouchKeys(event.touches[0], touchEvents.lastPos); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (Math.abs(touchEvents.downPos.clientX - touchEvents.lastPos.clientX) > MOVE_THRESHOLD || | ||
| Math.abs(touchEvents.downPos.clientY - touchEvents.lastPos.clientY) > MOVE_THRESHOLD) { | ||
| touchEvents.moved = true; | ||
| } | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| }; | ||
| var onTouchEnd = function (callback, onClick, type, event) { | ||
| touchEvents.touched = true; | ||
| touchEvents.lastTouchDate = new Date().getTime(); | ||
| invalidateIfMoreThanOneTouch(event); | ||
| if (typeof callback === 'function') { | ||
| callback(event); | ||
| } | ||
| if (!touchEvents.invalid && !touchEvents.moved) { | ||
| var box = event.currentTarget.getBoundingClientRect(); | ||
| if (touchEvents.lastPos.clientX - (touchEvents.lastPos.radiusX || 0) <= box.right && | ||
| touchEvents.lastPos.clientX + (touchEvents.lastPos.radiusX || 0) >= box.left && | ||
| touchEvents.lastPos.clientY - (touchEvents.lastPos.radiusY || 0) <= box.bottom && | ||
| touchEvents.lastPos.clientY + (touchEvents.lastPos.radiusY || 0) >= box.top) { | ||
| if (!isDisabled(event.currentTarget)) { | ||
| if (typeof onClick === 'function') { | ||
| copyTouchKeys(touchEvents.lastPos, event); | ||
| fakeClickEvent(event); | ||
| onClick(event); | ||
| } | ||
| if (!event.defaultPrevented && handleType[type]) { | ||
| handleType[type](event); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| var propsWithFastclickEvents = function (type, props) { | ||
| var newProps = {}; | ||
| // Loop over props | ||
| for (var key in props) { | ||
| // Copy props to newProps | ||
| newProps[key] = props[key]; | ||
| } | ||
| // Apply our wrapped mouse and touch handlers | ||
| newProps.onClick = onMouseEvent.bind(null, props.onClick); | ||
| newProps.onMouseDown = onMouseEvent.bind(null, props.onMouseDown); | ||
| newProps.onMouseMove = onMouseEvent.bind(null, props.onMouseMove); | ||
| newProps.onMouseUp = onMouseEvent.bind(null, props.onMouseUp); | ||
| newProps.onTouchStart = onTouchStart.bind(null, props.onTouchStart); | ||
| newProps.onTouchMove = onTouchMove.bind(null, props.onTouchMove); | ||
| newProps.onTouchEnd = onTouchEnd.bind(null, props.onTouchEnd, props.onClick, type); | ||
| if (typeof Object.freeze === 'function') { | ||
| Object.freeze(newProps); | ||
| } | ||
| return newProps; | ||
| }; | ||
| React.createElement = function () { | ||
| // Convert arguments to array | ||
| var args = Array.prototype.slice.call(arguments); | ||
| var type = args[0]; | ||
| var props = args[1]; | ||
| // Check if basic element & has onClick prop | ||
| if (type && typeof type === 'string' && ( | ||
| (props && typeof props.onClick === 'function') || handleType[type] | ||
| )) { | ||
| // Add our own events to props | ||
| args[1] = propsWithFastclickEvents(type, props || {}); | ||
| } | ||
| // Apply args to original createElement function | ||
| return originalCreateElement.apply(null, args); | ||
| }; | ||
| if (typeof React.DOM === 'object') { | ||
| for (var key in React.DOM) { | ||
| React.DOM[key] = React.createElement.bind(null, key); | ||
| } | ||
| } | ||
| })(); |
-711
| 'use strict'; | ||
| var expect = require('chai').expect; | ||
| var sinon = require('sinon'); | ||
| var spy = sinon.spy; | ||
| var stub = sinon.stub; | ||
| var TestUtils = require('react-addons-test-utils'); | ||
| var renderIntoApp = require('./helpers/render-into-app'); | ||
| describe('react-fastclick', function () { | ||
| var originalCreateElement, fastclickCreateElement; | ||
| function handlerKeyToSimulatedEventKey (key) { | ||
| var simulatedEventKey = key.replace(/^on/, ''); | ||
| return simulatedEventKey.charAt(0).toLowerCase() + simulatedEventKey.substring(1); | ||
| } | ||
| function getBoundingClientRect () { | ||
| return { | ||
| top: 25, | ||
| left: 25, | ||
| right: 75, | ||
| bottom: 75, | ||
| width: 50, | ||
| height: 50 | ||
| }; | ||
| } | ||
| var touches = [ | ||
| { | ||
| clientX: 50, | ||
| clientY: 50 | ||
| } | ||
| ]; | ||
| var specialTypes = [ | ||
| 'input', | ||
| 'textarea', | ||
| 'select', | ||
| 'label' | ||
| ]; | ||
| var additionalProps = { | ||
| onClick: function () {}, | ||
| onMouseDown: function () {}, | ||
| onMouseMove: function () {}, | ||
| onMouseUp: function () {}, | ||
| onTouchStart: function () {}, | ||
| onTouchMove: function () {}, | ||
| onTouchEnd: function () {} | ||
| }; | ||
| beforeEach(function () { | ||
| // Clear module cache | ||
| delete require.cache[require.resolve('react')]; | ||
| delete require.cache[require.resolve('../lib/index')]; | ||
| }); | ||
| it('should redefine React.createElement', function () { | ||
| originalCreateElement = require('react').createElement; | ||
| var theSameCreateElement = require('react').createElement; | ||
| expect(originalCreateElement).to.equal(theSameCreateElement); | ||
| require('../lib/index'); | ||
| fastclickCreateElement = require('react').createElement; | ||
| expect(originalCreateElement).not.to.equal(fastclickCreateElement); | ||
| }); | ||
| describe('createElement', function () { | ||
| it('should create a regular React element', function () { | ||
| var element = fastclickCreateElement('div'); | ||
| expect(element).to.exist; | ||
| expect(element.ref).to.be.null; | ||
| expect(element.key).to.be.null; | ||
| expect(element.type).to.equal('div'); | ||
| expect(element.props).to.eql({}); | ||
| }); | ||
| it('should add events if it is a special element', function () { | ||
| var element; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| element = fastclickCreateElement(specialTypes[i]); | ||
| for (var key in additionalProps) { | ||
| expect(typeof element.props[key]).to.equal('function'); | ||
| } | ||
| } | ||
| }); | ||
| it('should add events if it has an onClick handler', function () { | ||
| var element = fastclickCreateElement('div', {onClick: function () {}}); | ||
| for (var key in additionalProps) { | ||
| expect(typeof element.props[key]).to.equal('function'); | ||
| } | ||
| }); | ||
| }); | ||
| describe('mouse events', function () { | ||
| it('should trigger standard mouse event handlers', function () { | ||
| var props = { | ||
| onMouseDown: spy(), | ||
| onMouseMove: spy(), | ||
| onMouseUp: spy(), | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| for (var key in props) { | ||
| var mouseEvent = handlerKeyToSimulatedEventKey(key); | ||
| TestUtils.Simulate[mouseEvent](node); | ||
| expect(props[key]).to.have.been.calledOnce; | ||
| } | ||
| }); | ||
| }); | ||
| describe('touch events', function () { | ||
| it('should trigger standard touch event handlers', function () { | ||
| var props = { | ||
| onClick: function () {}, | ||
| onTouchStart: spy(), | ||
| onTouchMove: spy(), | ||
| onTouchEnd: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| for (var key in props) { | ||
| if (key !== 'onClick') { | ||
| var touchEvent = handlerKeyToSimulatedEventKey(key); | ||
| TestUtils.Simulate[touchEvent](node, {touches: [{}]}); | ||
| expect(props[key]).to.have.been.calledOnce; | ||
| } | ||
| } | ||
| }); | ||
| it('should trigger the click handler when a fastclick happens', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if multiple touches', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: [touches[0], touches[0]] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if touch moves', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchMove( | ||
| node, | ||
| { | ||
| type: 'touchmove', | ||
| touches: [ | ||
| { | ||
| clientX: 60, | ||
| clientY: 50 | ||
| } | ||
| ] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should not trigger the click handler if touch is outside of the element', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: [ | ||
| { | ||
| clientX: 80, | ||
| clientY: 80 | ||
| } | ||
| ] | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(props.onClick).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| describe('special elements', function () { | ||
| it('should focus inputs, selects, and textareas when a fastclick is triggered', function () { | ||
| var node, getBoundingClientRectStub, focusSpy; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| var type = specialTypes[i]; | ||
| if (type !== 'label') { | ||
| node = renderIntoApp(fastclickCreateElement(type)); | ||
| getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| focusSpy = spy(node, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| } | ||
| } | ||
| }); | ||
| it('should not focus inputs, selects, and textareas if they are disabled', function () { | ||
| var node, getBoundingClientRectStub, focusSpy; | ||
| for (var i = 0; i < specialTypes.length; i += 1) { | ||
| var type = specialTypes[i]; | ||
| if (type !== 'label') { | ||
| node = renderIntoApp(fastclickCreateElement(type, {disabled: true})); | ||
| getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| focusSpy = spy(node, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.called; | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.called; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| } | ||
| } | ||
| }); | ||
| it('should focus an input inside a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement('label', null, fastclickCreateElement('input')) | ||
| ); | ||
| var label = node; | ||
| var input = label.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should not focus a disabled input inside a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement('label', null, fastclickCreateElement('input', {disabled: true})) | ||
| ); | ||
| var label = node; | ||
| var input = label.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should focus an input for a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement( | ||
| 'div', | ||
| null, | ||
| fastclickCreateElement('label', {htmlFor: 'my-input'}), | ||
| fastclickCreateElement('input', {id: 'my-input'}) | ||
| ) | ||
| ); | ||
| var label = node.getElementsByTagName('label')[0]; | ||
| var input = node.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should not focus a disabled input for a label', function () { | ||
| var node = renderIntoApp( | ||
| fastclickCreateElement( | ||
| 'div', | ||
| null, | ||
| fastclickCreateElement('label', {htmlFor: 'my-input'}), | ||
| fastclickCreateElement('input', {id: 'my-input', disabled: true}) | ||
| ) | ||
| ); | ||
| var label = node.getElementsByTagName('label')[0]; | ||
| var input = node.getElementsByTagName('input')[0]; | ||
| var getBoundingClientRectStub = stub(label, 'getBoundingClientRect', getBoundingClientRect); | ||
| var focusSpy = spy(input, 'focus'); | ||
| TestUtils.Simulate.touchStart( | ||
| label, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| label, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| TestUtils.Simulate.click( | ||
| label, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| expect(focusSpy).not.to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| focusSpy.restore(); | ||
| }); | ||
| it('should gracefully handle no input inside a label', function () { | ||
| var node = renderIntoApp(fastclickCreateElement('label')); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| it('should gracefully handle no input for a label', function () { | ||
| var node = renderIntoApp(fastclickCreateElement('label', {htmlFor: 'my-input'})); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches | ||
| } | ||
| ); | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null | ||
| } | ||
| ); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click' | ||
| } | ||
| ); | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| describe('events', function () { | ||
| it('should persist events if they are to be mutated', function () { | ||
| var props = { | ||
| onClick: spy() | ||
| }; | ||
| var node = renderIntoApp(fastclickCreateElement('div', props)); | ||
| var getBoundingClientRectStub = stub(node, 'getBoundingClientRect', getBoundingClientRect); | ||
| var persistSpy = spy(); | ||
| TestUtils.Simulate.touchStart( | ||
| node, | ||
| { | ||
| type: 'touchstart', | ||
| touches: touches, | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| expect(persistSpy).not.to.have.been.called; | ||
| TestUtils.Simulate.touchEnd( | ||
| node, | ||
| { | ||
| type: 'touchend', | ||
| touches: null, | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| // Properties copied onto event from stored positions, and fake click event properties | ||
| expect(persistSpy).to.have.been.calledTwice; | ||
| persistSpy.reset(); | ||
| TestUtils.Simulate.click( | ||
| node, | ||
| { | ||
| type: 'click', | ||
| persist: persistSpy | ||
| } | ||
| ); | ||
| expect(persistSpy).not.to.have.been.called; | ||
| expect(props.onClick).to.have.been.calledOnce; | ||
| getBoundingClientRectStub.restore(); | ||
| }); | ||
| }); | ||
| }); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
30473
6.77%11
10%803
3.48%10
11.11%70
-2.78%1
Infinity%- Removed