mirror of
https://github.com/wahyd4/cdnjs.git
synced 2026-08-10 05:18:04 +10:00
8453 lines
266 KiB
JavaScript
8453 lines
266 KiB
JavaScript
/**
|
|
* 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;s<n.length;s++)i(n[s]);return i})({1:[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 React
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var ReactCompositeComponent = require("./ReactCompositeComponent");
|
|
var ReactComponent = require("./ReactComponent");
|
|
var ReactDOM = require("./ReactDOM");
|
|
var ReactMount = require("./ReactMount");
|
|
|
|
var ReactDefaultInjection = require("./ReactDefaultInjection");
|
|
|
|
ReactDefaultInjection.inject();
|
|
|
|
var React = {
|
|
DOM: ReactDOM,
|
|
initializeTouchEvents: function(shouldUseTouch) {
|
|
ReactMount.useTouchEvents = shouldUseTouch;
|
|
},
|
|
autoBind: ReactCompositeComponent.autoBind,
|
|
createClass: ReactCompositeComponent.createClass,
|
|
createComponentRenderer: ReactMount.createComponentRenderer,
|
|
constructAndRenderComponent: ReactMount.constructAndRenderComponent,
|
|
constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
|
|
renderComponent: ReactMount.renderComponent,
|
|
unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode,
|
|
isValidComponent: ReactComponent.isValidComponent
|
|
};
|
|
|
|
module.exports = React;
|
|
|
|
},{"./ReactCompositeComponent":2,"./ReactComponent":3,"./ReactDOM":4,"./ReactMount":5,"./ReactDefaultInjection":6}],2:[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 ReactCompositeComponent
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var ReactComponent = require("./ReactComponent");
|
|
var ReactCurrentOwner = require("./ReactCurrentOwner");
|
|
var ReactOwner = require("./ReactOwner");
|
|
var ReactPropTransferer = require("./ReactPropTransferer");
|
|
|
|
var invariant = require("./invariant");
|
|
var keyMirror = require("./keyMirror");
|
|
var merge = require("./merge");
|
|
var mixInto = require("./mixInto");
|
|
|
|
/**
|
|
* Policies that describe methods in `ReactCompositeComponentInterface`.
|
|
*/
|
|
var SpecPolicy = keyMirror({
|
|
/**
|
|
* These methods may be defined only once by the class specification or mixin.
|
|
*/
|
|
DEFINE_ONCE: null,
|
|
/**
|
|
* These methods may be defined by both the class specification and mixins.
|
|
* Subsequent definitions will be chained. These methods must return void.
|
|
*/
|
|
DEFINE_MANY: null,
|
|
/**
|
|
* These methods are overriding the base ReactCompositeComponent class.
|
|
*/
|
|
OVERRIDE_BASE: null
|
|
});
|
|
|
|
/**
|
|
* Composite components are higher-level components that compose other composite
|
|
* or native components.
|
|
*
|
|
* To create a new type of `ReactCompositeComponent`, pass a specification of
|
|
* your new class to `React.createClass`. The only requirement of your class
|
|
* specification is that you implement a `render` method.
|
|
*
|
|
* var MyComponent = React.createClass({
|
|
* render: function() {
|
|
* return <div>Hello World</div>;
|
|
* }
|
|
* });
|
|
*
|
|
* 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 <div>Hello, {name}!</div>;
|
|
* }
|
|
*
|
|
* @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 <a onClick={this.handleClick}>Jump</a>;
|
|
* }
|
|
* });
|
|
*
|
|
* @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'));
|
|
*
|
|
* <div id="container"> <-- Supplied `container`.
|
|
* <div id=".reactRoot[3]"> <-- Rendered reactRoot of React component.
|
|
* // ...
|
|
* </div>
|
|
* </div>
|
|
*
|
|
* 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 <form> 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 (
|
|
* <div onClick={this.handleClick}>
|
|
* <CustomComponent ref="custom" />
|
|
* </div>
|
|
* );
|
|
* },
|
|
* 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<object>} List of operation wrap proceedures.
|
|
* TODO: convert to array<TransactionWrapper>
|
|
*/
|
|
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 ? '' : '</' + tag + '>';
|
|
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 <form> `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 <form> element itself. There are lots of hacks we could
|
|
* do to accomplish this, but the most reliable is to make <form> 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<function>} 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.
|
|
*
|
|
* <pre>
|
|
* wrappers (injected at creation time)
|
|
* + +
|
|
* | |
|
|
* +-----------------|--------|--------------+
|
|
* | v | |
|
|
* | +---------------+ | |
|
|
* | +--| wrapper1 |---|----+ |
|
|
* | | +---------------+ v | |
|
|
* | | +-------------+ | |
|
|
* | | +----| wrapper2 |--------+ |
|
|
* | | | +-------------+ | | |
|
|
* | | | | | |
|
|
* | v v v v | wrapper
|
|
* | +---+ +---+ +---------+ +---+ +---+ | invariants
|
|
* perform(anyMethod) | | | | | | | | | | | | maintained
|
|
* +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
|
|
* | | | | | | | | | | | |
|
|
* | | | | | | | | | | | |
|
|
* | | | | | | | | | | | |
|
|
* | +---+ +---+ +---------+ +---+ +---+ |
|
|
* | initialize close |
|
|
* +-----------------------------------------+
|
|
* </pre>
|
|
*
|
|
* 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<TransactionalWrapper>} 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<TransactionWrapper>} 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 `<propName> in <element>`.)
|
|
* @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 `<object />` 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 (
|
|
'<span id="' + rootID + '">' +
|
|
escapeTextForBrowser(this.props.text) +
|
|
'</span>'
|
|
);
|
|
},
|
|
|
|
/**
|
|
* 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)
|
|
});
|
|
; |