UNPKG

react-pivot

Version:

React-Pivot is a data-grid component with pivot-table-like functionality for data display, filtering, and exploration.

258 lines (234 loc) 7.48 kB
/** * Copyright 2013-2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule CompositionEventPlugin * @typechecks static-only */ "use strict"; var EventConstants = require("./EventConstants"); var EventPropagators = require("./EventPropagators"); var ExecutionEnvironment = require("./ExecutionEnvironment"); var ReactInputSelection = require("./ReactInputSelection"); var SyntheticCompositionEvent = require("./SyntheticCompositionEvent"); var getTextContentAccessor = require("./getTextContentAccessor"); var keyOf = require("./keyOf"); var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space var START_KEYCODE = 229; var useCompositionEvent = ( ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window ); // In IE9+, we have access to composition events, but the data supplied // by the native compositionend event may be incorrect. In Korean, for example, // the compositionend event contains only one character regardless of // how many characters have been composed since compositionstart. // We therefore use the fallback data while still using the native // events as triggers. var useFallbackData = ( !useCompositionEvent || ( 'documentMode' in document && document.documentMode > 8 && document.documentMode <= 11 ) ); var topLevelTypes = EventConstants.topLevelTypes; var currentComposition = null; // Events and their corresponding property names. var eventTypes = { compositionEnd: { phasedRegistrationNames: { bubbled: keyOf({onCompositionEnd: null}), captured: keyOf({onCompositionEndCapture: null}) }, dependencies: [ topLevelTypes.topBlur, topLevelTypes.topCompositionEnd, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown ] }, compositionStart: { phasedRegistrationNames: { bubbled: keyOf({onCompositionStart: null}), captured: keyOf({onCompositionStartCapture: null}) }, dependencies: [ topLevelTypes.topBlur, topLevelTypes.topCompositionStart, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown ] }, compositionUpdate: { phasedRegistrationNames: { bubbled: keyOf({onCompositionUpdate: null}), captured: keyOf({onCompositionUpdateCapture: null}) }, dependencies: [ topLevelTypes.topBlur, topLevelTypes.topCompositionUpdate, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown ] } }; /** * Translate native top level events into event types. * * @param {string} topLevelType * @return {object} */ function getCompositionEventType(topLevelType) { switch (topLevelType) { case topLevelTypes.topCompositionStart: return eventTypes.compositionStart; case topLevelTypes.topCompositionEnd: return eventTypes.compositionEnd; case topLevelTypes.topCompositionUpdate: return eventTypes.compositionUpdate; } } /** * Does our fallback best-guess model think this event signifies that * composition has begun? * * @param {string} topLevelType * @param {object} nativeEvent * @return {boolean} */ function isFallbackStart(topLevelType, nativeEvent) { return ( topLevelType === topLevelTypes.topKeyDown && nativeEvent.keyCode === START_KEYCODE ); } /** * Does our fallback mode think that this event is the end of composition? * * @param {string} topLevelType * @param {object} nativeEvent * @return {boolean} */ function isFallbackEnd(topLevelType, nativeEvent) { switch (topLevelType) { case topLevelTypes.topKeyUp: // Command keys insert or clear IME input. return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1); case topLevelTypes.topKeyDown: // Expect IME keyCode on each keydown. If we get any other // code we must have exited earlier. return (nativeEvent.keyCode !== START_KEYCODE); case topLevelTypes.topKeyPress: case topLevelTypes.topMouseDown: case topLevelTypes.topBlur: // Events are not possible without cancelling IME. return true; default: return false; } } /** * Helper class stores information about selection and document state * so we can figure out what changed at a later date. * * @param {DOMEventTarget} root */ function FallbackCompositionState(root) { this.root = root; this.startSelection = ReactInputSelection.getSelection(root); this.startValue = this.getText(); } /** * Get current text of input. * * @return {string} */ FallbackCompositionState.prototype.getText = function() { return this.root.value || this.root[getTextContentAccessor()]; }; /** * Text that has changed since the start of composition. * * @return {string} */ FallbackCompositionState.prototype.getData = function() { var endValue = this.getText(); var prefixLength = this.startSelection.start; var suffixLength = this.startValue.length - this.startSelection.end; return endValue.substr( prefixLength, endValue.length - suffixLength - prefixLength ); }; /** * This plugin creates `onCompositionStart`, `onCompositionUpdate` and * `onCompositionEnd` events on inputs, textareas and contentEditable * nodes. */ var CompositionEventPlugin = { eventTypes: eventTypes, /** * @param {string} topLevelType Record from `EventConstants`. * @param {DOMEventTarget} topLevelTarget The listening component root node. * @param {string} topLevelTargetID ID of `topLevelTarget`. * @param {object} nativeEvent Native browser event. * @return {*} An accumulation of synthetic events. * @see {EventPluginHub.extractEvents} */ extractEvents: function( topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) { var eventType; var data; if (useCompositionEvent) { eventType = getCompositionEventType(topLevelType); } else if (!currentComposition) { if (isFallbackStart(topLevelType, nativeEvent)) { eventType = eventTypes.compositionStart; } } else if (isFallbackEnd(topLevelType, nativeEvent)) { eventType = eventTypes.compositionEnd; } if (useFallbackData) { // The current composition is stored statically and must not be // overwritten while composition continues. if (!currentComposition && eventType === eventTypes.compositionStart) { currentComposition = new FallbackCompositionState(topLevelTarget); } else if (eventType === eventTypes.compositionEnd) { if (currentComposition) { data = currentComposition.getData(); currentComposition = null; } } } if (eventType) { var event = SyntheticCompositionEvent.getPooled( eventType, topLevelTargetID, nativeEvent ); if (data) { // Inject data generated from fallback path into the synthetic event. // This matches the property of native CompositionEventInterface. event.data = data; } EventPropagators.accumulateTwoPhaseDispatches(event); return event; } } }; module.exports = CompositionEventPlugin;