react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / browser / eventPlugins / SelectEventPlugin.js
81155 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule SelectEventPlugin9*/1011"use strict";1213var EventConstants = require('EventConstants');14var EventPropagators = require('EventPropagators');15var ReactInputSelection = require('ReactInputSelection');16var SyntheticEvent = require('SyntheticEvent');1718var getActiveElement = require('getActiveElement');19var isTextInputElement = require('isTextInputElement');20var keyOf = require('keyOf');21var shallowEqual = require('shallowEqual');2223var topLevelTypes = EventConstants.topLevelTypes;2425var eventTypes = {26select: {27phasedRegistrationNames: {28bubbled: keyOf({onSelect: null}),29captured: keyOf({onSelectCapture: null})30},31dependencies: [32topLevelTypes.topBlur,33topLevelTypes.topContextMenu,34topLevelTypes.topFocus,35topLevelTypes.topKeyDown,36topLevelTypes.topMouseDown,37topLevelTypes.topMouseUp,38topLevelTypes.topSelectionChange39]40}41};4243var activeElement = null;44var activeElementID = null;45var lastSelection = null;46var mouseDown = false;4748/**49* Get an object which is a unique representation of the current selection.50*51* The return value will not be consistent across nodes or browsers, but52* two identical selections on the same node will return identical objects.53*54* @param {DOMElement} node55* @param {object}56*/57function getSelection(node) {58if ('selectionStart' in node &&59ReactInputSelection.hasSelectionCapabilities(node)) {60return {61start: node.selectionStart,62end: node.selectionEnd63};64} else if (window.getSelection) {65var selection = window.getSelection();66return {67anchorNode: selection.anchorNode,68anchorOffset: selection.anchorOffset,69focusNode: selection.focusNode,70focusOffset: selection.focusOffset71};72} else if (document.selection) {73var range = document.selection.createRange();74return {75parentElement: range.parentElement(),76text: range.text,77top: range.boundingTop,78left: range.boundingLeft79};80}81}8283/**84* Poll selection to see whether it's changed.85*86* @param {object} nativeEvent87* @return {?SyntheticEvent}88*/89function constructSelectEvent(nativeEvent) {90// Ensure we have the right element, and that the user is not dragging a91// selection (this matches native `select` event behavior). In HTML5, select92// fires only on input and textarea thus if there's no focused element we93// won't dispatch.94if (mouseDown ||95activeElement == null ||96activeElement != getActiveElement()) {97return;98}99100// Only fire when selection has actually changed.101var currentSelection = getSelection(activeElement);102if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {103lastSelection = currentSelection;104105var syntheticEvent = SyntheticEvent.getPooled(106eventTypes.select,107activeElementID,108nativeEvent109);110111syntheticEvent.type = 'select';112syntheticEvent.target = activeElement;113114EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);115116return syntheticEvent;117}118}119120/**121* This plugin creates an `onSelect` event that normalizes select events122* across form elements.123*124* Supported elements are:125* - input (see `isTextInputElement`)126* - textarea127* - contentEditable128*129* This differs from native browser implementations in the following ways:130* - Fires on contentEditable fields as well as inputs.131* - Fires for collapsed selection.132* - Fires after user input.133*/134var SelectEventPlugin = {135136eventTypes: eventTypes,137138/**139* @param {string} topLevelType Record from `EventConstants`.140* @param {DOMEventTarget} topLevelTarget The listening component root node.141* @param {string} topLevelTargetID ID of `topLevelTarget`.142* @param {object} nativeEvent Native browser event.143* @return {*} An accumulation of synthetic events.144* @see {EventPluginHub.extractEvents}145*/146extractEvents: function(147topLevelType,148topLevelTarget,149topLevelTargetID,150nativeEvent) {151152switch (topLevelType) {153// Track the input node that has focus.154case topLevelTypes.topFocus:155if (isTextInputElement(topLevelTarget) ||156topLevelTarget.contentEditable === 'true') {157activeElement = topLevelTarget;158activeElementID = topLevelTargetID;159lastSelection = null;160}161break;162case topLevelTypes.topBlur:163activeElement = null;164activeElementID = null;165lastSelection = null;166break;167168// Don't fire the event while the user is dragging. This matches the169// semantics of the native select event.170case topLevelTypes.topMouseDown:171mouseDown = true;172break;173case topLevelTypes.topContextMenu:174case topLevelTypes.topMouseUp:175mouseDown = false;176return constructSelectEvent(nativeEvent);177178// Chrome and IE fire non-standard event when selection is changed (and179// sometimes when it hasn't).180// Firefox doesn't support selectionchange, so check selection status181// after each key entry. The selection changes after keydown and before182// keyup, but we check on keydown as well in the case of holding down a183// key, when multiple keydown events are fired but only one keyup is.184case topLevelTypes.topSelectionChange:185case topLevelTypes.topKeyDown:186case topLevelTypes.topKeyUp:187return constructSelectEvent(nativeEvent);188}189}190};191192module.exports = SelectEventPlugin;193194195