/** * React v0.3.2 */ (function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()})(function(){var define,ses,bootstrap,module,exports; return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;sHello World; * } * }); * * The class specification supports a specific protocol of methods that have * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for * more the comprehensive protocol. Any other properties and methods in the * class specification will available on the prototype. * * @interface ReactCompositeComponentInterface * @internal */ var ReactCompositeComponentInterface = { /** * An array of Mixin objects to include when defining your component. * * @type {array} * @optional */ mixins: SpecPolicy.DEFINE_MANY, /** * Definition of props for this component. * * @type {array} * @optional */ props: SpecPolicy.DEFINE_ONCE, // ==== Definition methods ==== /** * Invoked once before the component is mounted. The return value will be used * as the initial value of `this.state`. * * getInitialState: function() { * return { * isOn: false, * fooBaz: new BazFoo() * } * } * * @return {object} * @optional */ getInitialState: SpecPolicy.DEFINE_ONCE, /** * Uses props from `this.props` and state from `this.state` to render the * structure of the component. * * No guarantees are made about when or how often this method is invoked, so * it must not have side effects. * * render: function() { * var name = this.props.name; * return
Hello, {name}!
; * } * * @return {ReactComponent} * @nosideeffects * @required */ render: SpecPolicy.DEFINE_ONCE, // ==== Delegate methods ==== /** * Invoked when the component is initially created and about to be mounted. * This may have side effects, but any external subscriptions or data created * by this method must be cleaned up in `componentWillUnmount`. * * @optional */ componentWillMount: SpecPolicy.DEFINE_MANY, /** * Invoked when the component has been mounted and has a DOM representation. * However, there is no guarantee that the DOM node is in the document. * * Use this as an opportunity to operate on the DOM when the component has * been mounted (initialized and rendered) for the first time. * * @param {DOMElement} rootNode DOM element representing the component. * @optional */ componentDidMount: SpecPolicy.DEFINE_MANY, /** * Invoked before the component receives new props. * * Use this as an opportunity to react to a prop transition by updating the * state using `this.setState`. Current props are accessed via `this.props`. * * componentWillReceiveProps: function(nextProps) { * this.setState({ * likesIncreasing: nextProps.likeCount > this.props.likeCount * }); * } * * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop * transition may cause a state change, but the opposite is not true. If you * need it, you are probably looking for `componentWillUpdate`. * * @param {object} nextProps * @optional */ componentWillReceiveProps: SpecPolicy.DEFINE_MANY, /** * Invoked while deciding if the component should be updated as a result of * receiving new props and state. * * Use this as an opportunity to `return false` when you're certain that the * transition to the new props and state will not require a component update. * * shouldComponentUpdate: function(nextProps, nextState) { * return !equal(nextProps, this.props) || !equal(nextState, this.state); * } * * @param {object} nextProps * @param {?object} nextState * @return {boolean} True if the component should update. * @optional */ shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, /** * Invoked when the component is about to update due to a transition from * `this.props` and `this.state` to `nextProps` and `nextState`. * * Use this as an opportunity to perform preparation before an update occurs. * * NOTE: You **cannot** use `this.setState()` in this method. * * @param {object} nextProps * @param {?object} nextState * @param {ReactReconcileTransaction} transaction * @optional */ componentWillUpdate: SpecPolicy.DEFINE_MANY, /** * Invoked when the component's DOM representation has been updated. * * Use this as an opportunity to operate on the DOM when the component has * been updated. * * @param {object} prevProps * @param {?object} prevState * @param {DOMElement} rootNode DOM element representing the component. * @optional */ componentDidUpdate: SpecPolicy.DEFINE_MANY, /** * Invoked when the component is about to be removed from its parent and have * its DOM representation destroyed. * * Use this as an opportunity to deallocate any external resources. * * NOTE: There is no `componentDidUnmount` since your component will have been * destroyed by that point. * * @optional */ componentWillUnmount: SpecPolicy.DEFINE_MANY, // ==== Advanced methods ==== /** * Updates the component's currently mounted DOM representation. * * By default, this implements React's rendering and reconciliation algorithm. * Sophisticated clients may wish to override this. * * @param {ReactReconcileTransaction} transaction * @internal * @overridable */ updateComponent: SpecPolicy.OVERRIDE_BASE }; /** * Mapping from class specification keys to special processing functions. * * Although these are declared in the specification when defining classes * using `React.createClass`, they will not be on the component's prototype. */ var RESERVED_SPEC_KEYS = { displayName: function(Constructor, displayName) { Constructor.displayName = displayName; }, mixins: function(Constructor, mixins) { if (mixins) { for (var i = 0; i < mixins.length; i++) { mixSpecIntoComponent(Constructor, mixins[i]); } } }, props: function(Constructor, props) { Constructor.propDeclarations = props; } }; /** * Custom version of `mixInto` which handles policy validation and reserved * specification keys when building `ReactCompositeComponent` classses. */ function mixSpecIntoComponent(Constructor, spec) { var proto = Constructor.prototype; for (var name in spec) { if (!spec.hasOwnProperty(name)) { continue; } var property = spec[name]; var specPolicy = ReactCompositeComponentInterface[name]; // Disallow overriding of base class methods unless explicitly allowed. if (ReactCompositeComponentMixin.hasOwnProperty(name)) { invariant( specPolicy === SpecPolicy.OVERRIDE_BASE, 'ReactCompositeComponentInterface: You are attempting to override ' + '`%s` from your class specification. Ensure that your method names ' + 'do not overlap with React methods.', name ); } // Disallow using `React.autoBind` on internal methods. if (specPolicy != null) { invariant( !property || !property.__reactAutoBind, 'ReactCompositeComponentInterface: You are attempting to use ' + '`React.autoBind` on `%s`, a method that is internal to React.' + 'Internal methods are called with the component as the context.', name ); } // Disallow defining methods more than once unless explicitly allowed. if (proto.hasOwnProperty(name)) { invariant( specPolicy === SpecPolicy.DEFINE_MANY, 'ReactCompositeComponentInterface: You are attempting to define ' + '`%s` on your component more than once. This conflict may be due ' + 'to a mixin.', name ); } if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { RESERVED_SPEC_KEYS[name](Constructor, property); } else if (property && property.__reactAutoBind) { if (!proto.__reactAutoBindMap) { proto.__reactAutoBindMap = {}; } proto.__reactAutoBindMap[name] = property.__reactAutoBind; } else if (proto.hasOwnProperty(name)) { // For methods which are defined more than once, call the existing methods // before calling the new property. proto[name] = createChainedFunction(proto[name], property); } else { proto[name] = property; } } } /** * Creates a function that invokes two functions and ignores their return vales. * * @param {function} one Function to invoke first. * @param {function} two Function to invoke second. * @return {function} Function that invokes the two argument functions. * @private */ function createChainedFunction(one, two) { return function chainedFunction(a, b, c, d, e, tooMany) { invariant( typeof tooMany === 'undefined', 'Chained function can only take a maximum of 5 arguments.' ); one.call(this, a, b, c, d, e); two.call(this, a, b, c, d, e); }; } /** * `ReactCompositeComponent` maintains an auxiliary life cycle state in * `this._compositeLifeCycleState` (which can be null). * * This is different from the life cycle state maintained by `ReactComponent` in * `this._lifeCycleState`. */ var CompositeLifeCycle = keyMirror({ /** * Components in the process of being mounted respond to state changes * differently. */ MOUNTING: null, /** * Components in the process of being unmounted are guarded against state * changes. */ UNMOUNTING: null, /** * Components that are mounted and receiving new props respond to state * changes differently. */ RECEIVING_PROPS: null, /** * Components that are mounted and receiving new state are guarded against * additional state changes. */ RECEIVING_STATE: null }); /** * @lends {ReactCompositeComponent.prototype} */ var ReactCompositeComponentMixin = { /** * Base constructor for all composite component. * * @param {?object} initialProps * @param {*} children * @final * @internal */ construct: function(initialProps, children) { ReactComponent.Mixin.construct.call(this, initialProps, children); this.state = null; this._pendingState = null; this._compositeLifeCycleState = null; }, /** * Initializes the component, renders markup, and registers event listeners. * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction} transaction * @return {?string} Rendered markup to be inserted into the DOM. * @final * @internal */ mountComponent: function(rootID, transaction) { ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); // Unset `this._lifeCycleState` until after this method is finished. this._lifeCycleState = ReactComponent.LifeCycle.UNMOUNTED; this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; if (this.constructor.propDeclarations) { this._assertValidProps(this.props); } if (this.__reactAutoBindMap) { this._bindAutoBindMethods(); } this.state = this.getInitialState ? this.getInitialState() : null; this._pendingState = null; if (this.componentWillMount) { this.componentWillMount(); // When mounting, calls to `setState` by `componentWillMount` will set // `this._pendingState` without triggering a re-render. if (this._pendingState) { this.state = this._pendingState; this._pendingState = null; } } if (this.componentDidMount) { transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); } this._renderedComponent = this._renderValidatedComponent(); // Done with mounting, `setState` will now trigger UI changes. this._compositeLifeCycleState = null; this._lifeCycleState = ReactComponent.LifeCycle.MOUNTED; return this._renderedComponent.mountComponent(rootID, transaction); }, /** * Releases any resources allocated by `mountComponent`. * * @final * @internal */ unmountComponent: function() { this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; if (this.componentWillUnmount) { this.componentWillUnmount(); } this._compositeLifeCycleState = null; ReactComponent.Mixin.unmountComponent.call(this); this._renderedComponent.unmountComponent(); this._renderedComponent = null; if (this.refs) { this.refs = null; } // Some existing components rely on this.props even after they've been // destroyed (in event handlers). // TODO: this.props = null; // TODO: this.state = null; }, /** * Updates the rendered DOM nodes given a new set of props. * * @param {object} nextProps Next set of properties. * @param {ReactReconcileTransaction} transaction * @final * @internal */ receiveProps: function(nextProps, transaction) { if (this.constructor.propDeclarations) { this._assertValidProps(nextProps); } ReactComponent.Mixin.receiveProps.call(this, nextProps, transaction); this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; if (this.componentWillReceiveProps) { this.componentWillReceiveProps(nextProps, transaction); } this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; // When receiving props, calls to `setState` by `componentWillReceiveProps` // will set `this._pendingState` without triggering a re-render. var nextState = this._pendingState || this.state; this._pendingState = null; this._receivePropsAndState(nextProps, nextState, transaction); this._compositeLifeCycleState = null; }, /** * Sets a subset of the state. Always use this or `replaceState` to mutate * state. You should treat `this.state` as immutable. * * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * @param {object} partialState Next partial state to be merged with state. * @final * @protected */ setState: function(partialState) { // Merge with `_pendingState` if it exists, otherwise with existing state. this.replaceState(merge(this._pendingState || this.state, partialState)); }, /** * Replaces all of the state. Always use this or `setState` to mutate state. * You should treat `this.state` as immutable. * * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * @param {object} completeState Next state. * @final * @protected */ replaceState: function(completeState) { var compositeLifeCycleState = this._compositeLifeCycleState; invariant( this._lifeCycleState === ReactComponent.LifeCycle.MOUNTED || compositeLifeCycleState === CompositeLifeCycle.MOUNTING, 'replaceState(...): Can only update a mounted (or mounting) component.' ); invariant( compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, 'replaceState(...): Cannot update while unmounting component or during ' + 'an existing state transition (such as within `render`).' ); this._pendingState = completeState; // Do not trigger a state transition if we are in the middle of mounting or // receiving props because both of those will already be doing this. if (compositeLifeCycleState !== CompositeLifeCycle.MOUNTING && compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_PROPS) { this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; var nextState = this._pendingState; this._pendingState = null; var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform( this._receivePropsAndState, this, this.props, nextState, transaction ); ReactComponent.ReactReconcileTransaction.release(transaction); this._compositeLifeCycleState = null; } }, /** * Receives next props and next state, and negotiates whether or not the * component should update as a result. * * @param {object} nextProps Next object to set as props. * @param {?object} nextState Next object to set as state. * @param {ReactReconcileTransaction} transaction * @private */ _receivePropsAndState: function(nextProps, nextState, transaction) { if (!this.shouldComponentUpdate || this.shouldComponentUpdate(nextProps, nextState)) { // Will set `this.props` and `this.state`. this._performComponentUpdate(nextProps, nextState, transaction); } else { // If it's determined that a component should not update, we still want // to set props and state. this.props = nextProps; this.state = nextState; } }, /** * Merges new props and state, notifies delegate methods of update and * performs update. * * @param {object} nextProps Next object to set as properties. * @param {?object} nextState Next object to set as state. * @param {ReactReconcileTransaction} transaction * @private */ _performComponentUpdate: function(nextProps, nextState, transaction) { var prevProps = this.props; var prevState = this.state; if (this.componentWillUpdate) { this.componentWillUpdate(nextProps, nextState, transaction); } this.props = nextProps; this.state = nextState; this.updateComponent(transaction); if (this.componentDidUpdate) { transaction.getReactOnDOMReady().enqueue( this, this.componentDidUpdate.bind(this, prevProps, prevState) ); } }, /** * Updates the component's currently mounted DOM representation. * * By default, this implements React's rendering and reconciliation algorithm. * Sophisticated clients may wish to override this. * * @param {ReactReconcileTransaction} transaction * @internal * @overridable */ updateComponent: function(transaction) { var currentComponent = this._renderedComponent; var nextComponent = this._renderValidatedComponent(); if (currentComponent.constructor === nextComponent.constructor) { if (!nextComponent.props.isStatic) { currentComponent.receiveProps(nextComponent.props, transaction); } } else { // These two IDs are actually the same! But nothing should rely on that. var thisID = this._rootNodeID; var currentComponentID = currentComponent._rootNodeID; currentComponent.unmountComponent(); var nextMarkup = nextComponent.mountComponent(thisID, transaction); ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( currentComponentID, nextMarkup ); this._renderedComponent = nextComponent; } }, /** * Forces an update. This should only be invoked when it is known with * certainty that we are **not** in a DOM transaction. * * You may want to call this when you know that some deeper aspect of the * component's state has changed but `setState` was not called. * * This will not invoke `shouldUpdateComponent`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @final * @protected */ forceUpdate: function() { var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform( this._performComponentUpdate, this, this.props, this.state, transaction ); ReactComponent.ReactReconcileTransaction.release(transaction); }, /** * @private */ _renderValidatedComponent: function() { ReactCurrentOwner.current = this; var renderedComponent = this.render(); ReactCurrentOwner.current = null; invariant( ReactComponent.isValidComponent(renderedComponent), '%s.render(): A valid ReactComponent must be returned.', this.constructor.displayName || 'ReactCompositeComponent' ); return renderedComponent; }, /** * @param {object} props * @private */ _assertValidProps: function(props) { var propDeclarations = this.constructor.propDeclarations; var componentName = this.constructor.displayName; for (var propName in propDeclarations) { var checkProp = propDeclarations[propName]; if (checkProp) { checkProp(props, propName, componentName); } } }, /** * @private */ _bindAutoBindMethods: function() { for (var autoBindKey in this.__reactAutoBindMap) { if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { continue; } var method = this.__reactAutoBindMap[autoBindKey]; this[autoBindKey] = this._bindAutoBindMethod(method); } }, /** * Binds a method to the component. * * @param {function} method Method to be bound. * @private */ _bindAutoBindMethod: function(method) { var component = this; var hasWarned = false; function autoBound(a, b, c, d, e, tooMany) { invariant( typeof tooMany === 'undefined', 'React.autoBind(...): Methods can only take a maximum of 5 arguments.' ); if (component._lifeCycleState === ReactComponent.LifeCycle.MOUNTED) { return method.call(component, a, b, c, d, e); } else if (!hasWarned) { hasWarned = true; if (true) { console.warn( 'React.autoBind(...): Attempted to invoke an auto-bound method ' + 'on an unmounted instance of `%s`. You either have a memory leak ' + 'or an event handler that is being run after unmounting.', component.constructor.displayName || 'ReactCompositeComponent' ); } } } return autoBound; } }; var ReactCompositeComponentBase = function() {}; mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); /** * Module for creating composite components. * * @class ReactCompositeComponent * @extends ReactComponent * @extends ReactOwner * @extends ReactPropTransferer */ var ReactCompositeComponent = { LifeCycle: CompositeLifeCycle, Base: ReactCompositeComponentBase, /** * Creates a composite component class given a class specification. * * @param {object} spec Class specification (which must define `render`). * @return {function} Component constructor function. * @public */ createClass: function(spec) { var Constructor = function(initialProps, children) { this.construct(initialProps, children); }; Constructor.prototype = new ReactCompositeComponentBase(); Constructor.prototype.constructor = Constructor; mixSpecIntoComponent(Constructor, spec); invariant( Constructor.prototype.render, 'createClass(...): Class specification must implement a `render` method.' ); var ConvenienceConstructor = function(props, children) { return new Constructor(props, children); }; ConvenienceConstructor.componentConstructor = Constructor; ConvenienceConstructor.originalSpec = spec; return ConvenienceConstructor; }, /** * Marks the provided method to be automatically bound to the component. * This means the method's context will always be the component. * * React.createClass({ * handleClick: React.autoBind(function() { * this.setState({jumping: true}); * }), * render: function() { * return Jump; * } * }); * * @param {function} method Method to be bound. * @public */ autoBind: function(method) { function unbound() { invariant( false, 'React.autoBind(...): Attempted to invoke an auto-bound method that ' + 'was not correctly defined on the class specification.' ); } unbound.__reactAutoBind = method; return unbound; } }; module.exports = ReactCompositeComponent; })() },{"./ReactComponent":3,"./ReactCurrentOwner":7,"./ReactOwner":8,"./ReactPropTransferer":9,"./invariant":10,"./keyMirror":11,"./merge":12,"./mixInto":13}],3:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactComponent */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var ReactCurrentOwner = require("./ReactCurrentOwner"); var ReactDOMIDOperations = require("./ReactDOMIDOperations"); var ReactMount = require("./ReactMount"); var ReactOwner = require("./ReactOwner"); var ReactReconcileTransaction = require("./ReactReconcileTransaction"); var invariant = require("./invariant"); var keyMirror = require("./keyMirror"); var merge = require("./merge"); /** * Prop key that references a component's owner. * @private */ var OWNER = '{owner}'; /** * Every React component is in one of these life cycles. */ var ComponentLifeCycle = keyMirror({ /** * Mounted components have a DOM node representation and are capable of * receiving new props. */ MOUNTED: null, /** * Unmounted components are inactive and cannot receive new props. */ UNMOUNTED: null }); /** * Components are the basic units of composition in React. * * Every component accepts a set of keyed input parameters known as "props" that * are initialized by the constructor. Once a component is mounted, the props * can be mutated using `setProps` or `replaceProps`. * * Every component is capable of the following operations: * * `mountComponent` * Initializes the component, renders markup, and registers event listeners. * * `receiveProps` * Updates the rendered DOM nodes given a new set of props. * * `unmountComponent` * Releases any resources allocated by this component. * * Components can also be "owned" by other components. Being owned by another * component means being constructed by that component. This is different from * being the child of a component, which means having a DOM representation that * is a child of the DOM representation of that component. * * @class ReactComponent */ var ReactComponent = { /** * @param {?object} object * @return {boolean} True if `object` is a valid component. * @final */ isValidComponent: function(object) { return !!( object && typeof object.mountComponentIntoNode === 'function' && typeof object.receiveProps === 'function' ); }, /** * @internal */ LifeCycle: ComponentLifeCycle, /** * React references `ReactDOMIDOperations` using this property in order to * allow dependency injection. * * @internal */ DOMIDOperations: ReactDOMIDOperations, /** * React references `ReactReconcileTransaction` using this property in order * to allow dependency injection. * * @internal */ ReactReconcileTransaction: ReactReconcileTransaction, /** * @param {object} DOMIDOperations * @final */ setDOMOperations: function(DOMIDOperations) { ReactComponent.DOMIDOperations = DOMIDOperations; }, /** * @param {Transaction} ReactReconcileTransaction * @final */ setReactReconcileTransaction: function(ReactReconcileTransaction) { ReactComponent.ReactReconcileTransaction = ReactReconcileTransaction; }, /** * Base functionality for every ReactComponent constructor. * * @lends {ReactComponent.prototype} */ Mixin: { /** * Returns the DOM node rendered by this component. * * @return {?DOMElement} The root node of this component. * @final * @protected */ getDOMNode: function() { invariant( ExecutionEnvironment.canUseDOM, 'getDOMNode(): The DOM is not supported in the current environment.' ); invariant( this._lifeCycleState === ComponentLifeCycle.MOUNTED, 'getDOMNode(): A component must be mounted to have a DOM node.' ); var rootNode = this._rootNode; if (!rootNode) { rootNode = document.getElementById(this._rootNodeID); if (!rootNode) { // TODO: Log the frequency that we reach this path. rootNode = ReactMount.findReactRenderedDOMNodeSlow(this._rootNodeID); } this._rootNode = rootNode; } return rootNode; }, /** * Sets a subset of the props. * * @param {object} partialProps Subset of the next props. * @final * @public */ setProps: function(partialProps) { this.replaceProps(merge(this.props, partialProps)); }, /** * Replaces all of the props. * * @param {object} props New props. * @final * @public */ replaceProps: function(props) { invariant( !this.props[OWNER], 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + 'component with an owner. This is an anti-pattern since props will ' + 'get reactively updated when rendered. Instead, change the owner\'s ' + '`render` method to pass the correct value as props to the component ' + 'where it is created.' ); var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform(this.receiveProps, this, props, transaction); ReactComponent.ReactReconcileTransaction.release(transaction); }, /** * Base constructor for all React component. * * Subclasses that override this method should make sure to invoke * `ReactComponent.Mixin.construct.call(this, ...)`. * * @param {?object} initialProps * @param {*} children * @internal */ construct: function(initialProps, children) { this.props = initialProps || {}; if (typeof children !== 'undefined') { this.props.children = children; } // Record the component responsible for creating this component. this.props[OWNER] = ReactCurrentOwner.current; // All components start unmounted. this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; }, /** * Initializes the component, renders markup, and registers event listeners. * * NOTE: This does not insert any nodes into the DOM. * * Subclasses that override this method should make sure to invoke * `ReactComponent.Mixin.mountComponent.call(this, ...)`. * * @param {string} rootID DOM ID of the root node. * @param {ReactReconcileTransaction} transaction * @return {?string} Rendered markup to be inserted into the DOM. * @internal */ mountComponent: function(rootID, transaction) { invariant( this._lifeCycleState === ComponentLifeCycle.UNMOUNTED, 'mountComponent(%s, ...): Can only mount an unmounted component.', rootID ); var props = this.props; if (props.ref != null) { ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]); } this._rootNodeID = rootID; this._lifeCycleState = ComponentLifeCycle.MOUNTED; // Effectively: return ''; }, /** * Releases any resources allocated by `mountComponent`. * * NOTE: This does not remove any nodes from the DOM. * * Subclasses that override this method should make sure to invoke * `ReactComponent.Mixin.unmountComponent.call(this)`. * * @internal */ unmountComponent: function() { invariant( this._lifeCycleState === ComponentLifeCycle.MOUNTED, 'unmountComponent(): Can only unmount a mounted component.' ); var props = this.props; if (props.ref != null) { ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); } this._rootNode = null; this._rootNodeID = null; this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; }, /** * Updates the rendered DOM nodes given a new set of props. * * Subclasses that override this method should make sure to invoke * `ReactComponent.Mixin.receiveProps.call(this, ...)`. * * @param {object} nextProps Next set of properties. * @param {ReactReconcileTransaction} transaction * @internal */ receiveProps: function(nextProps, transaction) { invariant( this._lifeCycleState === ComponentLifeCycle.MOUNTED, 'receiveProps(...): Can only update a mounted component.' ); var props = this.props; // If either the owner or a `ref` has changed, make sure the newest owner // has stored a reference to `this`, and the previous owner (if different) // has forgotten the reference to `this`. if (nextProps[OWNER] !== props[OWNER] || nextProps.ref !== props.ref) { if (props.ref != null) { ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); } // Correct, even if the owner is the same, and only the ref has changed. if (nextProps.ref != null) { ReactOwner.addComponentAsRefTo(this, nextProps.ref, nextProps[OWNER]); } } }, /** * Mounts this component and inserts it into the DOM. * * @param {string} rootID DOM ID of the root node. * @param {DOMElement} container DOM element to mount into. * @final * @internal * @see {ReactMount.renderComponent} */ mountComponentIntoNode: function(rootID, container) { var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); transaction.perform( this._mountComponentIntoNode, this, rootID, container, transaction ); ReactComponent.ReactReconcileTransaction.release(transaction); }, /** * @param {string} rootID DOM ID of the root node. * @param {DOMElement} container DOM element to mount into. * @param {ReactReconcileTransaction} transaction * @final * @private */ _mountComponentIntoNode: function(rootID, container, transaction) { var renderStart = Date.now(); var markup = this.mountComponent(rootID, transaction); ReactMount.totalInstantiationTime += (Date.now() - renderStart); var injectionStart = Date.now(); // Asynchronously inject markup by ensuring that the container is not in // the document when settings its `innerHTML`. var parent = container.parentNode; if (parent) { var next = container.nextSibling; parent.removeChild(container); container.innerHTML = markup; if (next) { parent.insertBefore(container, next); } else { parent.appendChild(container); } } else { container.innerHTML = markup; } ReactMount.totalInjectionTime += (Date.now() - injectionStart); }, /** * Unmounts this component and removes it from the DOM. * * @param {DOMElement} container DOM element to unmount from. * @final * @internal * @see {ReactMount.unmountAndReleaseReactRootNode} */ unmountComponentFromNode: function(container) { this.unmountComponent(); // http://jsperf.com/emptying-a-node while (container.lastChild) { container.removeChild(container.lastChild); } }, /** * Checks if this component is owned by the supplied `owner` component. * * @param {ReactComponent} owner Component to check. * @return {boolean} True if `owners` owns this component. * @final * @internal */ isOwnedBy: function(owner) { return this.props[OWNER] === owner; } } }; function logDeprecated(msg) { if (true) { throw new Error(msg); } } /** * @deprecated */ ReactComponent.Mixin.update = function(props) { logDeprecated('this.update() is deprecated. Use this.setProps()'); this.setProps(props); }; ReactComponent.Mixin.updateAll = function(props) { logDeprecated('this.updateAll() is deprecated. Use this.replaceProps()'); this.replaceProps(props); }; module.exports = ReactComponent; },{"./ExecutionEnvironment":14,"./ReactCurrentOwner":7,"./ReactDOMIDOperations":15,"./ReactMount":5,"./ReactOwner":8,"./ReactReconcileTransaction":16,"./invariant":10,"./keyMirror":11,"./merge":12}],4:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactDOM * @typechecks */ "use strict"; var ReactNativeComponent = require("./ReactNativeComponent"); var mergeInto = require("./mergeInto"); var objMapKeyVal = require("./objMapKeyVal"); /** * Creates a new React class that is idempotent and capable of containing other * React components. It accepts event listeners and DOM properties that are * valid according to `DOMProperty`. * * - Event listeners: `onClick`, `onMouseDown`, etc. * - DOM properties: `className`, `name`, `title`, etc. * * The `style` property functions differently from the DOM API. It accepts an * object mapping of style properties to values. * * @param {string} tag Tag name (e.g. `div`). * @param {boolean} omitClose True if the close tag should be omitted. * @private */ function createDOMComponentClass(tag, omitClose) { var Constructor = function(initialProps, children) { this.construct(initialProps, children); }; Constructor.prototype = new ReactNativeComponent(tag, omitClose); Constructor.prototype.constructor = Constructor; return function(props, children) { return new Constructor(props, children); }; } /** * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes. * This is also accessible via `React.DOM`. * * @public */ var ReactDOM = objMapKeyVal({ a: false, abbr: false, address: false, audio: false, b: false, body: false, br: true, button: false, code: false, col: true, colgroup: false, dd: false, div: false, section: false, dl: false, dt: false, em: false, embed: true, fieldset: false, footer: false, // Danger: this gets monkeypatched! See ReactDOMForm for more info. form: false, h1: false, h2: false, h3: false, h4: false, h5: false, h6: false, header: false, hr: true, i: false, iframe: false, img: true, input: true, label: false, legend: false, li: false, line: false, nav: false, object: false, ol: false, optgroup: false, option: false, p: false, param: true, pre: false, select: false, small: false, source: false, span: false, sub: false, sup: false, strong: false, table: false, tbody: false, td: false, textarea: false, tfoot: false, th: false, thead: false, time: false, title: false, tr: false, u: false, ul: false, video: false, wbr: false, // SVG circle: false, g: false, path: false, polyline: false, rect: false, svg: false, text: false }, createDOMComponentClass); var injection = { injectComponentClasses: function(componentClasses) { mergeInto(ReactDOM, componentClasses); } }; ReactDOM.injection = injection; module.exports = ReactDOM; },{"./ReactNativeComponent":17,"./mergeInto":18,"./objMapKeyVal":19}],5:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactMount */ "use strict"; var ReactEvent = require("./ReactEvent"); var ReactInstanceHandles = require("./ReactInstanceHandles"); var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback"); var $ = require("./$"); var globalMountPointCounter = 0; /** Mapping from reactRoot DOM ID to React component instance. */ var instanceByReactRootID = {}; /** Mapping from reactRoot DOM ID to `container` nodes. */ var containersByReactRootID = {}; /** * @param {DOMElement} container DOM element that may contain a React component. * @return {?string} A "reactRoot" ID, if a React component is rendered. */ function getReactRootID(container) { return container.firstChild && container.firstChild.id; } /** * Mounting is the process of initializing a React component by creatings its * representative DOM elements and inserting them into a supplied `container`. * Any prior content inside `container` is destroyed in the process. * * ReactMount.renderComponent(component, $('container')); * *
<-- Supplied `container`. *
<-- Rendered reactRoot of React component. * // ... *
*
* * Inside of `container`, the first element rendered is the "reactRoot". */ var ReactMount = { /** Time spent generating markup. */ totalInstantiationTime: 0, /** Time spent inserting markup into the DOM. */ totalInjectionTime: 0, /** Whether support for touch events should be initialized. */ useTouchEvents: false, /** * This is a hook provided to support rendering React components while * ensuring that the apparent scroll position of its `container` does not * change. * * @param {DOMElement} container The `container` being rendered into. * @param {function} renderCallback This must be called once to do the render. */ scrollMonitor: function(container, renderCallback) { renderCallback(); }, /** * Ensures tht the top-level event delegation listener is set up. This will be * invoked some time before the first time any React component is rendered. * * @param {object} TopLevelCallbackCreator * @private */ prepareTopLevelEvents: function(TopLevelCallbackCreator) { ReactEvent.ensureListening( ReactMount.useTouchEvents, TopLevelCallbackCreator ); }, /** * Renders a React component into the DOM in the supplied `container`. * * If the React component was previously rendered into `container`, this will * perform an update on it and only mutate the DOM as necessary to reflect the * latest React component. * * @param {ReactComponent} nextComponent Component instance to render. * @param {DOMElement} container DOM element to render into. * @return {ReactComponent} Component instance rendered in `container`. */ renderComponent: function(nextComponent, container) { var prevComponent = instanceByReactRootID[getReactRootID(container)]; if (prevComponent) { var nextProps = nextComponent.props; ReactMount.scrollMonitor(container, function() { prevComponent.replaceProps(nextProps); }); return prevComponent; } ReactMount.prepareTopLevelEvents(ReactEventTopLevelCallback); var reactRootID = ReactMount.registerContainer(container); instanceByReactRootID[reactRootID] = nextComponent; nextComponent.mountComponentIntoNode(reactRootID, container); return nextComponent; }, /** * Creates a function that accepts a `container` and renders the supplied * React component instance into it. * * var renderInto = ReactMount.createComponentRenderer(component); * // ... * var component = renderInto($('container')); * * @param {ReactComponent} component Component instance to render. * @return {function(DOMElement): ReactComponent} */ createComponentRenderer: function(component) { return function(container) { return ReactMount.renderComponent(component, container); }; }, /** * Constructs a component instance of `constructor` with `initialProps` and * renders it into the supplied `container`. * * @param {function} constructor React component constructor. * @param {?object} props Initial props of the component instance. * @param {DOMElement} container DOM element to render into. * @return {ReactComponent} Component instance rendered in `container`. */ constructAndRenderComponent: function(constructor, props, container) { return ReactMount.renderComponent(constructor(props), container); }, /** * Constructs a component instance of `constructor` with `initialProps` and * renders it into a container node identified by supplied `id`. * * @param {function} componentConstructor React component constructor * @param {?object} props Initial props of the component instance. * @param {string} id ID of the DOM element to render into. * @return {ReactComponent} Component instance rendered in the container node. */ constructAndRenderComponentByID: function(constructor, props, id) { return ReactMount.constructAndRenderComponent(constructor, props, $(id)); }, /** * Registers a container node into which React components will be rendered. * This also creates the "reatRoot" ID that will be assigned to the element * rendered within. * * @param {DOMElement} container DOM element to register as a container. * @return {string} The "reactRoot" ID of elements rendered within. */ registerContainer: function(container) { var reactRootID = getReactRootID(container); if (reactRootID) { // If one exists, make sure it is a valid "reactRoot" ID. reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); } if (!reactRootID) { // No valid "reactRoot" ID found, create one. reactRootID = ReactInstanceHandles.getReactRootID( globalMountPointCounter++ ); } containersByReactRootID[reactRootID] = container; return reactRootID; }, /** * Unmounts and destroys the React component rendered in the `container`. * * @param {DOMElement} container DOM element containing a React component. */ unmountAndReleaseReactRootNode: function(container) { var reactRootID = getReactRootID(container); var component = instanceByReactRootID[reactRootID]; // TODO: Consider throwing if no `component` was found. component.unmountComponentFromNode(container); delete instanceByReactRootID[reactRootID]; delete containersByReactRootID[reactRootID]; }, /** * Finds the container DOM element that contains React component to which the * supplied DOM `id` belongs. * * @param {string} id The ID of an element rendered by a React component. * @return {?DOMElement} DOM element that contains the `id`. */ findReactContainerForID: function(id) { var reatRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); // TODO: Consider throwing if `id` is not a valid React element ID. return containersByReactRootID[reatRootID]; }, /** * Given the ID of a DOM node rendered by a React component, finds the root * DOM node of the React component. * * @param {string} id ID of a DOM node in the React component. * @return {?DOMElement} Root DOM node of the React component. */ findReactRenderedDOMNodeSlow: function(id) { var reactRoot = ReactMount.findReactContainerForID(id); return ReactInstanceHandles.findComponentRoot(reactRoot, id); } }; module.exports = ReactMount; })() },{"./ReactEvent":20,"./ReactInstanceHandles":21,"./ReactEventTopLevelCallback":22,"./$":23}],6:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactDefaultInjection */ "use strict"; var ReactDOM = require("./ReactDOM"); var ReactDOMForm = require("./ReactDOMForm"); var DefaultEventPluginOrder = require("./DefaultEventPluginOrder"); var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin"); var EventPluginHub = require("./EventPluginHub"); var ReactInstanceHandles = require("./ReactInstanceHandles"); var SimpleEventPlugin = require("./SimpleEventPlugin"); function inject() { /** * Inject module for resolving DOM hierarchy and plugin ordering. */ EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder); EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles); /** * Two important event plugins included by default (without having to require * them). */ EventPluginHub.injection.injectEventPluginsByName({ 'SimpleEventPlugin': SimpleEventPlugin, 'EnterLeaveEventPlugin': EnterLeaveEventPlugin }); /* * This is a bit of a hack. We need to override the
element * to be a composite component because IE8 does not bubble or capture * submit to the top level. In order to make this work with our * dependency graph we need to inject it here. */ ReactDOM.injection.injectComponentClasses({ form: ReactDOMForm }); } module.exports = { inject: inject }; },{"./ReactDOM":4,"./ReactDOMForm":24,"./DefaultEventPluginOrder":25,"./EnterLeaveEventPlugin":26,"./EventPluginHub":27,"./ReactInstanceHandles":21,"./SimpleEventPlugin":28}],7:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactCurrentOwner */ "use strict"; /** * Keeps track of the current owner. * * The current owner is the component who should own any components that are * currently being constructed. */ var ReactCurrentOwner = { /** * @internal * @type {ReactComponent} */ current: null }; module.exports = ReactCurrentOwner; },{}],10:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule invariant */ /** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf style format and arguments to provide information about * what broke and what you were expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ function invariant(condition) { if (!condition) { throw new Error('Invariant Violation'); } } module.exports = invariant; if (true) { var invariantDev = function(condition, format, a, b, c, d, e, f) { if (format === undefined) { throw new Error('invariant requires an error message argument'); } if (!condition) { var args = [a, b, c, d, e, f]; var argIndex = 0; throw new Error( 'Invariant Violation: ' + format.replace(/%s/g, function() { return args[argIndex++]; }) ); } }; module.exports = invariantDev; } },{}],13:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule mixInto */ "use strict"; /** * Simply copies properties to the prototype. */ var mixInto = function(constructor, methodBag) { var methodName; for (methodName in methodBag) { if (!methodBag.hasOwnProperty(methodName)) { continue; } constructor.prototype[methodName] = methodBag[methodName]; } }; module.exports = mixInto; },{}],14:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ExecutionEnvironment */ /*jslint evil: true */ "use strict"; var canUseDOM = typeof window !== 'undefined'; /** * Simple, lightweight module assisting with the detection and context of * Worker. Helps avoid circular dependencies and allows code to reason about * whether or not they are in a Worker, even if they never include the main * `ReactWorker` dependency. */ var ExecutionEnvironment = { canUseDOM: canUseDOM, canUseWorkers: typeof Worker !== 'undefined', isInWorker: !canUseDOM, // For now, this is true - might change in the future. global: new Function('return this;')() }; module.exports = ExecutionEnvironment; })() },{}],19:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule objMapKeyVal */ "use strict"; /** * Behaves the same as `objMap` but invokes func with the key first, and value * second. Use `objMap` unless you need this special case. * Invokes func as: * * func(key, value, iteration) * * @param {?object} obj Object to map keys over * @param {!function} func Invoked for each key/val pair. * @param {?*} context * @return {?object} Result of mapping or null if obj is falsey */ function objMapKeyVal(obj, func, context) { if (!obj) { return null; } var i = 0; var ret = {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { ret[key] = func.call(context, key, obj[key], i++); } } return ret; } module.exports = objMapKeyVal; },{}],8:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactOwner */ "use strict"; var invariant = require("./invariant"); /** * ReactOwners are capable of storing references to owned components. * * All components are capable of //being// referenced by owner components, but * only ReactOwner components are capable of //referencing// owned components. * The named reference is known as a "ref". * * Refs are available when mounted and updated during reconciliation. * * var MyComponent = React.createClass({ * render: function() { * return ( *
* *
* ); * }, * handleClick: React.autoBind(function() { * this.refs.custom.handleClick(); * }), * componentDidMount: function() { * this.refs.custom.initialize(); * } * }); * * Refs should rarely be used. When refs are used, they should only be done to * control data that is not handled by React's data flow. * * @class ReactOwner */ var ReactOwner = { /** * @param {?object} object * @return {boolean} True if `object` is a valid owner. * @final */ isValidOwner: function(object) { return !!( object && typeof object.attachRef === 'function' && typeof object.detachRef === 'function' ); }, /** * Adds a component by ref to an owner component. * * @param {ReactComponent} component Component to reference. * @param {string} ref Name by which to refer to the component. * @param {ReactOwner} owner Component on which to record the ref. * @final * @internal */ addComponentAsRefTo: function(component, ref, owner) { invariant( ReactOwner.isValidOwner(owner), 'addComponentAsRefTo(...): Only a ReactOwner can have refs.' ); owner.attachRef(ref, component); }, /** * Removes a component by ref from an owner component. * * @param {ReactComponent} component Component to dereference. * @param {string} ref Name of the ref to remove. * @param {ReactOwner} owner Component on which the ref is recorded. * @final * @internal */ removeComponentAsRefFrom: function(component, ref, owner) { invariant( ReactOwner.isValidOwner(owner), 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs.' ); // Check that `component` is still the current ref because we do not want to // detach the ref if another component stole it. if (owner.refs[ref] === component) { owner.detachRef(ref); } }, /** * A ReactComponent must mix this in to have refs. * * @lends {ReactOwner.prototype} */ Mixin: { /** * Lazily allocates the refs object and stores `component` as `ref`. * * @param {string} ref Reference name. * @param {component} component Component to store as `ref`. * @final * @private */ attachRef: function(ref, component) { invariant( component.isOwnedBy(this), 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.', ref ); var refs = this.refs || (this.refs = {}); refs[ref] = component; }, /** * Detaches a reference name. * * @param {string} ref Name to dereference. * @final * @private */ detachRef: function(ref) { delete this.refs[ref]; } } }; module.exports = ReactOwner; },{"./invariant":10}],9:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactPropTransferer */ "use strict"; var emptyFunction = require("./emptyFunction"); var joinClasses = require("./joinClasses"); var merge = require("./merge"); /** * Creates a transfer strategy that will merge prop values using the supplied * `mergeStrategy`. If a prop was previously unset, this just sets it. * * @param {function} mergeStrategy * @return {function} */ function createTransferStrategy(mergeStrategy) { return function(props, key, value) { if (!props.hasOwnProperty(key)) { props[key] = value; } else { props[key] = mergeStrategy(props[key], value); } }; } /** * Transfer strategies dictate how props are transferred by `transferPropsTo`. */ var TransferStrategies = { /** * Never transfer the `ref` prop. */ ref: emptyFunction, /** * Transfer the `className` prop by merging them. */ className: createTransferStrategy(joinClasses), /** * Transfer the `style` prop (which is an object) by merging them. */ style: createTransferStrategy(merge) }; /** * ReactPropTransferer are capable of transferring props to another component * using a `transferPropsTo` method. * * @class ReactPropTransferer */ var ReactPropTransferer = { TransferStrategies: TransferStrategies, /** * @lends {ReactPropTransferer.prototype} */ Mixin: { /** * Transfer props from this component to a target component. * * Props that do not have an explicit transfer strategy will be transferred * only if the target component does not already have the prop set. * * This is usually used to pass down props to a returned root component. * * @param {ReactComponent} component Component receiving the properties. * @return {ReactComponent} The supplied `component`. * @final * @protected */ transferPropsTo: function(component) { var props = {}; for (var thatKey in component.props) { if (component.props.hasOwnProperty(thatKey)) { props[thatKey] = component.props[thatKey]; } } for (var thisKey in this.props) { if (!this.props.hasOwnProperty(thisKey)) { continue; } var transferStrategy = TransferStrategies[thisKey]; if (transferStrategy) { transferStrategy(props, thisKey, this.props[thisKey]); } else if (!props.hasOwnProperty(thisKey)) { props[thisKey] = this.props[thisKey]; } } component.props = props; return component; } } }; module.exports = ReactPropTransferer; },{"./emptyFunction":29,"./joinClasses":30,"./merge":12}],11:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule keyMirror */ "use strict"; var throwIf = require("./throwIf"); var NOT_OBJECT_ERROR = 'NOT_OBJECT_ERROR'; if (true) { NOT_OBJECT_ERROR = 'keyMirror only works on objects'; } /** * Utility for constructing enums with keys being equal to the associated * values, even when using advanced key crushing. This is useful for debugging, * but also for using the values themselves as lookups into the enum. * Example: * var COLORS = keyMirror({blue: null, red: null}); * var myColor = COLORS.blue; * var isColorValid = !!COLORS[myColor] * The last line could not be performed if the values of the generated enum were * not equal to their keys. * Input: {key1: val1, key2: val2} * Output: {key1: key1, key2: key2} */ var keyMirror = function(obj) { var ret = {}; var key; throwIf(!(obj instanceof Object) || Array.isArray(obj), NOT_OBJECT_ERROR); for (key in obj) { if (!obj.hasOwnProperty(key)) { continue; } ret[key] = key; } return ret; }; module.exports = keyMirror; },{"./throwIf":31}],12:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule merge */ "use strict"; var mergeInto = require("./mergeInto"); /** * Shallow merges two structures into a return value, without mutating either. * * @param {?object} one Optional object with properties to merge from. * @param {?object} two Optional object with properties to merge from. * @return {object} The shallow extension of one by two. */ var merge = function(one, two) { var result = {}; mergeInto(result, one); mergeInto(result, two); return result; }; module.exports = merge; },{"./mergeInto":18}],15:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactDOMIDOperations * @typechecks */ /*jslint evil: true */ "use strict"; var CSSPropertyOperations = require("./CSSPropertyOperations"); var DOMChildrenOperations = require("./DOMChildrenOperations"); var DOMPropertyOperations = require("./DOMPropertyOperations"); var ReactDOMNodeCache = require("./ReactDOMNodeCache"); var getTextContentAccessor = require("./getTextContentAccessor"); var invariant = require("./invariant"); /** * Errors for properties that should not be updated with `updatePropertyById()`. * * @type {object} * @private */ var INVALID_PROPERTY_ERRORS = { content: '`content` must be set using `updateTextContentByID()`.', dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', style: '`style` must be set using `updateStylesByID()`.' }; /** * The DOM property to use when setting text content. * * @type {string} * @private */ var textContentAccessor = getTextContentAccessor() || 'NA'; /** * Operations used to process updates to DOM nodes. This is made injectable via * `ReactComponent.DOMIDOperations`. */ var ReactDOMIDOperations = { /** * Updates a DOM node with new property values. This should only be used to * update DOM properties in `DOMProperty`. * * @param {string} id ID of the node to update. * @param {string} name A valid property name, see `DOMProperty`. * @param {*} value New value of the property. * @internal */ updatePropertyByID: function(id, name, value) { var node = ReactDOMNodeCache.getCachedNodeByID(id); invariant( !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name] ); DOMPropertyOperations.setValueForProperty(node, name, value); }, /** * This should almost never be used instead of `updatePropertyByID()` due to * the extra object allocation required by the API. That said, this is useful * for batching up several operations across worker thread boundaries. * * @param {string} id ID of the node to update. * @param {object} properties A mapping of valid property names. * @internal * @see {ReactDOMIDOperations.updatePropertyByID} */ updatePropertiesByID: function(id, properties) { for (var name in properties) { if (!properties.hasOwnProperty(name)) { continue; } ReactDOMIDOperations.updatePropertiesByID(id, name, properties[name]); } }, /** * Updates a DOM node with new style values. * * @param {string} id ID of the node to update. * @param {object} styles Mapping from styles to values. * @internal */ updateStylesByID: function(id, styles) { var node = ReactDOMNodeCache.getCachedNodeByID(id); CSSPropertyOperations.setValueForStyles(node, styles); }, /** * Updates a DOM node's innerHTML set by `props.dangerouslySetInnerHTML`. * * @param {string} id ID of the node to update. * @param {object} html An HTML object with the `__html` property. * @internal */ updateInnerHTMLByID: function(id, html) { var node = ReactDOMNodeCache.getCachedNodeByID(id); // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces. // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html node.innerHTML = (html && html.__html || '').replace(/^ /g, ' '); }, /** * Updates a DOM node's text content set by `props.content`. * * @param {string} id ID of the node to update. * @param {string} content Text content. * @internal */ updateTextContentByID: function(id, content) { var node = ReactDOMNodeCache.getCachedNodeByID(id); node[textContentAccessor] = content; }, /** * Replaces a DOM node that exists in the document with markup. * * @param {string} id ID of child to be replaced. * @param {string} markup Dangerous markup to inject in place of child. * @internal * @see {Danger.dangerouslyReplaceNodeWithMarkup} */ dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { var node = ReactDOMNodeCache.getCachedNodeByID(id); DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); ReactDOMNodeCache.purgeEntireCache(); }, /** * TODO: We only actually *need* to purge the cache when we remove elements. * Detect if any elements were removed instead of blindly purging. */ manageChildrenByParentID: function(parentID, domOperations) { var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); DOMChildrenOperations.manageChildren(parent, domOperations); ReactDOMNodeCache.purgeEntireCache(); }, setTextNodeValueAtIndexByParentID: function(parentID, index, value) { var parent = ReactDOMNodeCache.getCachedNodeByID(parentID); DOMChildrenOperations.setTextNodeValueAtIndex(parent, index, value); } }; module.exports = ReactDOMIDOperations; })() },{"./CSSPropertyOperations":32,"./DOMChildrenOperations":33,"./DOMPropertyOperations":34,"./ReactDOMNodeCache":35,"./getTextContentAccessor":36,"./invariant":10}],16:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactReconcileTransaction * @typechecks */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var PooledClass = require("./PooledClass"); var ReactEvent = require("./ReactEvent"); var ReactInputSelection = require("./ReactInputSelection"); var ReactOnDOMReady = require("./ReactOnDOMReady"); var Transaction = require("./Transaction"); var mixInto = require("./mixInto"); /** * Ensures that, when possible, the selection range (currently selected text * input) is not disturbed by performing the transaction. */ var SELECTION_RESTORATION = { /** * @return {Selection} Selection information. */ initialize: ReactInputSelection.getSelectionInformation, /** * @param {Selection} sel Selection information returned from `initialize`. */ close: ReactInputSelection.restoreSelection }; /** * Suppresses events (blur/focus) that could be inadvertently dispatched due to * high level DOM manipulations (like temporarily removing a text input from the * DOM). */ var EVENT_SUPPRESSION = { /** * @return {boolean} The enabled status of `ReactEvent` before the * reconciliation. */ initialize: function() { var currentlyEnabled = ReactEvent.isEnabled(); ReactEvent.setEnabled(false); return currentlyEnabled; }, /** * @param {boolean} previouslyEnabled The enabled status of `ReactEvent` * before the reconciliation occured. `close` restores the previous value. */ close: function(previouslyEnabled) { ReactEvent.setEnabled(previouslyEnabled); } }; /** * Provides a `ReactOnDOMReady` queue for collecting `onDOMReady` callbacks * during the performing of the transaction. */ var ON_DOM_READY_QUEUEING = { /** * Initializes the internal `onDOMReady` queue. */ initialize: function() { this.reactOnDOMReady.reset(); }, /** * After DOM is flushed, invoke all registered `onDOMReady` callbacks. */ close: function() { this.reactOnDOMReady.notifyAll(); } }; /** * Executed within the scope of the `Transaction` instance. Consider these as * being member methods, but with an implied ordering while being isolated from * each other. */ var TRANSACTION_WRAPPERS = [ SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING ]; /** * Currently: * - The order that these are listed in the transaction is critical: * - Suppresses events. * - Restores selection range. * * Future: * - Restore document/overflow scroll positions that were unintentionally * modified via DOM insertions above the top viewport boundary. * - Implement/integrate with customized constraint based layout system and keep * track of which dimensions must be remeasured. * * @class ReactReconcileTransaction */ function ReactReconcileTransaction() { this.reinitializeTransaction(); this.reactOnDOMReady = ReactOnDOMReady.getPooled(null); } var Mixin = { /** * @see Transaction * @abstract * @final * @return {array} List of operation wrap proceedures. * TODO: convert to array */ getTransactionWrappers: function() { if (ExecutionEnvironment.canUseDOM) { return TRANSACTION_WRAPPERS; } else { return []; } }, /** * @return {object} The queue to collect `onDOMReady` callbacks with. * TODO: convert to ReactOnDOMReady */ getReactOnDOMReady: function() { return this.reactOnDOMReady; }, /** * `PooledClass` looks for this, and will invoke this before allowing this * instance to be resused. */ destructor: function() { ReactOnDOMReady.release(this.reactOnDOMReady); this.reactOnDOMReady = null; } }; mixInto(ReactReconcileTransaction, Transaction.Mixin); mixInto(ReactReconcileTransaction, Mixin); PooledClass.addPoolingTo(ReactReconcileTransaction); module.exports = ReactReconcileTransaction; },{"./ExecutionEnvironment":14,"./PooledClass":37,"./ReactEvent":20,"./ReactInputSelection":38,"./ReactOnDOMReady":39,"./Transaction":40,"./mixInto":13}],17:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactNativeComponent * @typechecks */ "use strict"; var CSSPropertyOperations = require("./CSSPropertyOperations"); var DOMPropertyOperations = require("./DOMPropertyOperations"); var ReactComponent = require("./ReactComponent"); var ReactEvent = require("./ReactEvent"); var ReactMultiChild = require("./ReactMultiChild"); var escapeTextForBrowser = require("./escapeTextForBrowser"); var flattenChildren = require("./flattenChildren"); var invariant = require("./invariant"); var keyOf = require("./keyOf"); var merge = require("./merge"); var mixInto = require("./mixInto"); var putListener = ReactEvent.putListener; var registrationNames = ReactEvent.registrationNames; // For quickly matching children type, to test if can be treated as content. var CONTENT_TYPES = {'string': true, 'number': true}; var CONTENT = keyOf({content: null}); var DANGEROUSLY_SET_INNER_HTML = keyOf({dangerouslySetInnerHTML: null}); var STYLE = keyOf({style: null}); /** * @param {?object} props */ function assertValidProps(props) { if (!props) { return; } // Note the use of `!=` which checks for null or undefined. var hasChildren = props.children != null ? 1 : 0; var hasContent = props.content != null ? 1 : 0; var hasInnerHTML = props.dangerouslySetInnerHTML != null ? 1 : 0; invariant( hasChildren + hasContent + hasInnerHTML <= 1, 'Can only set one of `children`, `props.content`, or ' + '`props.dangerouslySetInnerHTML`.' ); invariant( props.style == null || typeof props.style === 'object', 'The `style` prop expects a mapping from style properties to values, ' + 'not a string.' ); } /** * @constructor ReactNativeComponent * @extends ReactComponent * @extends ReactMultiChild */ function ReactNativeComponent(tag, omitClose) { this._tagOpen = '<' + tag + ' '; this._tagClose = omitClose ? '' : ''; this.tagName = tag.toUpperCase(); } ReactNativeComponent.Mixin = { /** * Generates root tag markup then recurses. This method has side effects and * is not idempotent. * * @internal * @param {string} rootID The root DOM ID for this node. * @param {ReactReconcileTransaction} transaction * @return {string} The computed markup. */ mountComponent: function(rootID, transaction) { ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); assertValidProps(this.props); return ( this._createOpenTagMarkup() + this._createContentMarkup(transaction) + this._tagClose ); }, /** * Creates markup for the open tag and all attributes. * * This method has side effects because events get registered. * * Iterating over object properties is faster than iterating over arrays. * @see http://jsperf.com/obj-vs-arr-iteration * * @private * @return {string} Markup of opening tag. */ _createOpenTagMarkup: function() { var props = this.props; var ret = this._tagOpen; for (var propKey in props) { if (!props.hasOwnProperty(propKey)) { continue; } var propValue = props[propKey]; if (propValue == null) { continue; } if (registrationNames[propKey]) { putListener(this._rootNodeID, propKey, propValue); } else { if (propKey === STYLE) { if (propValue) { propValue = props.style = merge(props.style); } propValue = CSSPropertyOperations.createMarkupForStyles(propValue); } var markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue); if (markup) { ret += ' ' + markup; } } } return ret + ' id="' + this._rootNodeID + '">'; }, /** * Creates markup for the content between the tags. * * @private * @param {ReactReconcileTransaction} transaction * @return {string} Content markup. */ _createContentMarkup: function(transaction) { // Intentional use of != to avoid catching zero/false. var innerHTML = this.props.dangerouslySetInnerHTML; if (innerHTML != null) { if (innerHTML.__html != null) { return innerHTML.__html; } } else { var contentToUse = this.props.content != null ? this.props.content : CONTENT_TYPES[typeof this.props.children] ? this.props.children : null; var childrenToUse = contentToUse != null ? null : this.props.children; if (contentToUse != null) { return escapeTextForBrowser(contentToUse); } else if (childrenToUse != null) { return this.mountMultiChild( flattenChildren(childrenToUse), transaction ); } } return ''; }, /** * Controls a native DOM component after it has already been allocated and * attached to the DOM. Reconciles the root DOM node, then recurses. * * @internal * @param {object} nextProps * @param {ReactReconcileTransaction} transaction */ receiveProps: function(nextProps, transaction) { invariant( this._rootNodeID, 'Trying to control a native dom element without a backing id' ); assertValidProps(nextProps); ReactComponent.Mixin.receiveProps.call(this, nextProps, transaction); this._updateDOMProperties(nextProps); this._updateDOMChildren(nextProps, transaction); this.props = nextProps; }, /** * Reconciles the properties by detecting differences in property values and * updating the DOM as necessary. This function is probably the single most * critical path for performance optimization. * * TODO: Benchmark whether checking for changed values in memory actually * improves performance (especially statically positioned elements). * TODO: Benchmark the effects of putting this at the top since 99% of props * do not change for a given reconciliation. * TODO: Benchmark areas that can be improved with caching. * * @private * @param {object} nextProps */ _updateDOMProperties: function(nextProps) { var lastProps = this.props; for (var propKey in nextProps) { var nextProp = nextProps[propKey]; var lastProp = lastProps[propKey]; if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) { continue; } if (propKey === STYLE) { if (nextProp) { nextProp = nextProps.style = merge(nextProp); } var styleUpdates; for (var styleName in nextProp) { if (!nextProp.hasOwnProperty(styleName)) { continue; } if (!lastProp || lastProp[styleName] !== nextProp[styleName]) { if (!styleUpdates) { styleUpdates = {}; } styleUpdates[styleName] = nextProp[styleName]; } } if (styleUpdates) { ReactComponent.DOMIDOperations.updateStylesByID( this._rootNodeID, styleUpdates ); } } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { var lastHtml = lastProp && lastProp.__html; var nextHtml = nextProp && nextProp.__html; if (lastHtml !== nextHtml) { ReactComponent.DOMIDOperations.updateInnerHTMLByID( this._rootNodeID, nextProp ); } } else if (propKey === CONTENT) { ReactComponent.DOMIDOperations.updateTextContentByID( this._rootNodeID, '' + nextProp ); } else if (registrationNames[propKey]) { putListener(this._rootNodeID, propKey, nextProp); } else { ReactComponent.DOMIDOperations.updatePropertyByID( this._rootNodeID, propKey, nextProp ); } } }, /** * Reconciles the children with the various properties that affect the * children content. * * @param {object} nextProps * @param {ReactReconcileTransaction} transaction */ _updateDOMChildren: function(nextProps, transaction) { var thisPropsContentType = typeof this.props.content; var thisPropsContentEmpty = this.props.content == null || thisPropsContentType === 'boolean'; var nextPropsContentType = typeof nextProps.content; var nextPropsContentEmpty = nextProps.content == null || nextPropsContentType === 'boolean'; var lastUsedContent = !thisPropsContentEmpty ? this.props.content : CONTENT_TYPES[typeof this.props.children] ? this.props.children : null; var contentToUse = !nextPropsContentEmpty ? nextProps.content : CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null; // Note the use of `!=` which checks for null or undefined. var lastUsedChildren = lastUsedContent != null ? null : this.props.children; var childrenToUse = contentToUse != null ? null : nextProps.children; if (contentToUse != null) { var childrenRemoved = lastUsedChildren != null && childrenToUse == null; if (childrenRemoved) { this.updateMultiChild(null, transaction); } if (lastUsedContent !== contentToUse) { ReactComponent.DOMIDOperations.updateTextContentByID( this._rootNodeID, '' + contentToUse ); } } else { var contentRemoved = lastUsedContent != null && contentToUse == null; if (contentRemoved) { ReactComponent.DOMIDOperations.updateTextContentByID( this._rootNodeID, '' ); } this.updateMultiChild(flattenChildren(nextProps.children), transaction); } }, /** * Destroys all event registrations for this instance. Does not remove from * the DOM. That must be done by the parent. * * @internal */ unmountComponent: function() { ReactComponent.Mixin.unmountComponent.call(this); this.unmountMultiChild(); ReactEvent.deleteAllListeners(this._rootNodeID); } }; mixInto(ReactNativeComponent, ReactComponent.Mixin); mixInto(ReactNativeComponent, ReactNativeComponent.Mixin); mixInto(ReactNativeComponent, ReactMultiChild.Mixin); module.exports = ReactNativeComponent; },{"./CSSPropertyOperations":32,"./DOMPropertyOperations":34,"./ReactComponent":3,"./ReactEvent":20,"./ReactMultiChild":41,"./escapeTextForBrowser":42,"./flattenChildren":43,"./invariant":10,"./keyOf":44,"./merge":12,"./mixInto":13}],18:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule mergeInto * @typechecks */ "use strict"; var mergeHelpers = require("./mergeHelpers"); var checkMergeObjectArg = mergeHelpers.checkMergeObjectArg; /** * Shallow merges two structures by mutating the first parameter. * * @param {object} one Object to be merged into. * @param {?object} two Optional object with properties to merge from. */ function mergeInto(one, two) { checkMergeObjectArg(one); if (two != null) { checkMergeObjectArg(two); for (var key in two) { if (!two.hasOwnProperty(key)) { continue; } one[key] = two[key]; } } } module.exports = mergeInto; },{"./mergeHelpers":45}],20:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactEvent */ "use strict"; var BrowserEnv = require("./BrowserEnv"); var EventConstants = require("./EventConstants"); var EventPluginHub = require("./EventPluginHub"); var ExecutionEnvironment = require("./ExecutionEnvironment"); var NormalizedEventListener = require("./NormalizedEventListener"); var invariant = require("./invariant"); var isEventSupported = require("./isEventSupported"); var registrationNames = EventPluginHub.registrationNames; var topLevelTypes = EventConstants.topLevelTypes; var listen = NormalizedEventListener.listen; var capture = NormalizedEventListener.capture; /** * `ReactEvent` is used to attach top-level event listeners. For example: * * ReactEvent.putListener('myID', 'onClick', myFunction); * * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'. */ /** * Overview of React and the event system: * * . * +-------------+ . * | DOM | . * +-------------+ . +-----------+ * + . +--------+|SimpleEvent| * | . | |Plugin | * +-----|-------+ . v +-----------+ * | | | . +--------------+ +------------+ * | +------------.---->|EventPluginHub| | Event | * | | . | | +-----------+ | Propagators| * | ReactEvent | . | | |TapEvent | |------------| * | | . | |<---+|Plugin | |other plugin| * | +------------.---------+ | +-----------+ | utilities | * | | | . | | | +------------+ * | | | . +---|----------+ * | | | . | ^ +-----------+ * | | | . | | |Enter/Leave| * +-----| ------+ . | +-------+|Plugin | * | . v +-----------+ * + . +--------+ * +-------------+ . |callback| * | application | . |registry| * |-------------| . +--------+ * | | . * | | . * | | . * | | . * +-------------+ . * . * React Core . General Purpose Event Plugin System */ /** * We listen for bubbled touch events on the document object. * * Firefox v8.01 (and possibly others) exhibited strange behavior when mounting * `onmousemove` events at some node that was not the document element. The * symptoms were that if your mouse is not moving over something contained * within that mount point (for example on the background) the top-level * listeners for `onmousemove` won't be called. However, if you register the * `mousemove` on the document object, then it will of course catch all * `mousemove`s. This along with iOS quirks, justifies restricting top-level * listeners to the document object only, at least for these movement types of * events and possibly all events. * * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html * * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but * they bubble to document. * * @see http://www.quirksmode.org/dom/events/keys.html. */ var _isListening = false; var EVENT_LISTEN_MISUSE; var WORKER_DISABLE; if (true) { EVENT_LISTEN_MISUSE = 'You must register listeners at the top of the document, only once - ' + 'and only in the main UI thread of a browser - if you are attempting ' + 'listen in a worker, the framework is probably doing something wrong ' + 'and you should report this immediately.'; WORKER_DISABLE = 'Cannot disable event listening in Worker thread. This is likely a ' + 'bug in the framework. Please report immediately.'; } /** * Traps top-level events that bubble. Delegates to the main dispatcher * `handleTopLevel` after performing some basic normalization via * `TopLevelCallbackCreator.createTopLevelCallback`. */ function trapBubbledEvent(topLevelType, handlerBaseName, onWhat) { listen( onWhat, handlerBaseName, ReactEvent.TopLevelCallbackCreator.createTopLevelCallback(topLevelType) ); } /** * Traps a top-level event by using event capturing. */ function trapCapturedEvent(topLevelType, handlerBaseName, onWhat) { capture( onWhat, handlerBaseName, ReactEvent.TopLevelCallbackCreator.createTopLevelCallback(topLevelType) ); } /** * Listens to document scroll and window resize events that may change the * document scroll values. We store those results so as to discourage * application code from asking the DOM itself which could trigger additional * reflows. */ function registerDocumentScrollListener() { listen(window, 'scroll', function(nativeEvent) { if (nativeEvent.target === window) { BrowserEnv.refreshAuthoritativeScrollValues(); } }); } function registerDocumentResizeListener() { listen(window, 'resize', function(nativeEvent) { if (nativeEvent.target === window) { BrowserEnv.refreshAuthoritativeScrollValues(); } }); } /** * Summary of `ReactEvent` event handling: * * - We trap low level 'top-level' events. * * - We dedupe cross-browser event names into these 'top-level types' so that * `DOMMouseScroll` or `mouseWheel` both become `topMouseWheel`. * * - At this point we have native browser events with the top-level type that * was used to catch it at the top-level. * * - We continuously stream these native events (and their respective top-level * types) to the event plugin system `EventPluginHub` and ask the plugin * system if it was able to extract `AbstractEvent` objects. `AbstractEvent` * objects are the events that applications actually deal with - they are not * native browser events but cross-browser wrappers. * * - When returning the `AbstractEvent` objects, `EventPluginHub` will make * sure each abstract event is annotated with "dispatches", which are the * sequence of listeners (and IDs) that care about the event. * * - These `AbstractEvent` objects are fed back into the event plugin system, * which in turn executes these dispatches. * * @private */ function listenAtTopLevel(touchNotMouse) { invariant( !_isListening, 'listenAtTopLevel(...): Cannot setup top-level listener more than once.' ); var mountAt = document; registerDocumentScrollListener(); registerDocumentResizeListener(); trapBubbledEvent(topLevelTypes.topMouseOver, 'mouseover', mountAt); trapBubbledEvent(topLevelTypes.topMouseDown, 'mousedown', mountAt); trapBubbledEvent(topLevelTypes.topMouseUp, 'mouseup', mountAt); trapBubbledEvent(topLevelTypes.topMouseMove, 'mousemove', mountAt); trapBubbledEvent(topLevelTypes.topMouseOut, 'mouseout', mountAt); trapBubbledEvent(topLevelTypes.topClick, 'click', mountAt); trapBubbledEvent(topLevelTypes.topDoubleClick, 'dblclick', mountAt); trapBubbledEvent(topLevelTypes.topMouseWheel, 'mousewheel', mountAt); if (touchNotMouse) { trapBubbledEvent(topLevelTypes.topTouchStart, 'touchstart', mountAt); trapBubbledEvent(topLevelTypes.topTouchEnd, 'touchend', mountAt); trapBubbledEvent(topLevelTypes.topTouchMove, 'touchmove', mountAt); trapBubbledEvent(topLevelTypes.topTouchCancel, 'touchcancel', mountAt); } trapBubbledEvent(topLevelTypes.topKeyUp, 'keyup', mountAt); trapBubbledEvent(topLevelTypes.topKeyPress, 'keypress', mountAt); trapBubbledEvent(topLevelTypes.topKeyDown, 'keydown', mountAt); trapBubbledEvent(topLevelTypes.topChange, 'change', mountAt); trapBubbledEvent( topLevelTypes.topDOMCharacterDataModified, 'DOMCharacterDataModified', mountAt ); // Firefox needs to capture a different mouse scroll event. // @see http://www.quirksmode.org/dom/events/tests/scroll.html trapBubbledEvent(topLevelTypes.topMouseWheel, 'DOMMouseScroll', mountAt); // IE < 9 doesn't support capturing so just trap the bubbled event there. if (isEventSupported('scroll', true)) { trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt); } else { trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window); } if (isEventSupported('focus', true)) { trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt); trapCapturedEvent(topLevelTypes.topBlur, 'blur', mountAt); } else if (isEventSupported('focusin')) { // IE has `focusin` and `focusout` events which bubble. // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html trapBubbledEvent(topLevelTypes.topFocus, 'focusin', mountAt); trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt); } } /** * This is the heart of `ReactEvent`. It simply streams the top-level native * events to `EventPluginHub`. * * @param {object} topLevelType Record from `EventConstants`. * @param {Event} nativeEvent A Standard Event with fixed `target` property. * @param {DOMElement} renderedTarget Element of interest to the framework. * @param {string} renderedTargetID string ID of `renderedTarget`. * @internal */ function handleTopLevel( topLevelType, nativeEvent, renderedTargetID, renderedTarget) { var abstractEvents = EventPluginHub.extractAbstractEvents( topLevelType, nativeEvent, renderedTargetID, renderedTarget ); // The event queue being processed in the same cycle allows preventDefault. EventPluginHub.enqueueAbstractEvents(abstractEvents); EventPluginHub.processAbstractEventQueue(); } function setEnabled(enabled) { invariant( ExecutionEnvironment.canUseDOM, 'setEnabled(...): Cannot toggle event listening in a Worker thread. This ' + 'is likely a bug in the framework. Please report immediately.' ); ReactEvent.TopLevelCallbackCreator.setEnabled(enabled); } function isEnabled() { return ReactEvent.TopLevelCallbackCreator.isEnabled(); } /** * Ensures that top-level event delegation listeners are listening at `mountAt`. * There are issues with listening to both touch events and mouse events on the * top-level, so we make the caller choose which one to listen to. (If there's a * touch top-level listeners, anchors don't receive clicks for some reason, and * only in some cases). * * @param {boolean} touchNotMouse Listen to touch events instead of mouse. * @param {object} TopLevelCallbackCreator Module that can create top-level * callback handlers. * @internal */ function ensureListening(touchNotMouse, TopLevelCallbackCreator) { invariant( ExecutionEnvironment.canUseDOM, 'ensureListening(...): Cannot toggle event listening in a Worker thread. ' + 'This is likely a bug in the framework. Please report immediately.' ); if (!_isListening) { ReactEvent.TopLevelCallbackCreator = TopLevelCallbackCreator; listenAtTopLevel(touchNotMouse); _isListening = true; } } var ReactEvent = { TopLevelCallbackCreator: null, // Injectable callback creator. handleTopLevel: handleTopLevel, setEnabled: setEnabled, isEnabled: isEnabled, ensureListening: ensureListening, registrationNames: registrationNames, putListener: EventPluginHub.putListener, getListener: EventPluginHub.getListener, deleteAllListeners: EventPluginHub.deleteAllListeners, trapBubbledEvent: trapBubbledEvent, trapCapturedEvent: trapCapturedEvent }; module.exports = ReactEvent; },{"./BrowserEnv":46,"./EventConstants":47,"./EventPluginHub":27,"./ExecutionEnvironment":14,"./NormalizedEventListener":48,"./invariant":10,"./isEventSupported":49}],21:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactInstanceHandles */ "use strict"; var getDOMNodeID = require("./getDOMNodeID"); var invariant = require("./invariant"); var SEPARATOR = '.'; var SEPARATOR_LENGTH = SEPARATOR.length; /** * Maximum depth of traversals before we consider the possibility of a bad ID. */ var MAX_TREE_DEPTH = 100; /** * Checks if a character in the supplied ID is a separator or the end. * * @param {string} id A React DOM ID. * @param {number} index Index of the character to check. * @return {boolean} True if the character is a separator or end of the ID. * @private */ function isMarker(id, index) { return id.charAt(index) === SEPARATOR || index === id.length; } /** * Checks if the supplied string is a valid React DOM ID. * * @param {string} id A React DOM ID, maybe. * @return {boolean} True if the string is a valid React DOM ID. * @private */ function isValidID(id) { return id === '' || ( id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR ); } /** * True if the supplied `node` is rendered by React. * * @param {DOMElement} node DOM Element to check. * @return {boolean} True if the DOM Element appears to be rendered by React. * @private */ function isRenderedByReact(node) { var id = getDOMNodeID(node); return id && id.charAt(0) === SEPARATOR; } /** * Gets the parent ID of the supplied React DOM ID, `id`. * * @param {string} id ID of a component. * @return {string} ID of the parent, or an empty string. * @private */ function parentID(id) { return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : ''; } /** * Traverses the parent path between two IDs (either up or down). The IDs must * not be the same, and there must exist a parent path between them. * * @param {?string} start ID at which to start traversal. * @param {?string} stop ID at which to end traversal. * @param {function} cb Callback to invoke each ID with. * @param {?boolean} skipFirst Whether or not to skip the first node. * @param {?boolean} skipLast Whether or not to skip the last node. * @private */ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) { start = start || ''; stop = stop || ''; invariant( start !== stop, 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.', start ); var ancestorID = ReactInstanceHandles.getFirstCommonAncestorID(start, stop); var traverseUp = ancestorID === stop; invariant( traverseUp || ancestorID === start, 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' + 'not have a parent path.', start, stop ); // Traverse from `start` to `stop` one depth at a time. var depth = 0; var traverse = traverseUp ? parentID : ReactInstanceHandles.nextDescendantID; for (var id = start; /* until break */; id = traverse(id, stop)) { if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) { cb(id, traverseUp, arg); } if (id === stop) { // Only break //after// visiting `stop`. break; } invariant( depth++ < MAX_TREE_DEPTH, 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' + 'traversing the React DOM ID tree. This may be due to malformed IDs: %s', start, stop ); } } /** * Manages the IDs assigned to DOM representations of React components. This * uses a specific scheme in order to traverse the DOM efficiently (e.g. in * order to simulate events). * * @internal */ var ReactInstanceHandles = { separator: SEPARATOR, /** * Traverses up the ancestors of the supplied node to find a node that is a * DOM representation of a React component. * * @param {DOMElement} node * @return {?DOMElement} * @internal */ getFirstReactDOM: function(node) { var current = node; while (current && current.parentNode !== current) { if (isRenderedByReact(current)) { return current; } current = current.parentNode; } return null; }, /** * Finds a node with the supplied `id` inside of the supplied `ancestorNode`. * Exploits the ID naming scheme to perform the search quickly. * * @param {DOMElement} ancestorNode Search from this root. * @pararm {string} id ID of the DOM representation of the component. * @return {?DOMElement} DOM element with the supplied `id`, if one exists. * @internal */ findComponentRoot: function(ancestorNode, id) { var child = ancestorNode.firstChild; while (child) { if (id === child.id) { return child; } else if (id.indexOf(child.id) === 0) { return ReactInstanceHandles.findComponentRoot(child, id); } child = child.nextSibling; } // Effectively: return null; }, /** * Gets the nearest common ancestor ID of two IDs. * * Using this ID scheme, the nearest common ancestor ID is the longest common * prefix of the two IDs that immediately preceded a "marker" in both strings. * * @param {string} oneID * @param {string} twoID * @return {string} Nearest common ancestor ID, or the empty string if none. * @internal */ getFirstCommonAncestorID: function(oneID, twoID) { var minLength = Math.min(oneID.length, twoID.length); if (minLength === 0) { return ''; } var lastCommonMarkerIndex = 0; // Use `<=` to traverse until the "EOL" of the shorter string. for (var i = 0; i <= minLength; i++) { if (isMarker(oneID, i) && isMarker(twoID, i)) { lastCommonMarkerIndex = i; } else if (oneID.charAt(i) !== twoID.charAt(i)) { break; } } var longestCommonID = oneID.substr(0, lastCommonMarkerIndex); invariant( isValidID(longestCommonID), 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s', oneID, twoID, longestCommonID ); return longestCommonID; }, /** * Creates a DOM ID to use when mounting React components. * * @param {number} mountPointCount The count of React renders so far. * @return {string} React root ID. * @internal */ getReactRootID: function(mountPointCount) { return '.reactRoot[' + mountPointCount + ']'; }, /** * Gets the DOM ID of the React component that is the root of the tree that * contains the React component with the supplied DOM ID. * * @param {string} id DOM ID of a React component. * @return {string} DOM ID of the React component that is the root. * @internal */ getReactRootIDFromNodeID: function(id) { var regexResult = /\.reactRoot\[[^\]]+\]/.exec(id); return regexResult && regexResult[0]; }, /** * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that * should would receive a `mouseEnter` or `mouseLeave` event. * * NOTE: Does not invoke the callback on the nearest common ancestor because * nothing "entered" or "left" that element. * * @param {string} leaveID ID being left. * @param {string} enterID ID being entered. * @param {function} cb Callback to invoke on each entered/left ID. * @param {*} upArg Argument to invoke the callback with on left IDs. * @param {*} downArg Argument to invoke the callback with on entered IDs. * @internal */ traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) { var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID( leaveID, enterID ); if (longestCommonID !== leaveID) { traverseParentPath(leaveID, longestCommonID, cb, upArg, false, true); } if (longestCommonID !== enterID) { traverseParentPath(longestCommonID, enterID, cb, downArg, true, false); } }, /** * Simulates the traversal of a two-phase, capture/bubble event dispatch. * * NOTE: This traversal happens on IDs without touching the DOM. * * @param {string} targetID ID of the target node. * @param {function} cb Callback to invoke. * @param {*} arg Argument to invoke the callback with. * @internal */ traverseTwoPhase: function(targetID, cb, arg) { if (targetID) { traverseParentPath('', targetID, cb, arg, true, false); traverseParentPath(targetID, '', cb, arg, false, true); } }, /** * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the * supplied `destinationID`. If they are equal, the ID is returned. * * @param {string} ancestorID ID of an ancestor node of `destinationID`. * @param {string} destinationID ID of the destination node. * @return {string} Next ID on the path from `ancestorID` to `destinationID`. * @internal */ nextDescendantID: function(ancestorID, destinationID) { invariant( isValidID(ancestorID) && isValidID(destinationID), 'nextDescendantID(%s, %s): Received an invalid React DOM ID.', ancestorID, destinationID ); var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID( ancestorID, destinationID ); invariant( longestCommonID === ancestorID, 'nextDescendantID(...): React has made an invalid assumption about the ' + 'DOM hierarchy. Expected `%s` to be an ancestor of `%s`.', ancestorID, destinationID ); if (ancestorID === destinationID) { return ancestorID; } // Skip over the ancestor and the immediate separator. Traverse until we hit // another separator or we reach the end of `destinationID`. var start = ancestorID.length + SEPARATOR_LENGTH; for (var i = start; i < destinationID.length; i++) { if (isMarker(destinationID, i)) { break; } } return destinationID.substr(0, i); } }; module.exports = ReactInstanceHandles; },{"./getDOMNodeID":50,"./invariant":10}],22:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactEventTopLevelCallback */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var ReactEvent = require("./ReactEvent"); var ReactInstanceHandles = require("./ReactInstanceHandles"); var getDOMNodeID = require("./getDOMNodeID"); var _topLevelListenersEnabled = true; var ReactEventTopLevelCallback = { /** * @param {boolean} enabled Whether or not all callbacks that have ever been * created with this module should be enabled. */ setEnabled: function(enabled) { _topLevelListenersEnabled = !!enabled; }, isEnabled: function() { return _topLevelListenersEnabled; }, /** * For a given `topLevelType`, creates a callback that could be added as a * listener to the document. That top level callback will simply fix the * native events before invoking `handleTopLevel`. * * - Raw native events cannot be trusted to describe their targets correctly * so we expect that the argument to the nested function has already been * fixed. But the `target` property may not be something of interest to * React, so we find the most suitable target. But even at that point, DOM * Elements (the target ) can't be trusted to describe their IDs correctly * so we obtain the ID in a reliable manner and pass it to * `handleTopLevel`. The target/id that we found to be relevant to our * framework are called `renderedTarget`/`renderedTargetID` respectively. */ createTopLevelCallback: function(topLevelType) { return function(fixedNativeEvent) { if (!_topLevelListenersEnabled) { return; } var renderedTarget = ReactInstanceHandles.getFirstReactDOM( fixedNativeEvent.target ) || ExecutionEnvironment.global; var renderedTargetID = getDOMNodeID(renderedTarget); var event = fixedNativeEvent; var target = renderedTarget; ReactEvent.handleTopLevel(topLevelType, event, renderedTargetID, target); }; } }; module.exports = ReactEventTopLevelCallback; })() },{"./ExecutionEnvironment":14,"./ReactEvent":20,"./ReactInstanceHandles":21,"./getDOMNodeID":50}],23:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule $ */ var ge = require("./ge"); /** * Find a node by ID. * * If your application code depends on the existence of the element, use $, * which will throw if the element doesn't exist. * * If you're not sure whether or not the element exists, use ge instead, and * manually check for the element's existence in your application code. */ function $(arg) { var element = ge(arg); if (!element) { if (typeof arg == 'undefined') { arg = 'undefined'; } else if (arg === null) { arg = 'null'; } throw new Error( 'Tried to get element "' + arg.toString() + '" but it is not present ' + 'on the page.' ); } return element; } module.exports = $; },{"./ge":51}],24:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactDOMForm */ "use strict"; var ReactCompositeComponent = require("./ReactCompositeComponent"); var ReactDOM = require("./ReactDOM"); var ReactEvent = require("./ReactEvent"); var EventConstants = require("./EventConstants"); // Store a reference to the `ReactNativeComponent`. var form = ReactDOM.form; /** * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need * to capture it on the element itself. There are lots of hacks we could * do to accomplish this, but the most reliable is to make a * composite component and use `componentDidMount` to attach the event handlers. */ var ReactDOMForm = ReactCompositeComponent.createClass({ render: function() { // TODO: Instead of using `ReactDOM` directly, we should use JSX. However, // `jshint` fails to parse JSX so in order for linting to work in the open // source repo, we need to just use `ReactDOM.form`. return this.transferPropsTo(form(null, this.props.children)); }, componentDidMount: function(node) { ReactEvent.trapBubbledEvent( EventConstants.topLevelTypes.topSubmit, 'submit', node ); } }); module.exports = ReactDOMForm; },{"./ReactCompositeComponent":2,"./ReactDOM":4,"./ReactEvent":20,"./EventConstants":47}],25:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule DefaultEventPluginOrder */ "use strict"; var keyOf = require("./keyOf"); /** * Module that is injectable into `EventPluginHub`, that specifies a * deterministic ordering of `EventPlugin`s. A convenient way to reason about * plugins, without having to package every one of them. This is better than * having plugins be ordered in the same order that they are injected because * that ordering would be influenced by the packaging order. * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that * preventing default on events is convenient in `SimpleEventPlugin` handlers. */ var DefaultEventPluginOrder = [ keyOf({ResponderEventPlugin: null}), keyOf({SimpleEventPlugin: null}), keyOf({TapEventPlugin: null}), keyOf({EnterLeaveEventPlugin: null}), keyOf({AnalyticsEventPlugin: null}) ]; module.exports = DefaultEventPluginOrder; },{"./keyOf":44}],26:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EnterLeaveEventPlugin */ "use strict"; var EventPropagators = require("./EventPropagators"); var ExecutionEnvironment = require("./ExecutionEnvironment"); var AbstractEvent = require("./AbstractEvent"); var EventConstants = require("./EventConstants"); var ReactInstanceHandles = require("./ReactInstanceHandles"); var getDOMNodeID = require("./getDOMNodeID"); var keyOf = require("./keyOf"); var topLevelTypes = EventConstants.topLevelTypes; var getFirstReactDOM = ReactInstanceHandles.getFirstReactDOM; var abstractEventTypes = { mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, mouseLeave: {registrationName: keyOf({onMouseLeave: null})} }; /** * For almost every interaction we care about, there will be a top level * `mouseOver` and `mouseOut` event that occur so we can usually only pay * attention to one of the two (we'll pay attention to the `mouseOut` event) to * avoid extracting a duplicate event. However, there's one interaction where * there will be no `mouseOut` event to rely on - mousing from outside the * browser *into* the chrome. We detect this scenario and only in that case, we * use the `mouseOver` event. * * @see EventPluginHub.extractAbstractEvents */ var extractAbstractEvents = function( topLevelType, nativeEvent, renderedTargetID, renderedTarget) { if (topLevelType === topLevelTypes.topMouseOver && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { return; } if (topLevelType !== topLevelTypes.topMouseOut && topLevelType !== topLevelTypes.topMouseOver){ return null; // Must not be a mouse in or mouse out - ignoring. } var to, from; if (topLevelType === topLevelTypes.topMouseOut) { to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || ExecutionEnvironment.global; from = renderedTarget; } else { to = renderedTarget; from = ExecutionEnvironment.global; } // Nothing pertains to our managed components. if (from === to ) { return; } var fromID = from ? getDOMNodeID(from) : ''; var toID = to ? getDOMNodeID(to) : ''; var leave = AbstractEvent.getPooled( abstractEventTypes.mouseLeave, fromID, topLevelType, nativeEvent ); var enter = AbstractEvent.getPooled( abstractEventTypes.mouseEnter, toID, topLevelType, nativeEvent ); EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); return [leave, enter]; }; var EnterLeaveEventPlugin = { abstractEventTypes: abstractEventTypes, extractAbstractEvents: extractAbstractEvents }; module.exports = EnterLeaveEventPlugin; })() },{"./EventPropagators":52,"./ExecutionEnvironment":14,"./AbstractEvent":53,"./EventConstants":47,"./ReactInstanceHandles":21,"./getDOMNodeID":50,"./keyOf":44}],27:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EventPluginHub */ "use strict"; var AbstractEvent = require("./AbstractEvent"); var CallbackRegistry = require("./CallbackRegistry"); var EventPluginUtils = require("./EventPluginUtils"); var EventPropagators = require("./EventPropagators"); var ExecutionEnvironment = require("./ExecutionEnvironment"); var accumulate = require("./accumulate"); var forEachAccumulated = require("./forEachAccumulated"); var keyMirror = require("./keyMirror"); var merge = require("./merge"); var throwIf = require("./throwIf"); var deleteListener = CallbackRegistry.deleteListener; var ERRORS = keyMirror({ DOUBLE_REGISTER: null, DOUBLE_ENQUEUE: null, DEPENDENCY_ERROR: null }); if (true) { ERRORS.DOUBLE_REGISTER = 'You\'ve included an event plugin that extracts an ' + 'event type with the exact same or identity as an event that ' + 'had previously been injected - or, one of the registration names ' + 'used by an plugin has already been used.'; ERRORS.DOUBLE_ENQUEUE = 'During the processing of events, more events were enqueued. This ' + 'is strange and should not happen. Please report immediately. '; ERRORS.DEPENDENCY_ERROR = 'You have either attempted to load an event plugin that has no ' + 'entry in EventPluginOrder, or have attempted to extract events ' + 'when some critical dependencies have not yet been injected.'; } /** * EventPluginHub: To see a diagram and explanation of the overall architecture * of the plugin hub system, @see ReactEvents.js */ /** * Injected Dependencies: */ var injection = { /** * [required] Dependency of `EventPropagators`. */ injectInstanceHandle: function(InjectedInstanceHandle) { EventPropagators.injection.injectInstanceHandle(InjectedInstanceHandle); }, /** * `EventPluginOrder`: [optional] Provides deterministic ordering of * `EventPlugin`s. Ordering decoupled from the injection of actual * plugins so that there is always a deterministic and permanent ordering * regardless of the plugins that happen to become packaged, or applications * that happen to inject on-the-fly event plugins. */ EventPluginOrder: null, injectEventPluginOrder: function(InjectedEventPluginOrder) { injection.EventPluginOrder = InjectedEventPluginOrder; injection._recomputePluginsList(); }, /** * `EventPlugins`: [optional][lazy-loadable] Plugins that must be listed in * the `EventPluginOrder` injected dependency. The list of plugins may grow as * custom plugins are injected into the system at page as part of the * initialization process, or even after the initialization process (on-the- * fly). Plugins injected into the hub have an opportunity to infer abstract * events when top level events are streamed through the `EventPluginHub`. */ plugins: [], injectEventPluginsByName: function(pluginsByName) { injection.pluginsByName = merge(injection.pluginsByName, pluginsByName); injection._recomputePluginsList(); }, /** * A reference of all injected plugins by their name. Both plugins and * `EventPluginOrder` can be injected on-the-fly. Any time either dependency * is (re)injected, the resulting list of plugins in correct order is * recomputed. */ pluginsByName: {}, _recomputePluginsList: function() { var injectPluginByName = function(name, PluginModule) { var pluginIndex = injection.EventPluginOrder.indexOf(name); throwIf(pluginIndex === -1, ERRORS.DEPENDENCY_ERROR + name); if (!injection.plugins[pluginIndex]) { injection.plugins[pluginIndex] = PluginModule; for (var eventName in PluginModule.abstractEventTypes) { var eventType = PluginModule.abstractEventTypes[eventName]; recordAllRegistrationNames(eventType, PluginModule); } } }; if (injection.EventPluginOrder) { // Else, do when plugin order injected var injectedPluginsByName = injection.pluginsByName; for (var name in injectedPluginsByName) { injectPluginByName(name, injectedPluginsByName[name]); } } } }; /** * `renderedTarget`: We'll refer to the concept of a "rendered target". Any * framework code that uses the `EventPluginHub` will stream events to the * `EventPluginHub`. In order for registered plugins to make sense of the native * events, it helps to allow plugins to not only have access to the native * `Event` object but also the notion of a "rendered target", which is the * conceptual target `Element` of the `Event` that the framework (user of * `EventPluginHub`) deems as being the "important" target. */ /** * Keeps track of all valid "registration names" (`onClick` etc). We expose * these structures to other modules, who will always see updates that we apply * to these structures. They should never have a desire to mutate these. */ var registrationNames = {}; /** * This prevents the need for clients to call `Object.keys(registrationNames)` * every time they want to loop through the possible registration names. */ var registrationNamesArr = []; /** * Internal queue of events that have accumulated their dispatches and are * waiting to have their dispatches executed. */ var abstractEventQueue = []; /** * Records all the registration names that the event plugin makes available * to the general event system. These are things like * `onClick`/`onClickCapture`. */ function recordAllRegistrationNames(eventType, PluginModule) { var phaseName; var phasedRegistrationNames = eventType.phasedRegistrationNames; if (phasedRegistrationNames) { for (phaseName in phasedRegistrationNames) { if (!phasedRegistrationNames.hasOwnProperty(phaseName)) { continue; } if (true) { throwIf( registrationNames[phasedRegistrationNames[phaseName]], ERRORS.DOUBLE_REGISTER ); } registrationNames[phasedRegistrationNames[phaseName]] = PluginModule; registrationNamesArr.push(phasedRegistrationNames[phaseName]); } } else if (eventType.registrationName) { if (true) { throwIf( registrationNames[eventType.registrationName], ERRORS.DOUBLE_REGISTER ); } registrationNames[eventType.registrationName] = PluginModule; registrationNamesArr.push(eventType.registrationName); } } /** * A hacky way to reverse engineer which event plugin module created an * AbstractEvent. * @param {AbstractEvent} abstractEvent to look at */ function getPluginModuleForAbstractEvent(abstractEvent) { if (abstractEvent.type.registrationName) { return registrationNames[abstractEvent.type.registrationName]; } else { for (var phase in abstractEvent.type.phasedRegistrationNames) { if (!abstractEvent.type.phasedRegistrationNames.hasOwnProperty(phase)) { continue; } var PluginModule = registrationNames[ abstractEvent.type.phasedRegistrationNames[phase] ]; if (PluginModule) { return PluginModule; } } } return null; } var deleteAllListeners = function(domID) { var ii; for (ii = 0; ii < registrationNamesArr.length; ii++) { deleteListener(domID, registrationNamesArr[ii]); } }; /** * Accepts the stream of top level native events, and gives every registered * plugin an opportunity to extract `AbstractEvent`s with annotated dispatches. * * @param {Enum} topLevelType Record from `EventConstants`. * @param {Event} nativeEvent A Standard Event with fixed `target` property. * @param {Element} renderedTarget Element of interest to the framework, usually * the same as `nativeEvent.target` but occasionally an element immediately * above `nativeEvent.target` (the first DOM node recognized as one "rendered" * by the framework at hand.) * @param {string} renderedTargetID string ID of `renderedTarget`. */ var extractAbstractEvents = function(topLevelType, nativeEvent, renderedTargetID, renderedTarget) { var abstractEvents; var plugins = injection.plugins; var len = plugins.length; for (var i = 0; i < len; i++) { // Not every plugin in the ordering may be loaded at runtime. var possiblePlugin = plugins[i]; var extractedAbstractEvents = possiblePlugin && possiblePlugin.extractAbstractEvents( topLevelType, nativeEvent, renderedTargetID, renderedTarget ); if (extractedAbstractEvents) { abstractEvents = accumulate(abstractEvents, extractedAbstractEvents); } } return abstractEvents; }; var enqueueAbstractEvents = function(abstractEvents) { if (abstractEvents) { abstractEventQueue = accumulate(abstractEventQueue, abstractEvents); } }; /** * Executes a single abstract event dispatch. Returns a value, but this return * value doesn't make much sense when executing dispatches for a list of a * events. However, if a plugin executes a single dispatch, mostly bypassing * `EventPluginHub`, it can execute dispatches directly and assign special * meaning to the return value. So this will return the result of executing the * dispatch, though for most use cases, it gets dropped. */ var executeDispatchesAndRelease = function(abstractEvent) { if (abstractEvent) { var PluginModule = getPluginModuleForAbstractEvent(abstractEvent); var pluginExecuteDispatch = PluginModule && PluginModule.executeDispatch; EventPluginUtils.executeDispatchesInOrder( abstractEvent, pluginExecuteDispatch || EventPluginUtils.executeDispatch ); AbstractEvent.release(abstractEvent); } }; /** * Sets `abstractEventQueue` to null before processing it, so that we can tell * if in the process of processing events, more were enqueued. We throw if we * find that any were enqueued though this use case could be supported in the * future. For now, throwing an error as it's something we don't expect to * occur. */ var processAbstractEventQueue = function() { var processingAbstractEventQueue = abstractEventQueue; abstractEventQueue = null; forEachAccumulated(processingAbstractEventQueue, executeDispatchesAndRelease); if (true) { throwIf(abstractEventQueue, ERRORS.DOUBLE_ENQUEUE); } }; /** * Provides a unified interface for an arbitrary and dynamic set of event * plugins. Loosely, a hub, where several "event plugins" may act as a single * event plugin behind the facade of `EventPluginHub`. Each event plugin injects * themselves into the HUB, and will immediately become operable upon injection. * * @constructor EventPluginHub */ var EventPluginHub = { registrationNames: registrationNames, registrationNamesArr: registrationNamesArr, putListener: CallbackRegistry.putListener, getListener: CallbackRegistry.getListener, deleteAllListeners: deleteAllListeners, extractAbstractEvents: extractAbstractEvents, enqueueAbstractEvents: enqueueAbstractEvents, processAbstractEventQueue: processAbstractEventQueue, injection: injection }; if (ExecutionEnvironment.canUseDOM) { window.EventPluginHub = EventPluginHub; } module.exports = EventPluginHub; })() },{"./AbstractEvent":53,"./CallbackRegistry":54,"./EventPluginUtils":55,"./EventPropagators":52,"./ExecutionEnvironment":14,"./accumulate":56,"./forEachAccumulated":57,"./keyMirror":11,"./merge":12,"./throwIf":31}],28:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule SimpleEventPlugin */ "use strict"; var AbstractEvent = require("./AbstractEvent"); var EventConstants = require("./EventConstants"); var EventPropagators = require("./EventPropagators"); var keyOf = require("./keyOf"); var topLevelTypes = EventConstants.topLevelTypes; var SimpleEventPlugin = { abstractEventTypes: { // Note: We do not allow listening to mouseOver events. Instead, use the // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`. mouseDown: { phasedRegistrationNames: { bubbled: keyOf({onMouseDown: true}), captured: keyOf({onMouseDownCapture: true}) } }, mouseUp: { phasedRegistrationNames: { bubbled: keyOf({onMouseUp: true}), captured: keyOf({onMouseUpCapture: true}) } }, mouseMove: { phasedRegistrationNames: { bubbled: keyOf({onMouseMove: true}), captured: keyOf({onMouseMoveCapture: true}) } }, doubleClick: { phasedRegistrationNames: { bubbled: keyOf({onDoubleClick: true}), captured: keyOf({onDoubleClickCapture: true}) } }, click: { phasedRegistrationNames: { bubbled: keyOf({onClick: true}), captured: keyOf({onClickCapture: true}) } }, mouseWheel: { phasedRegistrationNames: { bubbled: keyOf({onMouseWheel: true}), captured: keyOf({onMouseWheelCapture: true}) } }, touchStart: { phasedRegistrationNames: { bubbled: keyOf({onTouchStart: true}), captured: keyOf({onTouchStartCapture: true}) } }, touchEnd: { phasedRegistrationNames: { bubbled: keyOf({onTouchEnd: true}), captured: keyOf({onTouchEndCapture: true}) } }, touchCancel: { phasedRegistrationNames: { bubbled: keyOf({onTouchCancel: true}), captured: keyOf({onTouchCancelCapture: true}) } }, touchMove: { phasedRegistrationNames: { bubbled: keyOf({onTouchMove: true}), captured: keyOf({onTouchMoveCapture: true}) } }, keyUp: { phasedRegistrationNames: { bubbled: keyOf({onKeyUp: true}), captured: keyOf({onKeyUpCapture: true}) } }, keyPress: { phasedRegistrationNames: { bubbled: keyOf({onKeyPress: true}), captured: keyOf({onKeyPressCapture: true}) } }, keyDown: { phasedRegistrationNames: { bubbled: keyOf({onKeyDown: true}), captured: keyOf({onKeyDownCapture: true}) } }, focus: { phasedRegistrationNames: { bubbled: keyOf({onFocus: true}), captured: keyOf({onFocusCapture: true}) } }, blur: { phasedRegistrationNames: { bubbled: keyOf({onBlur: true}), captured: keyOf({onBlurCapture: true}) } }, scroll: { phasedRegistrationNames: { bubbled: keyOf({onScroll: true}), captured: keyOf({onScrollCapture: true}) } }, change: { phasedRegistrationNames: { bubbled: keyOf({onChange: true}), captured: keyOf({onChangeCapture: true}) } }, submit: { phasedRegistrationNames: { bubbled: keyOf({onSubmit: true}), captured: keyOf({onSubmitCapture: true}) } }, DOMCharacterDataModified: { phasedRegistrationNames: { bubbled: keyOf({onDOMCharacterDataModified: true}), captured: keyOf({onDOMCharacterDataModifiedCapture: true}) } } }, /** * Same as the default implementation, except cancels the event when return * value is false. * @param {AbstractEvent} AbstractEvent to handle * @param {function} Application-level callback * @param {string} domID DOM id to pass to the callback. */ executeDispatch: function(abstractEvent, listener, domID) { var returnValue = listener(abstractEvent, domID); if (returnValue === false) { abstractEvent.stopPropagation(); abstractEvent.preventDefault(); } }, /** * @see EventPluginHub.extractAbstractEvents */ extractAbstractEvents: function(topLevelType, nativeEvent, renderedTargetID, renderedTarget) { var data; var abstractEventType = SimpleEventPlugin.topLevelTypesToAbstract[topLevelType]; if (!abstractEventType) { return null; } switch(topLevelType) { case topLevelTypes.topMouseWheel: data = AbstractEvent.normalizeMouseWheelData(nativeEvent); break; case topLevelTypes.topScroll: data = AbstractEvent.normalizeScrollDataFromTarget(renderedTarget); break; case topLevelTypes.topClick: case topLevelTypes.topDoubleClick: case topLevelTypes.topChange: case topLevelTypes.topDOMCharacterDataModified: case topLevelTypes.topMouseDown: case topLevelTypes.topMouseUp: case topLevelTypes.topMouseMove: case topLevelTypes.topTouchMove: case topLevelTypes.topTouchStart: case topLevelTypes.topTouchEnd: data = AbstractEvent.normalizePointerData(nativeEvent); break; default: data = null; } var abstractEvent = AbstractEvent.getPooled( abstractEventType, renderedTargetID, topLevelType, nativeEvent, data ); EventPropagators.accumulateTwoPhaseDispatches(abstractEvent); return abstractEvent; } }; SimpleEventPlugin.topLevelTypesToAbstract = { topMouseDown: SimpleEventPlugin.abstractEventTypes.mouseDown, topMouseUp: SimpleEventPlugin.abstractEventTypes.mouseUp, topMouseMove: SimpleEventPlugin.abstractEventTypes.mouseMove, topClick: SimpleEventPlugin.abstractEventTypes.click, topDoubleClick: SimpleEventPlugin.abstractEventTypes.doubleClick, topMouseWheel: SimpleEventPlugin.abstractEventTypes.mouseWheel, topTouchStart: SimpleEventPlugin.abstractEventTypes.touchStart, topTouchEnd: SimpleEventPlugin.abstractEventTypes.touchEnd, topTouchMove: SimpleEventPlugin.abstractEventTypes.touchMove, topTouchCancel: SimpleEventPlugin.abstractEventTypes.touchCancel, topKeyUp: SimpleEventPlugin.abstractEventTypes.keyUp, topKeyPress: SimpleEventPlugin.abstractEventTypes.keyPress, topKeyDown: SimpleEventPlugin.abstractEventTypes.keyDown, topFocus: SimpleEventPlugin.abstractEventTypes.focus, topBlur: SimpleEventPlugin.abstractEventTypes.blur, topScroll: SimpleEventPlugin.abstractEventTypes.scroll, topChange: SimpleEventPlugin.abstractEventTypes.change, topSubmit: SimpleEventPlugin.abstractEventTypes.submit, topDOMCharacterDataModified: SimpleEventPlugin.abstractEventTypes.DOMCharacterDataModified }; module.exports = SimpleEventPlugin; },{"./AbstractEvent":53,"./EventConstants":47,"./EventPropagators":52,"./keyOf":44}],30:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule joinClasses * @typechecks */ "use strict"; /** * Combines multiple className strings into one. * http://jsperf.com/joinclasses-args-vs-array * * @param {...?string} classes * @return {string} */ function joinClasses(className/*, ... */) { if (!className) { className = ''; } var nextClass; var argLength = arguments.length; if (argLength > 1) { for (var ii = 1; ii < argLength; ii++) { nextClass = arguments[ii]; nextClass && (className += ' ' + nextClass); } } return className; } module.exports = joinClasses; },{}],31:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule throwIf */ "use strict"; var throwIf = function(condition, err) { if (condition) { throw new Error(err); } }; module.exports = throwIf; },{}],37:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule PooledClass */ "use strict"; /** * Static poolers. Several custom versions for each potential number of * arguments. A completely generic pooler is easy to implement, but would * require accessing the `arguments` object. In each of these, `this` refers to * the Class itself, not an instance. If any others are needed, simply add them * here, or in their own files. */ var oneArgumentPooler = function(copyFieldsFrom) { var Klass = this; if (Klass.instancePool.length) { var instance = Klass.instancePool.pop(); Klass.call(instance, copyFieldsFrom); return instance; } else { return new Klass(copyFieldsFrom); } }; var twoArgumentPooler = function(a1, a2) { var Klass = this; if (Klass.instancePool.length) { var instance = Klass.instancePool.pop(); Klass.call(instance, a1, a2); return instance; } else { return new Klass(a1, a2); } }; var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { var Klass = this; if (Klass.instancePool.length) { var instance = Klass.instancePool.pop(); Klass.call(instance, a1, a2, a3, a4, a5); return instance; } else { return new Klass(a1, a2, a3, a4, a5); } }; var standardReleaser = function(instance) { var Klass = this; if (instance.destructor) { instance.destructor(); } if (Klass.instancePool.length < Klass.poolSize) { Klass.instancePool.push(instance); } }; var DEFAULT_POOL_SIZE = 10; var DEFAULT_POOLER = oneArgumentPooler; /** * Augments `CopyConstructor` to be a poolable class, augmenting only the class * itself (statically) not adding any prototypical fields. Any CopyConstructor * you give this may have a `poolSize` property, and will look for a * prototypical `destructor` on instances (optional). * * @param {Function} CopyConstructor Constructor that can be used to reset. * @param {Function} pooler Customizable pooler. */ var addPoolingTo = function(CopyConstructor, pooler) { var NewKlass = CopyConstructor; NewKlass.instancePool = []; NewKlass.getPooled = pooler || DEFAULT_POOLER; if (!NewKlass.poolSize) { NewKlass.poolSize = DEFAULT_POOL_SIZE; } NewKlass.release = standardReleaser; return NewKlass; }; var PooledClass = { addPoolingTo: addPoolingTo, oneArgumentPooler: oneArgumentPooler, twoArgumentPooler: twoArgumentPooler, fiveArgumentPooler: fiveArgumentPooler }; module.exports = PooledClass; },{}],38:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactInputSelection */ "use strict"; // It is not safe to read the document.activeElement property in IE if there's // nothing focused. function getActiveElement() { try { return document.activeElement; } catch (e) { } } /** * @ReactInputSelection: React input selection module. Based on Selection.js, * but modified to be suitable for react and has a couple of bug fixes (doesn't * assume buttons have range selections allowed). * Input selection module for React. */ var ReactInputSelection = { hasSelectionCapabilities: function(elem) { return elem && ( (elem.nodeName === 'INPUT' && elem.type === 'text') || elem.nodeName === 'TEXTAREA' || elem.contentEditable === 'true' ); }, getSelectionInformation: function() { var focusedElem = getActiveElement(); return { focusedElem: focusedElem, selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem) ? ReactInputSelection.getSelection(focusedElem) : null }; }, /** * @restoreSelection: If any selection information was potentially lost, * restore it. This is useful when performing operations that could remove dom * nodes and place them back in, resulting in focus being lost. */ restoreSelection: function(priorSelectionInformation) { var curFocusedElem = getActiveElement(); var priorFocusedElem = priorSelectionInformation.focusedElem; var priorSelectionRange = priorSelectionInformation.selectionRange; if (curFocusedElem !== priorFocusedElem && document.getElementById(priorFocusedElem.id)) { if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) { ReactInputSelection.setSelection( priorFocusedElem, priorSelectionRange ); } priorFocusedElem.focus(); } }, /** * @getSelection: Gets the selection bounds of a textarea or input. * -@input: Look up selection bounds of this input or textarea * -@return {start: selectionStart, end: selectionEnd} */ getSelection: function(input) { var range; if (input.contentEditable === 'true' && window.getSelection) { range = window.getSelection().getRangeAt(0); var commonAncestor = range.commonAncestorContainer; if (commonAncestor && commonAncestor.nodeType === 3) { commonAncestor = commonAncestor.parentNode; } if (commonAncestor !== input) { return {start: 0, end: 0}; } else { return {start: range.startOffset, end: range.endOffset}; } } if (!document.selection) { // Mozilla, Safari, etc. return {start: input.selectionStart, end: input.selectionEnd}; } range = document.selection.createRange(); if (range.parentElement() !== input) { // There can only be one selection per document in IE, so if the // containing element of the document's selection isn't our text field, // our text field must have no selection. return {start: 0, end: 0}; } var length = input.value.length; if (input.nodeName === 'INPUT') { return { start: -range.moveStart('character', -length), end: -range.moveEnd('character', -length) }; } else { var range2 = range.duplicate(); range2.moveToElementText(input); range2.setEndPoint('StartToEnd', range); var end = length - range2.text.length; range2.setEndPoint('StartToStart', range); return { start: length - range2.text.length, end: end }; } }, /** * @setSelection: Sets the selection bounds of a textarea or input and focuses * the input. * -@input Set selection bounds of this input or textarea * -@rangeObj Object of same form that is returned from get* */ setSelection: function(input, rangeObj) { var range; var start = rangeObj.start; var end = rangeObj.end; if (typeof end === 'undefined') { end = start; } if (document.selection) { // IE is inconsistent about character offsets when it comes to carriage // returns, so we need to manually take them into account if (input.tagName === 'TEXTAREA') { var cr_before = (input.value.slice(0, start).match(/\r/g) || []).length; var cr_inside = (input.value.slice(start, end).match(/\r/g) || []).length; start -= cr_before; end -= cr_before + cr_inside; } range = input.createTextRange(); range.collapse(true); range.moveStart('character', start); range.moveEnd('character', end - start); range.select(); } else { if (input.contentEditable === 'true') { if (input.childNodes.length === 1) { range = document.createRange(); range.setStart(input.childNodes[0], start); range.setEnd(input.childNodes[0], end); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } } else { input.selectionStart = start; input.selectionEnd = Math.min(end, input.value.length); input.focus(); } } } }; module.exports = ReactInputSelection; },{}],44:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule keyOf */ /** * Allows extraction of a minified key. Let's the build system minify keys * without loosing the ability to dynamically use key strings as values * themselves. Pass in an object with a single key/val pair and it will return * you the string key of that single record. Suppose you want to grab the * value for a key 'className' inside of an object. Key/val minification may * have aliased that key to be 'xa12'. keyOf({className: null}) will return * 'xa12' in that case. Resolve keys you want to use once at startup time, then * reuse those resolutions. */ var keyOf = function(oneKeyObj) { var key; for (key in oneKeyObj) { if (!oneKeyObj.hasOwnProperty(key)) { continue; } return key; } return null; }; module.exports = keyOf; },{}],46:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule BrowserEnv */ "use strict"; /** * A place to share/cache browser/chrome level computations. */ var BrowserEnv = { currentScrollLeft: 0, currentScrollTop: 0, browserInfo: null, refreshAuthoritativeScrollValues: function() { BrowserEnv.currentScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft; BrowserEnv.currentScrollTop = document.body.scrollTop + document.documentElement.scrollTop; } }; module.exports = BrowserEnv; },{}],50:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule getDOMNodeID */ "use strict"; /** * Accessing "id" or calling getAttribute('id') on a form element can return its * control whose name or ID is "id". However, not all DOM nodes support * `getAttributeNode` (document - which is not a form) so that is checked first. * * @param {Element} domNode DOM node element to return ID of. * @returns {string} The ID of `domNode`. */ function getDOMNodeID(domNode) { if (domNode.getAttributeNode) { var attributeNode = domNode.getAttributeNode('id'); return attributeNode && attributeNode.value || ''; } else { return domNode.id || ''; } } module.exports = getDOMNodeID; },{}],51:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ge */ /** * Find a node by ID. Optionally search a sub-tree outside of the document * * Use ge if you're not sure whether or not the element exists. You can test * for existence yourself in your application code. * * If your application code depends on the existence of the element, use $ * instead, which will throw in DEV if the element doesn't exist. */ function ge(arg, root, tag) { return typeof arg != 'string' ? arg : !root ? document.getElementById(arg) : _geFromSubtree(arg, root, tag); } function _geFromSubtree(id, root, tag) { var elem, children, ii; if (_getNodeID(root) == id) { return root; } else if (root.getElementsByTagName) { // All Elements implement this, which does an iterative DFS, which is // faster than recursion and doesn't run into stack depth issues. children = root.getElementsByTagName(tag || '*'); for (ii = 0; ii < children.length; ii++) { if (_getNodeID(children[ii]) == id) { return children[ii]; } } } else { // DocumentFragment does not implement getElementsByTagName, so // recurse over its children. Its children must be Elements, so // each child will use the getElementsByTagName case instead. children = root.childNodes; for (ii = 0; ii < children.length; ii++) { elem = _geFromSubtree(id, children[ii]); if (elem) { return elem; } } } return null; } /** * Return the ID value for a given node. This allows us to avoid issues * with forms that contain inputs with name="id". * * @return string (null if attribute not set) */ function _getNodeID(node) { // #document and #document-fragment do not have getAttributeNode. var id = node.getAttributeNode && node.getAttributeNode('id'); return id ? id.value : null; } module.exports = ge; },{}],54:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule CallbackRegistry */ "use strict"; var listenerBank = {}; /** * Stores "listeners" by `registrationName`/`id`. There should be at most one * "listener" per `registrationName/id` in the `listenerBank`. * Access listeners via `listenerBank[registrationName][id]` * * @constructor CallbackRegistry */ var CallbackRegistry = { /** * Stores `listener` at `listenerBank[registrationName][id]. Is idempotent. * @param {string} domID The id of the DOM node. * @param {string} registrationName The name of listener (`onClick` etc). * @param {Function} listener The callback to to store. */ putListener: function(id, registrationName, listener) { var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {}); bankForRegistrationName[id] = listener; }, /** * @param {string} id. * @param {string} registrationName Name of registration (`onClick` etc). * @return {Function?} The Listener */ getListener: function(id, registrationName) { var bankForRegistrationName = listenerBank[registrationName]; return bankForRegistrationName && bankForRegistrationName[id]; }, /** * Deletes the listener from the registration bank. * @param {string} id * @param {string} registrationName (`onClick` etc). */ deleteListener: function(id, registrationName) { var bankForRegistrationName = listenerBank[registrationName]; if (bankForRegistrationName) { delete bankForRegistrationName[id]; } }, // This is needed for tests only. Do not use in real life __purge: function() { listenerBank = {}; } }; module.exports = CallbackRegistry; },{}],57:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule forEachAccumulated */ "use strict"; /** * @param {array} an "accumulation" of items which is either an Array or * a single item. Useful when paired with the `accumulate` module. This is a * simple utility that allows us to reason about a collection of items, but * handling the case when there is exactly one item (and we do not need to * allocate an array). */ var forEachAccumulated = function(arr, cb, scope) { if (Array.isArray(arr)) { arr.forEach(cb, scope); } else if (arr) { cb.call(scope, arr); } }; module.exports = forEachAccumulated; },{}],29:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule emptyFunction */ var copyProperties = require("./copyProperties"); function makeEmptyFunction(arg) { return function() { return arg; }; } /** * This function accepts and discards inputs; it has no side effects. This is * primarily useful idiomatically for overridable function endpoints which * always need to be callable, since JS lacks a null-call idiom ala Cocoa. */ function emptyFunction() {} copyProperties(emptyFunction, { thatReturns: makeEmptyFunction, thatReturnsFalse: makeEmptyFunction(false), thatReturnsTrue: makeEmptyFunction(true), thatReturnsNull: makeEmptyFunction(null), thatReturnsThis: function() { return this; }, thatReturnsArgument: function(arg) { return arg; }, mustImplement: function(module, property) { return function() { if (true) { throw new Error(module + '.' + property + ' must be implemented!'); } }; } }); module.exports = emptyFunction; },{"./copyProperties":58}],32:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule CSSPropertyOperations * @typechecks */ "use strict"; var dangerousStyleValue = require("./dangerousStyleValue"); var escapeTextForBrowser = require("./escapeTextForBrowser"); var hyphenate = require("./hyphenate"); var memoizeStringOnly = require("./memoizeStringOnly"); var processStyleName = memoizeStringOnly(function(styleName) { return escapeTextForBrowser(hyphenate(styleName)); }); /** * Operations for dealing with CSS properties. */ var CSSPropertyOperations = { /** * Serializes a mapping of style properties for use as inline styles: * * > createMarkupForStyles({width: '200px', height: 0}) * "width:200px;height:0;" * * Undefined values are ignored so that declarative programming is easier. * * @param {object} styles * @return {string} */ createMarkupForStyles: function(styles) { var serialized = ''; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { continue; } var styleValue = styles[styleName]; if (typeof styleValue !== 'undefined') { serialized += processStyleName(styleName) + ':'; serialized += dangerousStyleValue(styleName, styleValue) + ';'; } } return serialized; }, /** * Sets the value for multiple styles on a node. * * @param {DOMElement} node * @param {object} styles */ setValueForStyles: function(node, styles) { var style = node.style; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { continue; } var styleValue = styles[styleName]; style[styleName] = dangerousStyleValue(styleName, styleValue); } } }; module.exports = CSSPropertyOperations; },{"./dangerousStyleValue":59,"./escapeTextForBrowser":42,"./hyphenate":60,"./memoizeStringOnly":61}],33:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule DOMChildrenOperations */ "use strict"; var Danger = require("./Danger"); var insertNodeAt = require("./insertNodeAt"); var keyOf = require("./keyOf"); var throwIf = require("./throwIf"); var NON_INCREASING_OPERATIONS; if (true) { NON_INCREASING_OPERATIONS = 'DOM child management operations must be provided in order ' + 'of increasing destination index. This is likely an issue with ' + 'the core framework.'; } var MOVE_NODE_AT_ORIG_INDEX = keyOf({moveFrom: null}); var INSERT_MARKUP = keyOf({insertMarkup: null}); var REMOVE_AT = keyOf({removeAt: null}); /** * In order to carry out movement of DOM nodes without knowing their IDs, we * have to first store knowledge about nodes' original indices before beginning * to carry out the sequence of operations. Once we begin the sequence, the DOM * indices in future instructions are no longer valid. * * @param {Element} parent Parent DOM node. * @param {Object} childOperations Description of child operations. * @returns {Array?} Sparse array containing elements by their current index in * the DOM. */ var _getNodesByOriginalIndex = function(parent, childOperations) { var nodesByOriginalIndex; // Sparse array. var childOperation; var origIndex; for (var i = 0; i < childOperations.length; i++) { childOperation = childOperations[i]; if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { nodesByOriginalIndex = nodesByOriginalIndex || []; origIndex = childOperation.moveFrom; nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; } else if (REMOVE_AT in childOperation) { nodesByOriginalIndex = nodesByOriginalIndex || []; origIndex = childOperation.removeAt; nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; } } return nodesByOriginalIndex; }; /** * Removes DOM elements from their parent, or moved. * @param {Element} parent Parent DOM node. * @param {Array} nodesByOriginalIndex Child nodes by their original index * (potentially sparse.) */ var _removeChildrenByOriginalIndex = function(parent, nodesByOriginalIndex) { for (var j = 0; j < nodesByOriginalIndex.length; j++) { var nodeToRemove = nodesByOriginalIndex[j]; if (nodeToRemove) { // We used a sparse array. parent.removeChild(nodesByOriginalIndex[j]); } } }; /** * Once all nodes that will be removed or moved - are removed from the parent * node, we can begin the process of placing nodes into their final locations. * We must perform all operations in the order of the final DOM index - * otherwise, we couldn't count on the fact that an insertion at index X, will * remain at index X. This will iterate through the child operations, adding * content where needed, skip over removals (they've already been removed) and * insert "moved" Elements that were previously removed. The "moved" elements * are only temporarily removed from the parent, so that index calculations can * be manageable and perform well in the cases that matter. */ var _placeNodesAtDestination = function(parent, childOperations, nodesByOriginalIndex) { var origNode; var finalIndex; var lastFinalIndex = -1; var childOperation; for (var k = 0; k < childOperations.length; k++) { childOperation = childOperations[k]; if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { origNode = nodesByOriginalIndex[childOperation.moveFrom]; finalIndex = childOperation.finalIndex; insertNodeAt(parent, origNode, finalIndex); if (true) { throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); lastFinalIndex = finalIndex; } } else if (REMOVE_AT in childOperation) { } else if (INSERT_MARKUP in childOperation) { finalIndex = childOperation.finalIndex; var markup = childOperation.insertMarkup; Danger.dangerouslyInsertMarkupAt(parent, markup, finalIndex); if (true) { throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); lastFinalIndex = finalIndex; } } } }; var manageChildren = function(parent, childOperations) { var nodesByOriginalIndex = _getNodesByOriginalIndex(parent, childOperations); if (nodesByOriginalIndex) { _removeChildrenByOriginalIndex(parent, nodesByOriginalIndex); } _placeNodesAtDestination(parent, childOperations, nodesByOriginalIndex); }; var setTextNodeValueAtIndex = function(parent, index, val) { parent.childNodes[index].nodeValue = val; }; /** * Also reexport all of the dangerous functions. It helps to have all dangerous * functions located in a single module `Danger`. */ var DOMChildrenOperations = { dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, manageChildren: manageChildren, setTextNodeValueAtIndex: setTextNodeValueAtIndex }; module.exports = DOMChildrenOperations; })() },{"./Danger":62,"./insertNodeAt":63,"./keyOf":44,"./throwIf":31}],34:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule DOMPropertyOperations * @typechecks */ "use strict"; var DOMProperty = require("./DOMProperty"); var escapeTextForBrowser = require("./escapeTextForBrowser"); var memoizeStringOnly = require("./memoizeStringOnly"); var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { return escapeTextForBrowser(name) + '="'; }); /** * Operations for dealing with DOM properties. */ var DOMPropertyOperations = { /** * Creates markup for a property. * * @param {string} name * @param {*} value * @return {?string} Markup string, or null if the property was invalid. */ createMarkupForProperty: function(name, value) { if (DOMProperty.isStandardName[name]) { if (value == null || DOMProperty.hasBooleanValue[name] && !value) { return ''; } var attributeName = DOMProperty.getAttributeName[name]; return processAttributeNameAndPrefix(attributeName) + escapeTextForBrowser(value) + '"'; } else if (DOMProperty.isCustomAttribute(name)) { if (value == null) { return ''; } return processAttributeNameAndPrefix(name) + escapeTextForBrowser(value) + '"'; } else { return null; } }, /** * Sets the value for a property on a node. * * @param {DOMElement} node * @param {string} name * @param {*} value */ setValueForProperty: function(node, name, value) { if (DOMProperty.isStandardName[name]) { var mutationMethod = DOMProperty.getMutationMethod[name]; if (mutationMethod) { mutationMethod(node, value); } else if (DOMProperty.mustUseAttribute[name]) { if (DOMProperty.hasBooleanValue[name] && !value) { node.removeAttribute(DOMProperty.getAttributeName[name]); } else { node.setAttribute(DOMProperty.getAttributeName[name], value); } } else { var propName = DOMProperty.getPropertyName[name]; if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { node[propName] = value; } } } else if (DOMProperty.isCustomAttribute(name)) { node.setAttribute(name, value); } } }; module.exports = DOMPropertyOperations; },{"./DOMProperty":64,"./escapeTextForBrowser":42,"./memoizeStringOnly":61}],35:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactDOMNodeCache */ "use strict"; var ReactMount = require("./ReactMount"); var nodeCache = {}; /** * DOM node cache only intended for use by React. Placed into a shared module so * that both read and write utilities may benefit from a shared cache. */ var ReactDOMNodeCache = { /** * Releases fast id lookups (node/style cache). This implementation is * aggressive with purging because the bookkeeping associated with doing fine * grained deleted from the cache may outweight the benefits of the cache. The * heuristic that should be used to purge is 'any time anything is deleted'. * Typically this means that a large amount of content is being replaced and * several elements would need purging regardless. It's also a time when an * application is likely not in the middle of a "smooth operation" (such as * animating/scrolling). */ purgeEntireCache: function() { nodeCache = {}; return nodeCache; }, getCachedNodeByID: function(id) { return nodeCache[id] || (nodeCache[id] = document.getElementById(id) || ReactMount.findReactRenderedDOMNodeSlow(id)); } }; module.exports = ReactDOMNodeCache; },{"./ReactMount":5}],36:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule getTextContentAccessor */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var contentKey = null; /** * Gets the key used to access text content on a DOM node. * * @return {?string} Key used to access text content. * @internal */ function getTextContentAccessor() { if (!contentKey && ExecutionEnvironment.canUseDOM) { contentKey = 'innerText' in document.createElement('div') ? 'innerText' : 'textContent'; } return contentKey; } module.exports = getTextContentAccessor; },{"./ExecutionEnvironment":14}],39:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactOnDOMReady */ "use strict"; var PooledClass = require("./PooledClass"); var mixInto = require("./mixInto"); /** * A specialized pseudo-event module to help keep track of components waiting to * be notified when their DOM representations are available for use. * * This implements `PooledClass`, so you should never need to instantiate this. * Instead, use `ReactOnDOMReady.getPooled()`. * * @param {?array} initialCollection * @class ReactOnDOMReady * @implements PooledClass * @internal */ function ReactOnDOMReady(initialCollection) { this._queue = initialCollection || null; } mixInto(ReactOnDOMReady, { /** * Enqueues a callback to be invoked when `notifyAll` is invoked. This is used * to enqueue calls to `componentDidMount` and `componentDidUpdate`. * * @param {ReactComponent} component Component being rendered. * @param {function(DOMElement)} callback Invoked when `notifyAll` is invoked. * @internal */ enqueue: function(component, callback) { this._queue = this._queue || []; this._queue.push({component: component, callback: callback}); }, /** * Invokes all enqueued callbacks and clears the queue. This is invoked after * the DOM representation of a component has been created or updated. * * @internal */ notifyAll: function() { var queue = this._queue; if (queue) { this._queue = null; for (var i = 0, l = queue.length; i < l; i++) { var component = queue[i].component; var callback = queue[i].callback; callback.call(component, component.getDOMNode()); } queue.length = 0; } }, /** * Resets the internal queue. * * @internal */ reset: function() { this._queue = null; }, /** * `PooledClass` looks for this. */ destructor: function() { this.reset(); } }); PooledClass.addPoolingTo(ReactOnDOMReady); module.exports = ReactOnDOMReady; },{"./PooledClass":37,"./mixInto":13}],40:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule Transaction */ "use strict"; var throwIf = require("./throwIf"); var DUAL_TRANSACTION = 'DUAL_TRANSACTION'; var MISSING_TRANSACTION = 'MISSING_TRANSACTION'; if (true) { DUAL_TRANSACTION = 'Cannot initialize transaction when there is already an outstanding ' + 'transaction. Common causes of this are trying to render a component ' + 'when you are already rendering a component or attempting a state ' + 'transition while in a render function. Another possibility is that ' + 'you are rendering new content (or state transitioning) in a ' + 'componentDidRender callback. If this is not the case, please report the ' + 'issue immediately.'; MISSING_TRANSACTION = 'Cannot close transaction when there is none open.'; } /** * `Transaction` creates a black box that is able to wrap any method such that * certain invariants are maintained before and after the method is invoked * (Even if an exception is thrown while invoking the wrapped method). Whoever * instantiates a transaction can provide enforcers of the invariants at * creation time. The `Transaction` class itself will supply one additional * automatic invariant for you - the invariant that any transaction instance * should not be ran while it is already being ran. You would typically create a * single instance of a `Transaction` for reuse multiple times, that potentially * is used to wrap several different methods. Wrappers are extremely simple - * they only require implementing two methods. * *
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * 
* * Bonus: * - Reports timing metrics by method name and wrapper index. * * Use cases: * - Preserving the input selection ranges before/after reconciliation. * Restoring selection even in the event of an unexpected error. * - Deactivating events while rearranging the DOM, preventing blurs/focuses, * while guaranteeing that afterwards, the event system is reactivated. * - Flushing a queue of collected DOM mutations to the main UI thread after a * reconciliation takes place in a worker thread. * - Invoking any collected `componentDidRender` callbacks after rendering new * content. * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue * to preserve the `scrollTop` (an automatic scroll aware DOM). * - (Future use case): Layout calculations before and after DOM upates. * * Transactional plugin API: * - A module that has an `initialize` method that returns any precomputation. * - and a `close` method that accepts the precomputation. `close` is invoked * when the wrapped process is completed, or has failed. * * @param {Array} transactionWrapper Wrapper modules * that implement `initialize` and `close`. * @return {Transaction} Single transaction for reuse in thread. * * @class Transaction */ var Mixin = { /** * Sets up this instance so that it is prepared for collecting metrics. Does * so such that this setup method may be used on an instance that is already * initialized, in a way that does not consume additional memory upon reuse. * That can be useful if you decide to make your subclass of this mixin a * "PooledClass". */ reinitializeTransaction: function() { this.transactionWrappers = this.getTransactionWrappers(); if (!this.wrapperInitData) { this.wrapperInitData = []; } else { this.wrapperInitData.length = 0; } if (!this.timingMetrics) { this.timingMetrics = {}; } this.timingMetrics.methodInvocationTime = 0; if (!this.timingMetrics.wrapperInitTimes) { this.timingMetrics.wrapperInitTimes = []; } else { this.timingMetrics.wrapperInitTimes.length = 0; } if (!this.timingMetrics.wrapperCloseTimes) { this.timingMetrics.wrapperCloseTimes = []; } else { this.timingMetrics.wrapperCloseTimes.length = 0; } this._isInTransaction = false; }, _isInTransaction: false, /** * @abstract * @return {Array} Array of transaction wrappers. */ getTransactionWrappers: null, isInTransaction: function() { return !!this._isInTransaction; }, /** * Executes the function within a safety window. Use this for the top level * methods that result in large amounts of computation/mutations that would * need to be safety checked. * * @param {function} method Member of scope to call. * @param {Object} scope Scope to invoke from. * @param {Object?=} args... Arguments to pass to the method (optional). * Helps prevent need to bind in many cases. * @returns Return value from `method`. */ perform: function(method, scope, a, b, c, d, e, f) { throwIf(this.isInTransaction(), DUAL_TRANSACTION); var memberStart = Date.now(); var err = null; var ret; try { this.initializeAll(); ret = method.call(scope, a, b, c, d, e, f); } catch (ie_requires_catch) { err = ie_requires_catch; } finally { var memberEnd = Date.now(); this.methodInvocationTime += (memberEnd - memberStart); try { this.closeAll(); } catch (closeAllErr) { err = err || closeAllErr; } } if (err) { throw err; } return ret; }, initializeAll: function() { this._isInTransaction = true; var transactionWrappers = this.transactionWrappers; var wrapperInitTimes = this.timingMetrics.wrapperInitTimes; var err = null; for (var i = 0; i < transactionWrappers.length; i++) { var initStart = Date.now(); var wrapper = transactionWrappers[i]; try { this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null; } catch (initErr) { err = err || initErr; // Remember the first error. this.wrapperInitData[i] = Transaction.OBSERVED_ERROR; } finally { var curInitTime = wrapperInitTimes[i]; var initEnd = Date.now(); wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart); } } if (err) { throw err; } }, /** * Invokes each of `this.transactionWrappers.close[i]` functions, passing into * them the respective return values of `this.transactionWrappers.init[i]` * (`close`rs that correspond to initializers that failed will not be * invoked). */ closeAll: function() { throwIf(!this.isInTransaction(), MISSING_TRANSACTION); var transactionWrappers = this.transactionWrappers; var wrapperCloseTimes = this.timingMetrics.wrapperCloseTimes; var err = null; for (var i = 0; i < transactionWrappers.length; i++) { var wrapper = transactionWrappers[i]; var closeStart = Date.now(); var initData = this.wrapperInitData[i]; try { if (initData !== Transaction.OBSERVED_ERROR) { wrapper.close && wrapper.close.call(this, initData); } } catch (closeErr) { err = err || closeErr; // Remember the first error. } finally { var closeEnd = Date.now(); var curCloseTime = wrapperCloseTimes[i]; wrapperCloseTimes[i] = (curCloseTime || 0) + (closeEnd - closeStart); } } this.wrapperInitData.length = 0; this._isInTransaction = false; if (err) { throw err; } } }; var Transaction = { Mixin: Mixin, /** * Token to look for to determine if an error occured. */ OBSERVED_ERROR: {} }; module.exports = Transaction; })() },{"./throwIf":31}],41:[function(require,module,exports){ (function(){/** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactMultiChild */ "use strict"; var ReactComponent = require("./ReactComponent"); /** * Given a `curChild` and `newChild`, determines if `curChild` should be managed * as it exists, as opposed to being destroyed and/or replaced. * @param {?ReactComponent} curChild * @param {?ReactComponent} newChild * @return {!boolean} Whether or not `curChild` should be updated with * `newChild`'s props */ function shouldManageExisting(curChild, newChild) { return curChild && newChild && curChild.constructor === newChild.constructor; } /** * `ReactMultiChild` provides common functionality for components that have * multiple children. Standard `ReactCompositeComponent`s do not currently have * multiple children. `ReactNativeComponent`s do, however. Other specially * reconciled components will also have multiple children. Contains three * internally used properties that are used to keep track of state throughout * the `updateMultiChild` process. * * @class ReactMultiChild */ /** * @lends `ReactMultiChildMixin`. */ var ReactMultiChildMixin = { enqueueMarkupAt: function(markup, insertAt) { this.domOperations = this.domOperations || []; this.domOperations.push({insertMarkup: markup, finalIndex: insertAt}); }, enqueueMove: function(originalIndex, finalIndex) { this.domOperations = this.domOperations || []; this.domOperations.push({moveFrom: originalIndex, finalIndex: finalIndex}); }, enqueueUnmountChildByName: function(name, removeChild) { if (ReactComponent.isValidComponent(removeChild)) { this.domOperations = this.domOperations || []; this.domOperations.push({removeAt: removeChild._domIndex}); removeChild.unmountComponent && removeChild.unmountComponent(); delete this._renderedChildren[name]; } }, /** * Process any pending DOM operations that have been accumulated when updating * the UI. By default, we execute the injected `DOMIDOperations` module's * `manageChildrenByParentID` which does executes the DOM operations without * any animation. It can be used as a reference implementation for special * animation based implementations. * * @abstract */ processChildDOMOperationsQueue: function() { if (this.domOperations) { ReactComponent.DOMIDOperations .manageChildrenByParentID(this._rootNodeID, this.domOperations); this.domOperations = null; } }, unmountMultiChild: function() { var renderedChildren = this._renderedChildren; for (var name in renderedChildren) { if (renderedChildren.hasOwnProperty(name) && renderedChildren[name]) { var renderedChild = renderedChildren[name]; renderedChild.unmountComponent && renderedChild.unmountComponent(); } } this._renderedChildren = null; }, /** * Generates markup for a component that holds multiple children. #todo: Allow * all `ReactMultiChildMixin`s to support having arrays of children without a * container node. This current implementation may assume that children exist * at domIndices [0, parentNode.length]. * * Has side effects of (likely) causing events to be registered. Also, every * component instance may only be rendered once. * * @param {?Object} children Flattened children object. * @return {!String} The rendered markup. */ mountMultiChild: function(children, transaction) { var accum = ''; var index = 0; for (var name in children) { var child = children[name]; if (children.hasOwnProperty(name) && child) { accum += child.mountComponent( this._rootNodeID + '.' + name, transaction ); child._domIndex = index; index++; } } this._renderedChildren = children; // children are in just the right form! this.domOperations = null; return accum; }, /** * Reconciles new children with old children in three phases. * * - Adds new content while updating existing children that should remain. * - Remove children that are no longer present in the next children. * - As a very last step, moves existing dom structures around. * - (Comment 1) `curChildrenDOMIndex` is the largest index of the current * rendered children that appears in the next children and did not need to * be "moved". * - (Comment 2) This is the key insight. If any non-removed child's previous * index is less than `curChildrenDOMIndex` it must be moved. * * @param {?Object} children Flattened children object. */ updateMultiChild: function(nextChildren, transaction) { if (!nextChildren && !this._renderedChildren) { return; } else if (nextChildren && !this._renderedChildren) { this._renderedChildren = {}; // lazily allocate backing store with nothing } else if (!nextChildren && this._renderedChildren) { nextChildren = {}; } var rootDomIdDot = this._rootNodeID + '.'; var markupBuffer = null; // Accumulate adjacent new children markup. var numPendingInsert = 0; // How many root nodes are waiting in markupBuffer var loopDomIndex = 0; // Index of loop through new children. var curChildrenDOMIndex = 0; // See (Comment 1) for (var name in nextChildren) { if (!nextChildren.hasOwnProperty(name)) {continue;} var curChild = this._renderedChildren[name]; var nextChild = nextChildren[name]; if (shouldManageExisting(curChild, nextChild)) { if (markupBuffer) { this.enqueueMarkupAt(markupBuffer, loopDomIndex - numPendingInsert); markupBuffer = null; } numPendingInsert = 0; if (curChild._domIndex < curChildrenDOMIndex) { // (Comment 2) this.enqueueMove(curChild._domIndex, loopDomIndex); } curChildrenDOMIndex = Math.max(curChild._domIndex, curChildrenDOMIndex); !nextChild.props.isStatic && curChild.receiveProps(nextChild.props, transaction); curChild._domIndex = loopDomIndex; } else { if (curChild) { // !shouldUpdate && curChild => delete this.enqueueUnmountChildByName(name, curChild); curChildrenDOMIndex = Math.max(curChild._domIndex, curChildrenDOMIndex); } if (nextChild) { // !shouldUpdate && nextChild => insert this._renderedChildren[name] = nextChild; var nextMarkup = nextChild.mountComponent(rootDomIdDot + name, transaction); markupBuffer = markupBuffer ? markupBuffer + nextMarkup : nextMarkup; numPendingInsert++; nextChild._domIndex = loopDomIndex; } } loopDomIndex = nextChild ? loopDomIndex + 1 : loopDomIndex; } if (markupBuffer) { this.enqueueMarkupAt(markupBuffer, loopDomIndex - numPendingInsert); } for (var childName in this._renderedChildren) { // from other direction if (!this._renderedChildren.hasOwnProperty(childName)) { continue; } var child = this._renderedChildren[childName]; if (child && !nextChildren[childName]) { this.enqueueUnmountChildByName(childName, child); } } this.processChildDOMOperationsQueue(); } }; var ReactMultiChild = { Mixin: ReactMultiChildMixin }; module.exports = ReactMultiChild; })() },{"./ReactComponent":3}],42:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule escapeTextForBrowser */ "use strict"; var throwIf = require("./throwIf"); var ESCAPE_TYPE_ERR; if (true) { ESCAPE_TYPE_ERR = 'The React core has attempted to escape content that is of a ' + 'mysterious type (object etc) Escaping only works on numbers and strings'; } var ESCAPE_LOOKUP = { "&": "&", ">": ">", "<": "<", "\"": """, "'": "'", "/": "/" }; function escaper(match) { return ESCAPE_LOOKUP[match]; } var escapeTextForBrowser = function (text) { var type = typeof text; var invalid = type === 'object'; if (true) { throwIf(invalid, ESCAPE_TYPE_ERR); } if (text === '' || invalid) { return ''; } else { if (type === 'string') { return text.replace(/[&><"'\/]/g, escaper); } else { return (''+text).replace(/[&><"'\/]/g, escaper); } } }; module.exports = escapeTextForBrowser; },{"./throwIf":31}],43:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule flattenChildren */ "use strict"; var ReactTextComponent = require("./ReactTextComponent"); var escapeTextForBrowser = require("./escapeTextForBrowser"); var throwIf = require("./throwIf"); /** * @polyFill Array.isArray */ var INVALID_CHILD = 'INVALID_CHILD'; if (true) { INVALID_CHILD = 'You may not pass a child of that type to a React component. It ' + 'is a common mistake to try to pass a standard browser DOM element ' + 'as a child of a React component.'; } /** * If there is only a single child, it still needs a name. */ var ONLY_CHILD_NAME = '0'; var flattenChildrenImpl = function(res, children, nameSoFar) { if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { flattenChildrenImpl(res, children[i], nameSoFar + '[' + i + ']'); } } else { var type = typeof children; var isOnlyChild = nameSoFar === ''; var storageName = isOnlyChild ? ONLY_CHILD_NAME : nameSoFar; if (children === null || children === undefined || type === 'boolean') { res[storageName] = null; } else if (children.mountComponentIntoNode) { /* We found a component instance */ res[storageName] = children; } else { if (type === 'object') { throwIf(children && children.nodeType === 1, INVALID_CHILD); for (var key in children) { if (children.hasOwnProperty(key)) { flattenChildrenImpl( res, children[key], nameSoFar + '{' + escapeTextForBrowser(key) + '}' ); } } } else if (type === 'string') { res[storageName] = new ReactTextComponent(children); } else if (type === 'number') { res[storageName] = new ReactTextComponent('' + children); } } } }; /** * Flattens children that are typically specified as `props.children`. * @return {!Object} flattened children keyed by name. */ function flattenChildren(children) { if (children === null || children === undefined) { return children; } var result = {}; flattenChildrenImpl(result, children, ''); return result; } module.exports = flattenChildren; },{"./ReactTextComponent":65,"./escapeTextForBrowser":42,"./throwIf":31}],45:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule mergeHelpers * * requiresPolyfills: Array.isArray */ "use strict"; var keyMirror = require("./keyMirror"); var throwIf = require("./throwIf"); /* * Maximum number of levels to traverse. Will catch circular structures. * @const */ var MAX_MERGE_DEPTH = 36; var ERRORS = keyMirror({ MERGE_ARRAY_FAIL: null, MERGE_CORE_FAILURE: null, MERGE_TYPE_USAGE_FAILURE: null, MERGE_DEEP_MAX_LEVELS: null, MERGE_DEEP_NO_ARR_STRATEGY: null }); if (true) { ERRORS = { MERGE_ARRAY_FAIL: 'Unsupported type passed to a merge function. You may have passed a ' + 'structure that contains an array and the merge function does not know ' + 'how to merge arrays. ', MERGE_CORE_FAILURE: 'Critical assumptions about the merge functions have been violated. ' + 'This is the fault of the merge functions themselves, not necessarily ' + 'the callers.', MERGE_TYPE_USAGE_FAILURE: 'Calling merge function with invalid types. You may call merge ' + 'functions (non-array non-terminal) OR (null/undefined) arguments. ' + 'mergeInto functions have the same requirements but with an added ' + 'restriction that the first parameter must not be null/undefined.', MERGE_DEEP_MAX_LEVELS: 'Maximum deep merge depth exceeded. You may attempting to merge ' + 'circular structures in an unsupported way.', MERGE_DEEP_NO_ARR_STRATEGY: 'You must provide an array strategy to deep merge functions to ' + 'instruct the deep merge how to resolve merging two arrays.' }; } /** * We won't worry about edge cases like new String('x') or new Boolean(true). * Functions are considered terminals, and arrays are not. * @param {*} o The item/object/value to test. * @return {boolean} true iff the argument is a terminal. */ var isTerminal = function(o) { return typeof o !== 'object' || o === null; }; var mergeHelpers = { MAX_MERGE_DEPTH: MAX_MERGE_DEPTH, isTerminal: isTerminal, /** * Converts null/undefined values into empty object. * * @param {?Object=} arg Argument to be normalized (nullable optional) * @return {!Object} */ normalizeMergeArg: function(arg) { return arg === undefined || arg === null ? {} : arg; }, /** * If merging Arrays, a merge strategy *must* be supplied. If not, it is * likely the caller's fault. If this function is ever called with anything * but `one` and `two` being `Array`s, it is the fault of the merge utilities. * * @param {*} one Array to merge into. * @param {*} two Array to merge from. */ checkMergeArrayArgs: function(one, two) { throwIf( !Array.isArray(one) || !Array.isArray(two), ERRORS.MERGE_CORE_FAILURE ); }, /** * @param {*} one Object to merge into. * @param {*} two Object to merge from. */ checkMergeObjectArgs: function(one, two) { mergeHelpers.checkMergeObjectArg(one); mergeHelpers.checkMergeObjectArg(two); }, /** * @param {*} arg */ checkMergeObjectArg: function(arg) { throwIf(isTerminal(arg) || Array.isArray(arg), ERRORS.MERGE_CORE_FAILURE); }, /** * Checks that a merge was not given a circular object or an object that had * too great of depth. * * @param {number} Level of recursion to validate against maximum. */ checkMergeLevel: function(level) { throwIf(level >= MAX_MERGE_DEPTH, ERRORS.MERGE_DEEP_MAX_LEVELS); }, /** * Checks that a merge was not given a circular object or an object that had * too great of depth. * * @param {number} Level of recursion to validate against maximum. */ checkArrayStrategy: function(strategy) { throwIf( strategy !== undefined && !(strategy in mergeHelpers.ArrayStrategies), ERRORS.MERGE_DEEP_NO_ARR_STRATEGY ); }, /** * Set of possible behaviors of merge algorithms when encountering two Arrays * that must be merged together. * - `clobber`: The left `Array` is ignored. * - `indexByIndex`: The result is achieved by recursively deep merging at * each index. (not yet supported.) */ ArrayStrategies: keyMirror({ Clobber: true, IndexByIndex: true }), ERRORS: ERRORS }; module.exports = mergeHelpers; },{"./keyMirror":11,"./throwIf":31}],47:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EventConstants */ "use strict"; var keyMirror = require("./keyMirror"); var PropagationPhases = keyMirror({bubbled: null, captured: null}); /** * Types of raw signals from the browser caught at the top level. */ var topLevelTypes = keyMirror({ topBlur: null, topChange: null, topClick: null, topDOMCharacterDataModified: null, topDoubleClick: null, topFocus: null, topKeyDown: null, topKeyPress: null, topKeyUp: null, topMouseDown: null, topMouseMove: null, topMouseOut: null, topMouseOver: null, topMouseUp: null, topMouseWheel: null, topScroll: null, topSubmit: null, topTouchCancel: null, topTouchEnd: null, topTouchMove: null, topTouchStart: null }); var EventConstants = { topLevelTypes: topLevelTypes, PropagationPhases: PropagationPhases }; module.exports = EventConstants; },{"./keyMirror":11}],48:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule NormalizedEventListener */ "use strict"; var EventListener = require("./EventListener"); /** * @param {?Event} eventParam Event parameter from an attached listener. * @return {Event} Normalized event object. * @private */ function normalizeEvent(eventParam) { var normalized = eventParam || window.event; // In some browsers (OLD FF), setting the target throws an error. A good way // to tell if setting the target will throw an error, is to check if the event // has a `target` property. Safari events have a `target` but it's not always // normalized. Even if a `target` property exists, it's good to only set the // target property if we realize that a change will actually take place. var hasTargetProperty = 'target' in normalized; var eventTarget = normalized.target || normalized.srcElement || window; // Safari may fire events on text nodes (Node.TEXT_NODE is 3) // @see http://www.quirksmode.org/js/events_properties.html var textNodeNormalizedTarget = (eventTarget.nodeType === 3) ? eventTarget.parentNode : eventTarget; if (!hasTargetProperty || normalized.target !== textNodeNormalizedTarget) { // Create an object that inherits from the native event so that we can set // `target` on it. (It is read-only and setting it throws in strict mode). normalized = Object.create(normalized); normalized.target = textNodeNormalizedTarget; } return normalized; } function createNormalizedCallback(cb) { return function(unfixedNativeEvent) { cb(normalizeEvent(unfixedNativeEvent)); }; } var NormalizedEventListener = { /** * Listens to bubbled events on a DOM node. * * NOTE: The listener will be invoked with a normalized event object. * * @param {DOMElement} el DOM element to register listener on. * @param {string} handlerBaseName Event name, e.g. "click". * @param {function} cb Callback function. * @public */ listen: function(el, handlerBaseName, cb) { EventListener.listen(el, handlerBaseName, createNormalizedCallback(cb)); }, /** * Listens to captured events on a DOM node. * * NOTE: The listener will be invoked with a normalized event object. * * @param {DOMElement} el DOM element to register listener on. * @param {string} handlerBaseName Event name, e.g. "click". * @param {function} cb Callback function. * @public */ capture: function(el, handlerBaseName, cb) { EventListener.capture(el, handlerBaseName, createNormalizedCallback(cb)); } }; module.exports = NormalizedEventListener; },{"./EventListener":66}],49:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule isEventSupported */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var testNode; if (ExecutionEnvironment.canUseDOM) { testNode = document.createElement('div'); } /** * Checks if an event is supported in the current execution environment. * * NOTE: This will not work correctly for non-generic events such as `change`, * `reset`, `load`, `error`, and `select`. * * Borrows from Modernizr. * * @param {string} eventNameSuffix Event name, e.g. "click". * @param {?boolean} capture Check if the capture phase is supported. * @return {boolean} True if the event is supported. * @internal * @license Modernizr 3.0.0pre (Custom Build) | MIT */ function isEventSupported(eventNameSuffix, capture) { if (!testNode || (capture && !testNode.addEventListener)) { return false; } var element = document.createElement('div'); var eventName = 'on' + eventNameSuffix; var isSupported = eventName in element; if (!isSupported) { element.setAttribute(eventName, ''); isSupported = typeof element[eventName] === 'function'; if (typeof element[eventName] !== 'undefined') { element[eventName] = undefined; } element.removeAttribute(eventName); } element = null; return isSupported; } module.exports = isEventSupported; },{"./ExecutionEnvironment":14}],52:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EventPropagators */ "use strict"; var CallbackRegistry = require("./CallbackRegistry"); var EventConstants = require("./EventConstants"); var accumulate = require("./accumulate"); var forEachAccumulated = require("./forEachAccumulated"); var getListener = CallbackRegistry.getListener; var PropagationPhases = EventConstants.PropagationPhases; /** * Injected dependencies: */ /** * - `InstanceHandle`: [required] Module that performs logical traversals of DOM * hierarchy given ids of the logical DOM elements involved. */ var injection = { InstanceHandle: null, injectInstanceHandle: function(InjectedInstanceHandle) { injection.InstanceHandle = InjectedInstanceHandle; if (true) { injection.validate(); } }, validate: function() { var invalid = !injection.InstanceHandle|| !injection.InstanceHandle.traverseTwoPhase || !injection.InstanceHandle.traverseEnterLeave; if (invalid) { throw new Error('InstanceHandle not injected before use!'); } } }; /** * Some event types have a notion of different registration names for different * "phases" of propagation. This finds listeners by a given phase. */ function listenerAtPhase(id, abstractEvent, propagationPhase) { var registrationName = abstractEvent.type.phasedRegistrationNames[propagationPhase]; return getListener(id, registrationName); } /** * Tags an `AbstractEvent` with dispatched listeners. Creating this function * here, allows us to not have to bind or create functions for each event. * Mutating the event's members allows us to not have to create a wrapping * "dispatch" object that pairs the event with the listener. */ function accumulateDirectionalDispatches(domID, upwards, abstractEvent) { if (true) { if (!domID) { throw new Error('Dispatching id must not be null'); } injection.validate(); } var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; var listener = listenerAtPhase(domID, abstractEvent, phase); if (listener) { abstractEvent._dispatchListeners = accumulate(abstractEvent._dispatchListeners, listener); abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, domID); } } /** * Collect dispatches (must be entirely collected before dispatching - see unit * tests). Lazily allocate the array to conserve memory. We must loop through * each event and perform the traversal for each one. We can not perform a * single traversal for the entire collection of events because each event may * have a different target. */ function accumulateTwoPhaseDispatchesSingle(abstractEvent) { if (abstractEvent && abstractEvent.type.phasedRegistrationNames) { injection.InstanceHandle.traverseTwoPhase( abstractEvent.abstractTargetID, accumulateDirectionalDispatches, abstractEvent ); } } /** * Accumulates without regard to direction, does not look for phased * registration names. Same as `accumulateDirectDispatchesSingle` but without * requiring that the `abstractTargetID` be the same as the dispatched ID. */ function accumulateDispatches(id, ignoredDirection, abstractEvent) { if (abstractEvent && abstractEvent.type.registrationName) { var listener = getListener(id, abstractEvent.type.registrationName); if (listener) { abstractEvent._dispatchListeners = accumulate(abstractEvent._dispatchListeners, listener); abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, id); } } } /** * Accumulates dispatches on an `AbstractEvent`, but only for the * `abstractTargetID`. * @param {AbstractEvent} abstractEvent */ function accumulateDirectDispatchesSingle(abstractEvent) { if (abstractEvent && abstractEvent.type.registrationName) { accumulateDispatches(abstractEvent.abstractTargetID, null, abstractEvent); } } function accumulateTwoPhaseDispatches(abstractEvents) { if (true) { injection.validate(); } forEachAccumulated(abstractEvents, accumulateTwoPhaseDispatchesSingle); } function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { if (true) { injection.validate(); } injection.InstanceHandle.traverseEnterLeave( fromID, toID, accumulateDispatches, leave, enter ); } function accumulateDirectDispatches(abstractEvents) { if (true) { injection.validate(); } forEachAccumulated(abstractEvents, accumulateDirectDispatchesSingle); } /** * A small set of propagation patterns, each of which will accept a small amount * of information, and generate a set of "dispatch ready event objects" - which * are sets of events that have already been annotated with a set of dispatched * listener functions/ids. The API is designed this way to discourage these * propagation strategies from actually executing the dispatches, since we * always want to collect the entire set of dispatches before executing event a * single one. * * @constructor EventPropagators */ var EventPropagators = { accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, accumulateDirectDispatches: accumulateDirectDispatches, accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, injection: injection }; module.exports = EventPropagators; },{"./CallbackRegistry":54,"./EventConstants":47,"./accumulate":56,"./forEachAccumulated":57}],53:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule AbstractEvent */ "use strict"; var BrowserEnv = require("./BrowserEnv"); var PooledClass = require("./PooledClass"); var TouchEventUtils = require("./TouchEventUtils"); var throwIf = require("./throwIf"); // Only accessed in __DEV__ var CLONE_TYPE_ERR; if (true) { CLONE_TYPE_ERR = 'You may only clone instances of AbstractEvent for ' + 'persistent references. Check yourself.'; } var MAX_POOL_SIZE = 20; /** * AbstractEvent copy constructor. @see `PooledClass`. Provides a single place * to define all cross browser normalization of DOM events. Does not attempt to * extend a native event, rather creates a completely new object that has a * reference to the nativeEvent through .nativeEvent member. The property .data * should hold all data that is extracted from the event in a cross browser * manner. Application code should use the data field when possible, not the * unreliable native event. */ function AbstractEvent( abstractEventType, abstractTargetID, // Allows the abstract target to differ from native. originatingTopLevelEventType, nativeEvent, data) { this.type = abstractEventType; this.abstractTargetID = abstractTargetID || ''; this.originatingTopLevelEventType = originatingTopLevelEventType; this.nativeEvent = nativeEvent; this.data = data; // TODO: Deprecate storing target - doesn't always make sense for some types this.target = nativeEvent && nativeEvent.target; /** * As a performance optimization, we tag the existing event with the listeners * (or listener [singular] if only one). This avoids having to package up an * abstract event along with the set of listeners into a wrapping "dispatch" * object. No one should ever read this property except event system and * plugin/dispatcher code. We also tag the abstract event with a parallel * ID array. _dispatchListeners[i] is being dispatched to a DOM node at ID * _dispatchIDs[i]. The lengths should never, ever, ever be different. */ this._dispatchListeners = null; this._dispatchIDs = null; this.isPropagationStopped = false; } /** `PooledClass` looks for this. */ AbstractEvent.poolSize = MAX_POOL_SIZE; /** * `PooledClass` looks for `destructor` on each instance it releases. We need to * ensure that we remove all references to listeners which could trap large * amounts of memory in their closures. */ AbstractEvent.prototype.destructor = function() { this.target = null; this._dispatchListeners = null; this._dispatchIDs = null; }; /** * Enhance the `AbstractEvent` class to have pooling abilities. We instruct * `PooledClass` that our copy constructor accepts five arguments (this is just * a performance optimization). These objects are instantiated frequently. */ PooledClass.addPoolingTo(AbstractEvent, PooledClass.fiveArgumentPooler); AbstractEvent.prototype.stopPropagation = function() { this.isPropagationStopped = true; if (this.nativeEvent.stopPropagation) { this.nativeEvent.stopPropagation(); } // IE8 only understands cancelBubble, not stopPropagation(). this.nativeEvent.cancelBubble = true; }; AbstractEvent.prototype.preventDefault = function() { AbstractEvent.preventDefaultOnNativeEvent(this.nativeEvent); }; /** * Utility function for preventing default in cross browser manner. */ AbstractEvent.preventDefaultOnNativeEvent = function(nativeEvent) { if (nativeEvent.preventDefault) { nativeEvent.preventDefault(); } else { nativeEvent.returnValue = false; } }; /** * @param {Element} target The target element. */ AbstractEvent.normalizeScrollDataFromTarget = function(target) { return { scrollTop: target.scrollTop, scrollLeft: target.scrollLeft, clientWidth: target.clientWidth, clientHeight: target.clientHeight, scrollHeight: target.scrollHeight, scrollWidth: target.scrollWidth }; }; /* * There are some normalizations that need to happen for various browsers. In * addition to replacing the general event fixing with a framework such as * jquery, we need to normalize mouse events here. Code below is mostly borrowed * from: jScrollPane/script/jquery.mousewheel.js */ AbstractEvent.normalizeMouseWheelData = function(nativeEvent) { var delta = 0; var deltaX = 0; var deltaY = 0; /* traditional scroll wheel data */ if ( nativeEvent.wheelDelta ) { delta = nativeEvent.wheelDelta/120; } if ( nativeEvent.detail ) { delta = -nativeEvent.detail/3; } /* Multidimensional scroll (touchpads) with deltas */ deltaY = delta; /* Gecko based browsers */ if (nativeEvent.axis !== undefined && nativeEvent.axis === nativeEvent.HORIZONTAL_AXIS ) { deltaY = 0; deltaX = -delta; } /* Webkit based browsers */ if (nativeEvent.wheelDeltaY !== undefined ) { deltaY = nativeEvent.wheelDeltaY/120; } if (nativeEvent.wheelDeltaX !== undefined ) { deltaX = -nativeEvent.wheelDeltaX/120; } return { delta: delta, deltaX: deltaX, deltaY: deltaY }; }; /** * I <3 Quirksmode.org: * http://www.quirksmode.org/js/events_properties.html */ AbstractEvent.isNativeClickEventRightClick = function(nativeEvent) { return nativeEvent.which ? nativeEvent.which === 3 : nativeEvent.button ? nativeEvent.button === 2 : false; }; AbstractEvent.normalizePointerData = function(nativeEvent) { return { globalX: AbstractEvent.eventPageX(nativeEvent), globalY: AbstractEvent.eventPageY(nativeEvent), rightMouseButton: AbstractEvent.isNativeClickEventRightClick(nativeEvent) }; }; AbstractEvent.normalizeDragEventData = function(nativeEvent, globalX, globalY, startX, startY) { return { globalX: globalX, globalY: globalY, startX: startX, startY: startY }; }; /** * Warning: It is possible to move your finger on a touch surface, yet not * effect the `eventPageX/Y` because the touch had caused a scroll that * compensated for your movement. To track movements across the page, prevent * default to avoid scrolling, and control scrolling in javascript. */ /** * Gets the exact position of a touch/mouse event on the page with respect to * the document body. The only reason why this method is needed instead of using * `TouchEventUtils.extractSingleTouch` is to support IE8-. Mouse events in all * browsers except IE8- contain a pageY. IE8 and below require clientY * computation: * * @param {Event} nativeEvent Native event, possibly touch or mouse. * @return {number} Coordinate with respect to document body. */ AbstractEvent.eventPageY = function(nativeEvent) { var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent); if (singleTouch) { return singleTouch.pageY; } else if (typeof nativeEvent.pageY !== 'undefined') { return nativeEvent.pageY; } else { return nativeEvent.clientY + BrowserEnv.currentPageScrollTop; } }; /** * @see `AbstractEvent.eventPageY`. * * @param {Event} nativeEvent Native event, possibly touch or mouse. * @return {number} Coordinate with respect to document body. */ AbstractEvent.eventPageX = function(nativeEvent) { var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent); if (singleTouch) { return singleTouch.pageX; } else if (typeof nativeEvent.pageX !== 'undefined') { return nativeEvent.pageX; } else { return nativeEvent.clientX + BrowserEnv.currentPageScrollLeft; } }; /** * A semantic API around cloning an event for use in another event loop. We * clear out all dispatched `AbstractEvent`s after each event loop, adding them * back into the pool. This allows a way to hold onto a reference that won't be * added back into the pool. Please note that `AbstractEvent.nativeEvent` is * *not* cloned and you will run into problems in IE if you assume that it will * be! The moral of that story is to always normalize any data you need into the * `.data` field. The data field is not cloned either, but there won't be any * issues related to use of `.data` in a future event cycle so long as no part * of your application mutates it. We don't clone the private fields because * your application should never be accessing them. * * - TODO: In __DEV__ when "releasing" events, don't put them back into the * pool. Instead add ES5 getters on all their fields that throw errors so you * can detect any application that's hanging onto events and reusing them. * In prod - we can put them back into the pool for reuse. */ AbstractEvent.persistentCloneOf = function(abstractEvent) { if (true) { throwIf(!(abstractEvent instanceof AbstractEvent), CLONE_TYPE_ERR); } return new AbstractEvent( abstractEvent.type, abstractEvent.abstractTargetID, abstractEvent.originatingTopLevelEventType, abstractEvent.nativeEvent, abstractEvent.data, abstractEvent.target ); }; module.exports = AbstractEvent; },{"./BrowserEnv":46,"./PooledClass":37,"./TouchEventUtils":67,"./throwIf":31}],55:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EventPluginUtils */ "use strict"; var EventConstants = require("./EventConstants"); var AbstractEvent = require("./AbstractEvent"); var invariant = require("./invariant"); var topLevelTypes = EventConstants.topLevelTypes; function isEndish(topLevelType) { return topLevelType === topLevelTypes.topMouseUp || topLevelType === topLevelTypes.topTouchEnd || topLevelType === topLevelTypes.topTouchCancel; } function isMoveish(topLevelType) { return topLevelType === topLevelTypes.topMouseMove || topLevelType === topLevelTypes.topTouchMove; } function isStartish(topLevelType) { return topLevelType === topLevelTypes.topMouseDown || topLevelType === topLevelTypes.topTouchStart; } function storePageCoordsIn(obj, nativeEvent) { var pageX = AbstractEvent.eventPageX(nativeEvent); var pageY = AbstractEvent.eventPageY(nativeEvent); obj.pageX = pageX; obj.pageY = pageY; } function eventDistance(coords, nativeEvent) { var pageX = AbstractEvent.eventPageX(nativeEvent); var pageY = AbstractEvent.eventPageY(nativeEvent); return Math.pow( Math.pow(pageX - coords.pageX, 2) + Math.pow(pageY - coords.pageY, 2), 0.5 ); } var validateEventDispatches; if (true) { validateEventDispatches = function(abstractEvent) { var dispatchListeners = abstractEvent._dispatchListeners; var dispatchIDs = abstractEvent._dispatchIDs; var listenersIsArr = Array.isArray(dispatchListeners); var idsIsArr = Array.isArray(dispatchIDs); var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; invariant( idsIsArr === listenersIsArr && IDsLen === listenersLen, 'EventPluginUtils: Invalid `abstractEvent`.' ); }; } /** * Invokes `cb(abstractEvent, listener, id)`. Avoids using call if no scope is * provided. The `(listener,id)` pair effectively forms the "dispatch" but are * kept separate to conserve memory. */ function forEachEventDispatch(abstractEvent, cb) { var dispatchListeners = abstractEvent._dispatchListeners; var dispatchIDs = abstractEvent._dispatchIDs; if (true) { validateEventDispatches(abstractEvent); } if (Array.isArray(dispatchListeners)) { var i; for ( i = 0; i < dispatchListeners.length && !abstractEvent.isPropagationStopped; i++) { // Listeners and IDs are two parallel arrays that are always in sync. cb(abstractEvent, dispatchListeners[i], dispatchIDs[i]); } } else if (dispatchListeners) { cb(abstractEvent, dispatchListeners, dispatchIDs); } } /** * Default implementation of PluginModule.executeDispatch(). * @param {AbstractEvent} AbstractEvent to handle * @param {function} Application-level callback * @param {string} domID DOM id to pass to the callback. */ function executeDispatch(abstractEvent, listener, domID) { listener(abstractEvent, domID); } /** * Standard/simple iteration through an event's collected dispatches. */ function executeDispatchesInOrder(abstractEvent, executeDispatch) { forEachEventDispatch(abstractEvent, executeDispatch); abstractEvent._dispatchListeners = null; abstractEvent._dispatchIDs = null; } /** * Standard/simple iteration through an event's collected dispatches, but stops * at the first dispatch execution returning true, and returns that id. * * @returns id of the first dispatch execution who's listener returns true, or * null if no listener returned true. */ function executeDispatchesInOrderStopAtTrue(abstractEvent) { var dispatchListeners = abstractEvent._dispatchListeners; var dispatchIDs = abstractEvent._dispatchIDs; if (true) { validateEventDispatches(abstractEvent); } if (Array.isArray(dispatchListeners)) { var i; for ( i = 0; i < dispatchListeners.length && !abstractEvent.isPropagationStopped; i++) { // Listeners and IDs are two parallel arrays that are always in sync. if (dispatchListeners[i](abstractEvent, dispatchIDs[i])) { return dispatchIDs[i]; } } } else if (dispatchListeners) { if (dispatchListeners(abstractEvent, dispatchIDs)) { return dispatchIDs; } } return null; } /** * Execution of a "direct" dispatch - there must be at most one dispatch * accumulated on the event or it is considered an error. It doesn't really make * sense for an event with multiple dispatches (bubbled) to keep track of the * return values at each dispatch execution, but it does tend to make sense when * dealing with "direct" dispatches. * * @returns The return value of executing the single dispatch. */ function executeDirectDispatch(abstractEvent) { if (true) { validateEventDispatches(abstractEvent); } var dispatchListener = abstractEvent._dispatchListeners; var dispatchID = abstractEvent._dispatchIDs; invariant( !Array.isArray(dispatchListener), 'executeDirectDispatch(...): Invalid `abstractEvent`.' ); var res = dispatchListener ? dispatchListener(abstractEvent, dispatchID) : null; abstractEvent._dispatchListeners = null; abstractEvent._dispatchIDs = null; return res; } /** * @param {AbstractEvent} abstractEvent * @returns {bool} True iff number of dispatches accumulated is greater than 0. */ function hasDispatches(abstractEvent) { return !!abstractEvent._dispatchListeners; } /** * General utilities that are useful in creating custom Event Plugins. */ var EventPluginUtils = { isEndish: isEndish, isMoveish: isMoveish, isStartish: isStartish, storePageCoordsIn: storePageCoordsIn, eventDistance: eventDistance, executeDispatchesInOrder: executeDispatchesInOrder, executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, executeDirectDispatch: executeDirectDispatch, hasDispatches: hasDispatches, executeDispatch: executeDispatch }; module.exports = EventPluginUtils; },{"./EventConstants":47,"./AbstractEvent":53,"./invariant":10}],56:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule accumulate */ "use strict"; var throwIf = require("./throwIf"); var INVALID_ARGS = 'INVALID_ACCUM_ARGS'; if (true) { INVALID_ARGS = 'accumulate requires non empty (non-null, defined) next ' + 'values. All arrays accumulated must not contain any empty items.'; } /** * Accumulates items that must never be empty, into a result in a manner that * conserves memory - avoiding allocation of arrays until they are needed. The * accumulation may start and/or end up being a single element or an array * depending on the total count (if greater than one, an array is allocated). * Handles most common case first (starting with an empty current value and * acquiring one). * @returns {Accumulation} An accumulation which is either a single item or an * Array of items. */ function accumulate(cur, next) { var curValIsEmpty = cur == null; // Will test for emptiness (null/undef) var nextValIsEmpty = next === null; if (true) { throwIf(nextValIsEmpty, INVALID_ARGS); } if (nextValIsEmpty) { return cur; } else { if (curValIsEmpty) { return next; } else { // Both are not empty. Warning: Never call x.concat(y) when you are not // certain that x is an Array (x could be a string with concat method). var curIsArray = Array.isArray(cur); var nextIsArray = Array.isArray(next); if (curIsArray) { return cur.concat(next); } else { if (nextIsArray) { return [cur].concat(next); } else { return [cur, next]; } } } } } module.exports = accumulate; },{"./throwIf":31}],58:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule copyProperties */ /** * Copy properties from one or more objects (up to 5) into the first object. * This is a shallow copy. It mutates the first object and also returns it. * * NOTE: `arguments` has a very significant performance penalty, which is why * we don't support unlimited arguments. */ function copyProperties(obj, a, b, c, d, e, f) { obj = obj || {}; if (true) { if (f) { throw new Error('Too many arguments passed to copyProperties'); } } var args = [a, b, c, d, e]; var ii = 0, v; while (args[ii]) { v = args[ii++]; for (var k in v) { obj[k] = v[k]; } // IE ignores toString in object iteration.. See: // webreflection.blogspot.com/2007/07/quick-fix-internet-explorer-and.html if (v.hasOwnProperty && v.hasOwnProperty('toString') && (typeof v.toString != 'undefined') && (obj.toString !== v.toString)) { obj.toString = v.toString; } } return obj; } module.exports = copyProperties; },{}],60:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule hyphenate * @typechecks */ var _uppercasePattern = /([A-Z])/g; /** * Hyphenates a camelcased string, for example: * * > hyphenate('backgroundColor') * < "background-color" * * @param {string} string * @return {string} */ function hyphenate(string) { return string.replace(_uppercasePattern, '-$1').toLowerCase(); } module.exports = hyphenate; },{}],61:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule memoizeStringOnly * @typechecks */ "use strict"; /** * Memoizes the return value of a function that accepts one string argument. * * @param {function} callback * @return {function} */ function memoizeStringOnly(callback) { var cache = {}; return function(string) { if (cache.hasOwnProperty(string)) { return cache[string]; } else { return cache[string] = callback.call(this, string); } }; } module.exports = memoizeStringOnly; },{}],63:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule insertNodeAt */ "use strict"; /** * Inserts `node` at a particular child index. Other nodes move to make room. * @param {!Element} root The parent root node to insert into. * @param {!node} node The node to insert. * @param {!number} atIndex The index in `root` that `node` should exist at. */ function insertNodeAt(root, node, atIndex) { var childNodes = root.childNodes; // Remove from parent so that if node is already child of root, // `childNodes[atIndex]` already takes into account the removal. var curAtIndex = root.childNodes[atIndex]; if (curAtIndex === node) { return node; } if (node.parentNode) { node.parentNode.removeChild(node); } if (atIndex >= childNodes.length) { root.appendChild(node); } else { root.insertBefore(node, childNodes[atIndex]); } return node; } module.exports = insertNodeAt; },{}],66:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule EventListener */ /** * Upstream version of event listener. Does not take into account specific * nature of platform. */ var EventListener = { /** * Listens to bubbled events on a DOM node. * * @param {Element} el DOM element to register listener on. * @param {string} handlerBaseName 'click'/'mouseover' * @param {Function!} cb Callback function */ listen: function(el, handlerBaseName, cb) { if (el.addEventListener) { el.addEventListener(handlerBaseName, cb, false); } else if (el.attachEvent) { el.attachEvent('on' + handlerBaseName, cb); } }, /** * Listens to captured events on a DOM node. * * @see `EventListener.listen` for params. * @throws Exception if addEventListener is not supported. */ capture: function(el, handlerBaseName, cb) { if (!el.addEventListener) { console.error( 'You are attempting to use addEventlistener ' + 'in a browser that does not support it support it.' + 'This likely means that you will not receive events that ' + 'your application relies on (such as scroll).'); return; } else { el.addEventListener(handlerBaseName, cb, true); } } }; module.exports = EventListener; },{}],67:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule TouchEventUtils */ var TouchEventUtils = { /** * Utility function for common case of extracting out the primary touch from a * touch event. * - `touchEnd` events usually do not have the `touches` property. * http://stackoverflow.com/questions/3666929/ * mobile-sarai-touchend-event-not-firing-when-last-touch-is-removed * * @param {Event} nativeEvent Native event that may or may not be a touch. * @return {TouchesObject?} an object with pageX and pageY or null. */ extractSingleTouch: function(nativeEvent) { var touches = nativeEvent.touches; var changedTouches = nativeEvent.changedTouches; var hasTouches = touches && touches.length > 0; var hasChangedTouches = changedTouches && changedTouches.length > 0; return !hasTouches && hasChangedTouches ? changedTouches[0] : hasTouches ? touches[0] : nativeEvent; } }; module.exports = TouchEventUtils; },{}],59:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule dangerousStyleValue * @typechecks */ "use strict"; var CSSProperty = require("./CSSProperty"); /** * Convert a value into the proper css writable value. The `styleName` name * name should be logical (no hyphens), as specified in `CSSProperty.isNumber`. * * @param {string} styleName CSS property name such as `topMargin`. * @param {*} value CSS property value such as `10px`. * @return {string} Normalized style value with dimensions applied. */ function dangerousStyleValue(styleName, value) { // Note that we've removed escapeTextForBrowser() calls here since the // whole string will be escaped when the attribute is injected into // the markup. If you provide unsafe user data here they can inject // arbitrary CSS which may be problematic (I couldn't repro this): // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ // This is not an XSS hole but instead a potential CSS injection issue // which has lead to a greater discussion about how we're going to // trust URLs moving forward. See #2115901 if (value === null || value === false || value === true || value === '') { return ''; } if (isNaN(value)) { return !value ? '' : '' + value; } return CSSProperty.isNumber[styleName] ? '' + value : (value + 'px'); } module.exports = dangerousStyleValue; },{"./CSSProperty":68}],62:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule Danger */ "use strict"; var ExecutionEnvironment = require("./ExecutionEnvironment"); var throwIf = require("./throwIf"); var DOM_UNSUPPORTED; var NO_MARKUP_PARENT; var NO_MULTI_MARKUP; if (true) { DOM_UNSUPPORTED = 'You may not insert markup into the document while you are in a worker ' + 'thread. It\'s not you, it\'s me. This is likely the fault of the ' + 'framework. Please report this immediately.'; NO_MARKUP_PARENT = 'You have attempted to inject markup without a suitable parent. This is ' + 'likely the fault of the framework - please report immediately.'; NO_MULTI_MARKUP = 'The framework has attempted to either insert zero or multiple markup ' + 'roots into a single location when it should not. This is a serious ' + 'error - a fault of the framework - please report immediately.'; } var validateMarkupParams; if (true) { validateMarkupParams = function(parentNode, markup) { throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); throwIf(!parentNode || !parentNode.tagName, NO_MARKUP_PARENT); throwIf(!markup, NO_MULTI_MARKUP); }; } var dummies = {}; function getParentDummy(parent) { var parentTag = parent.tagName; return dummies[parentTag] || (dummies[parentTag] = document.createElement(parentTag)); } /** * Inserts node after 'after'. If 'after' is null, inserts it after nothing, * which is inserting it at the beginning. * * @param {Element} elem Parent element. * @param {Element} insert Element to insert. * @param {Element} after Element to insert after. * @returns {Element} Element that was inserted. */ function insertNodeAfterNode(elem, insert, after) { if (true) { throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); } if (after) { if (after.nextSibling) { return elem.insertBefore(insert, after.nextSibling); } else { return elem.appendChild(insert); } } else { return elem.insertBefore(insert, elem.firstChild); } } /** * Slow: Should only be used when it is known there are a few (or one) element * in the node list. * @param {Element} parentRootDomNode Parent element. * @param {HTMLCollection} htmlCollection HTMLCollection to insert. * @param {Element} after Element to insert the node list after. */ function inefficientlyInsertHTMLCollectionAfter( parentRootDomNode, htmlCollection, after) { if (true) { throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); } var ret; var originalLength = htmlCollection.length; // Access htmlCollection[0] because htmlCollection shrinks as we remove items. // `insertNodeAfterNode` will remove items from the htmlCollection. for (var i = 0; i < originalLength; i++) { ret = insertNodeAfterNode(parentRootDomNode, htmlCollection[0], ret || after); } } /** * Super-dangerously inserts markup into existing DOM structure. Seriously, you * don't want to use this module unless you are building a framework. This * requires that the markup that you are inserting represents the root of a * tree. We do not support the case where there `markup` represents several * roots. * * @param {Element} parentNode Parent DOM element. * @param {string} markup Markup to dangerously insert. * @param {number} index Position to insert markup at. */ function dangerouslyInsertMarkupAt(parentNode, markup, index) { if (true) { validateMarkupParams(parentNode, markup); } var parentDummy = getParentDummy(parentNode); parentDummy.innerHTML = markup; var htmlCollection = parentDummy.childNodes; var afterNode = index ? parentNode.childNodes[index - 1] : null; inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode); } /** * Replaces a node with a string of markup at its current position within its * parent. `childNode` must be in the document (or at least within a parent * node). The string of markup must represent a tree of markup with a single * root. * * @param {Element} childNode Child node to replace. * @param {string} markup Markup to dangerously replace child with. */ function dangerouslyReplaceNodeWithMarkup(childNode, markup) { var parentNode = childNode.parentNode; if (true) { validateMarkupParams(parentNode, markup); } var parentDummy = getParentDummy(parentNode); parentDummy.innerHTML = markup; var htmlCollection = parentDummy.childNodes; if (true) { throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP); } parentNode.replaceChild(htmlCollection[0], childNode); } var Danger = { dangerouslyInsertMarkupAt: dangerouslyInsertMarkupAt, dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup }; module.exports = Danger; },{"./ExecutionEnvironment":14,"./throwIf":31}],64:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule DOMProperty * @typechecks */ /*jslint bitwise: true */ "use strict"; var invariant = require("./invariant"); /** * DOMProperty exports lookup objects that can be used like functions: * * > DOMProperty.isValid['id'] * true * > DOMProperty.isValid['foobar'] * undefined * * Although this may be confusing, it performs better in general. * * @see http://jsperf.com/key-exists * @see http://jsperf.com/key-missing */ var DOMProperty = { /** * Checks whether a property name is a standard property. * @type {Object} */ isStandardName: {}, /** * Mapping from normalized names to attribute names that differ. Attribute * names are used when rendering markup or with `*Attribute()`. * @type {Object} */ getAttributeName: {}, /** * Mapping from normalized names to properties on DOM node instances. * (This includes properties that mutate due to external factors.) * @type {Object} */ getPropertyName: {}, /** * Mapping from normalized names to mutation methods. This will only exist if * mutation cannot be set simply by the property or `setAttribute()`. * @type {Object} */ getMutationMethod: {}, /** * Whether the property must be accessed and mutated as an object property. * @type {Object} */ mustUseAttribute: {}, /** * Whether the property must be accessed and mutated using `*Attribute()`. * (This includes anything that fails ` in `.) * @type {Object} */ mustUseProperty: {}, /** * Whether the property should be removed when set to a falsey value. * @type {Object} */ hasBooleanValue: {}, /** * Whether or not setting a value causes side effects such as triggering * resources to be loaded or text selection changes. We must ensure that * the value is only set if it has changed. * @type {Object} */ hasSideEffects: {}, /** * Checks whether a property name is a custom attribute. * @method */ isCustomAttribute: RegExp.prototype.test.bind( /^(data|aria)-[a-z_][a-z\d_.\-]*$/ ) }; /** * Mapping from normalized, camelcased property names to a configuration that * specifies how the associated DOM property should be accessed or rendered. */ var MustUseAttribute = 0x1; var MustUseProperty = 0x2; var HasBooleanValue = 0x4; var HasSideEffects = 0x8; var Properties = { /** * Standard Properties */ accept: null, action: null, ajaxify: MustUseAttribute, allowFullScreen: MustUseAttribute | HasBooleanValue, alt: null, autoComplete: null, autoplay: HasBooleanValue, cellPadding: null, cellSpacing: null, checked: MustUseProperty | HasBooleanValue, className: MustUseProperty, colSpan: null, contentEditable: null, controls: MustUseProperty | HasBooleanValue, data: null, // For `` acts as `src`. dir: null, disabled: MustUseProperty | HasBooleanValue, enctype: null, height: null, href: null, htmlFor: null, method: null, multiple: MustUseProperty | HasBooleanValue, name: null, poster: null, preload: null, placeholder: null, rel: null, required: HasBooleanValue, role: MustUseAttribute, scrollLeft: MustUseProperty, scrollTop: MustUseProperty, selected: MustUseProperty | HasBooleanValue, spellCheck: null, src: null, style: null, tabIndex: null, target: null, title: null, type: null, value: MustUseProperty | HasSideEffects, width: null, wmode: MustUseAttribute, /** * SVG Properties */ cx: MustUseProperty, cy: MustUseProperty, d: MustUseProperty, fill: MustUseProperty, fx: MustUseProperty, fy: MustUseProperty, points: MustUseProperty, r: MustUseProperty, stroke: MustUseProperty, strokeLinecap: MustUseProperty, strokeWidth: MustUseProperty, transform: MustUseProperty, x: MustUseProperty, x1: MustUseProperty, x2: MustUseProperty, version: MustUseProperty, viewBox: MustUseProperty, y: MustUseProperty, y1: MustUseProperty, y2: MustUseProperty, spreadMethod: MustUseProperty, offset: MustUseProperty, stopColor: MustUseProperty, stopOpacity: MustUseProperty, gradientUnits: MustUseProperty, gradientTransform: MustUseProperty }; /** * Attribute names not specified use the **lowercase** normalized name. */ var DOMAttributeNames = { className: 'class', htmlFor: 'for', strokeLinecap: 'stroke-linecap', strokeWidth: 'stroke-width', stopColor: 'stop-color', stopOpacity: 'stop-opacity' }; /** * Property names not specified use the normalized name. */ var DOMPropertyNames = { autoComplete: 'autocomplete', spellCheck: 'spellcheck' }; /** * Properties that require special mutation methods. */ var DOMMutationMethods = { /** * Setting `className` to null may cause it to be set to the string "null". * * @param {DOMElement} node * @param {*} value */ className: function(node, value) { node.className = value || ''; } }; for (var propName in Properties) { DOMProperty.isStandardName[propName] = true; DOMProperty.getAttributeName[propName] = DOMAttributeNames[propName] || propName.toLowerCase(); DOMProperty.getPropertyName[propName] = DOMPropertyNames[propName] || propName; var mutationMethod = DOMMutationMethods[propName]; if (mutationMethod) { DOMProperty.getMutationMethod[propName] = mutationMethod; } var propConfig = Properties[propName]; DOMProperty.mustUseAttribute[propName] = propConfig & MustUseAttribute; DOMProperty.mustUseProperty[propName] = propConfig & MustUseProperty; DOMProperty.hasBooleanValue[propName] = propConfig & HasBooleanValue; DOMProperty.hasSideEffects[propName] = propConfig & HasSideEffects; invariant( !DOMProperty.mustUseAttribute[propName] || !DOMProperty.mustUseProperty[propName], 'DOMProperty: Cannot use require using both attribute and property: %s', propName ); invariant( DOMProperty.mustUseProperty[propName] || !DOMProperty.hasSideEffects[propName], 'DOMProperty: Properties that have side effects must use property: %s', propName ); } module.exports = DOMProperty; },{"./invariant":10}],65:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule ReactTextComponent * @typechecks */ "use strict"; var ReactComponent = require("./ReactComponent"); var escapeTextForBrowser = require("./escapeTextForBrowser"); var mixInto = require("./mixInto"); /** * Text nodes violate a couple assumptions that React makes about components: * * - When mounting text into the DOM, adjacent text nodes are merged. * - Text nodes cannot be assigned a React root ID. * * This component is used to wrap strings in elements so that they can undergo * the same reconciliation that is applied to elements. * * TODO: Investigate representing React components in the DOM with text nodes. * * @class ReactTextComponent * @extends ReactComponent * @internal */ var ReactTextComponent = function(initialText) { this.construct({text: initialText}); }; mixInto(ReactTextComponent, ReactComponent.Mixin); mixInto(ReactTextComponent, { /** * Creates the markup for this text node. This node is not intended to have * any features besides containing text content. * * @param {string} rootID DOM ID of the root node. * @return {string} Markup for this text node. * @internal */ mountComponent: function(rootID) { ReactComponent.Mixin.mountComponent.call(this, rootID); return ( '' + escapeTextForBrowser(this.props.text) + '' ); }, /** * Updates this component by updating the text content. * * @param {object} nextProps Contains the next text content. * @param {ReactReconcileTransaction} transaction * @internal */ receiveProps: function(nextProps, transaction) { if (nextProps.text !== this.props.text) { this.props.text = nextProps.text; ReactComponent.DOMIDOperations.updateTextContentByID( this._rootNodeID, nextProps.text ); } } }); module.exports = ReactTextComponent; },{"./ReactComponent":3,"./escapeTextForBrowser":42,"./mixInto":13}],68:[function(require,module,exports){ /** * Copyright 2013 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule CSSProperty */ "use strict"; /** * CSS properties for which we do not append "px". */ var isNumber = { fillOpacity: true, fontWeight: true, opacity: true, orphans: true, textDecoration: true, zIndex: true, zoom: true }; var CSSProperty = { isNumber: isNumber }; module.exports = CSSProperty; },{}]},{},[1])(1) }); ;