Socket
Socket
Sign inDemoInstall

react

Package Overview
Dependencies
8
Maintainers
2
Versions
1793
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.8.0 to 0.9.0-rc1

lib/AutoFocusMixin.js

3

addons.js
module.exports = require('./lib/ReactWithAddons');
if ('production' !== process.env.NODE_ENV) {
module.exports = require('./ReactJSErrors').wrap(module.exports);
}

@@ -25,2 +25,3 @@ /**

var ExecutionEnvironment = require("./ExecutionEnvironment");
var ReactUpdates = require("./ReactUpdates");
var SyntheticEvent = require("./SyntheticEvent");

@@ -39,3 +40,13 @@

captured: keyOf({onChangeCapture: null})
}
},
dependencies: [
topLevelTypes.topBlur,
topLevelTypes.topChange,
topLevelTypes.topClick,
topLevelTypes.topFocus,
topLevelTypes.topInput,
topLevelTypes.topKeyDown,
topLevelTypes.topKeyUp,
topLevelTypes.topSelectionChange
]
}

@@ -78,6 +89,17 @@ };

// If change bubbled, we'd just bind to it like all the other events
// and have it go through ReactEventTopLevelCallback. Since it doesn't, we
// manually listen for the change event and so we have to enqueue and
// If change and propertychange bubbled, we'd just bind to it like all the
// other events and have it go through ReactEventTopLevelCallback. Since it
// doesn't, we manually listen for the events and so we have to enqueue and
// process the abstract event manually.
//
// Batching is necessary here in order to ensure that all event handlers run
// before the next rerender (including event handlers attached to ancestor
// elements instead of directly on the input). Without this, controlled
// components don't work properly in conjunction with event bubbling because
// the component is rerendered and the value reverted before all the event
// handlers can run. See https://github.com/facebook/react/issues/708.
ReactUpdates.batchedUpdates(runEventInBatch, event);
}
function runEventInBatch(event) {
EventPluginHub.enqueueEvents(event);

@@ -84,0 +106,0 @@ EventPluginHub.processEventQueue();

@@ -34,4 +34,18 @@ /**

var useCompositionEvent = ExecutionEnvironment.canUseDOM &&
'CompositionEvent' in window;
var useCompositionEvent = (
ExecutionEnvironment.canUseDOM &&
'CompositionEvent' in window
);
// In IE9+, we have access to composition events, but the data supplied
// by the native compositionend event may be incorrect. In Korean, for example,
// the compositionend event contains only one character regardless of
// how many characters have been composed since compositionstart.
// We therefore use the fallback data while still using the native
// events as triggers.
var useFallbackData = (
!useCompositionEvent ||
'documentMode' in document && document.documentMode > 8
);
var topLevelTypes = EventConstants.topLevelTypes;

@@ -46,3 +60,11 @@ var currentComposition = null;

captured: keyOf({onCompositionEndCapture: null})
}
},
dependencies: [
topLevelTypes.topBlur,
topLevelTypes.topCompositionEnd,
topLevelTypes.topKeyDown,
topLevelTypes.topKeyPress,
topLevelTypes.topKeyUp,
topLevelTypes.topMouseDown
]
},

@@ -53,3 +75,11 @@ compositionStart: {

captured: keyOf({onCompositionStartCapture: null})
}
},
dependencies: [
topLevelTypes.topBlur,
topLevelTypes.topCompositionStart,
topLevelTypes.topKeyDown,
topLevelTypes.topKeyPress,
topLevelTypes.topKeyUp,
topLevelTypes.topMouseDown
]
},

@@ -60,3 +90,11 @@ compositionUpdate: {

captured: keyOf({onCompositionUpdateCapture: null})
}
},
dependencies: [
topLevelTypes.topBlur,
topLevelTypes.topCompositionUpdate,
topLevelTypes.topKeyDown,
topLevelTypes.topKeyPress,
topLevelTypes.topKeyUp,
topLevelTypes.topMouseDown
]
}

@@ -190,11 +228,21 @@ };

if (isFallbackStart(topLevelType, nativeEvent)) {
eventType = eventTypes.start;
currentComposition = new FallbackCompositionState(topLevelTarget);
eventType = eventTypes.compositionStart;
}
} else if (isFallbackEnd(topLevelType, nativeEvent)) {
eventType = eventTypes.compositionEnd;
data = currentComposition.getData();
currentComposition = null;
}
if (useFallbackData) {
// The current composition is stored statically and must not be
// overwritten while composition continues.
if (!currentComposition && eventType === eventTypes.compositionStart) {
currentComposition = new FallbackCompositionState(topLevelTarget);
} else if (eventType === eventTypes.compositionEnd) {
if (currentComposition) {
data = currentComposition.getData();
currentComposition = null;
}
}
}
if (eventType) {

@@ -201,0 +249,0 @@ var event = SyntheticCompositionEvent.getPooled(

@@ -20,7 +20,5 @@ /**

var toArray = require("./toArray");
/**
* NOTE: if you are a previous user of this function, it has been considered
* unsafe because it's inconsistent across browsers for some inputs.
* Instead use `Array.isArray()`.
*
* Perform a heuristic test to determine if an object is "array-like".

@@ -35,2 +33,4 @@ *

*
* It will return false for other array-like objects like Filelist.
*
* @param {*} obj

@@ -77,4 +77,4 @@ * @return {boolean}

*
* This is also good for converting certain pseudo-arrays, like `arguments` or
* HTMLCollections, into arrays.
* If you need to convert an array-like object, like `arguments`, into an array
* use toArray instead.
*

@@ -87,12 +87,9 @@ * @param {*} obj

return [obj];
} else if (Array.isArray(obj)) {
return obj.slice();
} else {
return toArray(obj);
}
if (obj.item) {
// IE does not support Array#slice on HTMLCollections
var l = obj.length, ret = new Array(l);
while (l--) { ret[l] = obj[l]; }
return ret;
}
return Array.prototype.slice.call(obj);
}
module.exports = createArrayFrom;

@@ -25,3 +25,3 @@ /**

* that should be used when dealing with the display of elements (via their
* CSS classes and visibility on screeni. It is an API focused on mutating the
* CSS classes and visibility on screen. It is an API focused on mutating the
* display and not reading it as no logical state should be encoded in the

@@ -31,20 +31,2 @@ * display of elements.

/**
* Tests whether the element has the class specified.
*
* Note: This function is not exported in CSSCore because CSS classNames should
* not store any logical information about the element. Use DataStore to store
* information on an element.
*
* @param {DOMElement} element the element to set the class on
* @param {string} className the CSS className
* @returns {boolean} true if the element has the class, false if not
*/
function hasClass(element, className) {
if (element.classList) {
return !!className && element.classList.contains(className);
}
return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
}
var CSSCore = {

@@ -69,3 +51,3 @@

element.classList.add(className);
} else if (!hasClass(element, className)) {
} else if (!CSSCore.hasClass(element, className)) {
element.className = element.className + ' ' + className;

@@ -94,3 +76,3 @@ }

element.classList.remove(className);
} else if (hasClass(element, className)) {
} else if (CSSCore.hasClass(element, className)) {
element.className = element.className

@@ -115,5 +97,24 @@ .replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1')

return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className);
},
/**
* Tests whether the element has the class specified.
*
* @param {DOMNode|DOMWindow} element the element to set the class on
* @param {string} className the CSS className
* @returns {boolean} true if the element has the class, false if not
*/
hasClass: function(element, className) {
("production" !== process.env.NODE_ENV ? invariant(
!/\s/.test(className),
'CSS.hasClass takes only a single class name.'
) : invariant(!/\s/.test(className)));
if (element.classList) {
return !!className && element.classList.contains(className);
}
return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
}
};
module.exports = CSSCore;

@@ -25,7 +25,14 @@ /**

var isUnitlessNumber = {
columnCount: true,
fillOpacity: true,
flex: true,
flexGrow: true,
flexShrink: true,
fontWeight: true,
lineClamp: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
widows: true,
zIndex: true,

@@ -36,2 +43,26 @@ zoom: true

/**
* @param {string} prefix vendor-specific prefix, eg: Webkit
* @param {string} key style name, eg: transitionDuration
* @return {string} style name prefixed with `prefix`, properly camelCased, eg:
* WebkitTransitionDuration
*/
function prefixKey(prefix, key) {
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}
/**
* Support style names that may come passed in prefixed by adding permutations
* of vendor prefixes.
*/
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
Object.keys(isUnitlessNumber).forEach(function(prop) {
prefixes.forEach(function(prefix) {
isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
});
});
/**
* Most style properties can be unset by doing .style[prop] = '' but IE8

@@ -38,0 +69,0 @@ * doesn't like doing that with shorthand properties so for the properties that

@@ -36,4 +36,4 @@ /**

if (typeof classNames == 'object') {
return Object.keys(classNames).map(function(className) {
return classNames[className] ? className : '';
return Object.keys(classNames).filter(function(className) {
return classNames[className];
}).join(' ');

@@ -40,0 +40,0 @@ } else {

@@ -30,3 +30,2 @@ /**

var invariant = require("./invariant");
var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup");

@@ -175,8 +174,10 @@ var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;

("production" !== process.env.NODE_ENV ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
// createNodesFromMarkup() won't work if the markup is rooted by <html>
// since it has special semantic meaning. So we use an alternatie strategy.
if (oldChild.tagName.toLowerCase() === 'html') {
mutateHTMLNodeWithMarkup(oldChild, markup);
return;
}
("production" !== process.env.NODE_ENV ? invariant(
oldChild.tagName.toLowerCase() !== 'html',
'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
'<html> node. This is because browser quirks make this unreliable ' +
'and/or slow. If you want to render to the root you must use ' +
'server rendering. See renderComponentToString().'
) : invariant(oldChild.tagName.toLowerCase() !== 'html'));
var newChild = createNodesFromMarkup(markup, emptyFunction)[0];

@@ -183,0 +184,0 @@ oldChild.parentNode.replaceChild(newChild, oldChild);

@@ -48,3 +48,4 @@ /**

autoComplete: null,
autoFocus: HAS_BOOLEAN_VALUE,
// autoFocus is polyfilled/normalized by AutoFocusMixin
// autoFocus: HAS_BOOLEAN_VALUE,
autoPlay: HAS_BOOLEAN_VALUE,

@@ -70,2 +71,3 @@ cellPadding: null,

form: MUST_USE_ATTRIBUTE,
formNoValidate: HAS_BOOLEAN_VALUE,
frameBorder: MUST_USE_ATTRIBUTE,

@@ -89,2 +91,3 @@ height: MUST_USE_ATTRIBUTE,

name: null,
noValidate: HAS_BOOLEAN_VALUE,
pattern: null,

@@ -101,8 +104,13 @@ placeholder: null,

rowSpan: null,
sandbox: null,
scope: null,
scrollLeft: MUST_USE_PROPERTY,
scrollTop: MUST_USE_PROPERTY,
seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
span: HAS_POSITIVE_NUMERIC_VALUE,
spellCheck: null,
src: null,
srcDoc: MUST_USE_PROPERTY,
step: null,

@@ -123,2 +131,3 @@ style: null,

autoCorrect: null, // Supported in Mobile Safari for keyboard hints
property: null, // Supports OG in meta tags

@@ -177,3 +186,4 @@ /**

radioGroup: 'radiogroup',
spellCheck: 'spellcheck'
spellCheck: 'spellcheck',
srcDoc: 'srcdoc'
},

@@ -180,0 +190,0 @@ DOMMutationMethods: {

@@ -33,3 +33,3 @@ /**

*/
var textContentAccessor = getTextContentAccessor() || 'NA';
var textContentAccessor = getTextContentAccessor();

@@ -62,2 +62,27 @@ /**

/**
* Sets the text content of `node` to `text`.
*
* @param {DOMElement} node Node to change
* @param {string} text New text content
*/
var updateTextContent;
if (textContentAccessor === 'textContent') {
updateTextContent = function(node, text) {
node.textContent = text;
};
} else {
updateTextContent = function(node, text) {
// In order to preserve newlines correctly, we can't use .innerText to set
// the contents (see #1080), so we empty the element then append a text node
while (node.firstChild) {
node.removeChild(node.firstChild);
}
if (text) {
var doc = node.ownerDocument || document;
node.appendChild(doc.createTextNode(text));
}
};
}
/**
* Operations for updating with DOM children.

@@ -69,2 +94,4 @@ */

updateTextContent: updateTextContent,
/**

@@ -127,3 +154,6 @@ * Updates a component's children by processing a series of updates. The

case ReactMultiChildUpdateTypes.TEXT_CONTENT:
update.parentNode[textContentAccessor] = update.textContent;
updateTextContent(
update.parentNode,
update.textContent
);
break;

@@ -130,0 +160,0 @@ case ReactMultiChildUpdateTypes.REMOVE_NODE:

@@ -157,2 +157,4 @@ /**

ID_ATTRIBUTE_NAME: 'data-reactid',
/**

@@ -159,0 +161,0 @@ * Checks whether a property name is a standard property.

@@ -39,3 +39,2 @@ /**

var reactProps = {
__owner__: true,
children: true,

@@ -77,2 +76,13 @@ dangerouslySetInnerHTML: true,

/**
* Creates markup for the ID property.
*
* @param {string} id Unescaped ID.
* @return {string} Markup string.
*/
createMarkupForID: function(id) {
return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) +
escapeTextForBrowser(id) + '"';
},
/**
* Creates markup for a property.

@@ -90,2 +100,5 @@ *

var attributeName = DOMProperty.getAttributeName[name];
if (DOMProperty.hasBooleanValue[name]) {
return escapeTextForBrowser(attributeName);
}
return processAttributeNameAndPrefix(attributeName) +

@@ -92,0 +105,0 @@ escapeTextForBrowser(value) + '"';

@@ -33,4 +33,16 @@ /**

var eventTypes = {
mouseEnter: {registrationName: keyOf({onMouseEnter: null})},
mouseLeave: {registrationName: keyOf({onMouseLeave: null})}
mouseEnter: {
registrationName: keyOf({onMouseEnter: null}),
dependencies: [
topLevelTypes.topMouseOut,
topLevelTypes.topMouseOver
]
},
mouseLeave: {
registrationName: keyOf({onMouseLeave: null}),
dependencies: [
topLevelTypes.topMouseOut,
topLevelTypes.topMouseOver
]
}
};

@@ -73,2 +85,16 @@

var win;
if (topLevelTarget.window === topLevelTarget) {
// `topLevelTarget` is probably a window object.
win = topLevelTarget;
} else {
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
var doc = topLevelTarget.ownerDocument;
if (doc) {
win = doc.defaultView || doc.parentWindow;
} else {
win = window;
}
}
var from, to;

@@ -79,5 +105,5 @@ if (topLevelType === topLevelTypes.topMouseOut) {

getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
window;
win;
} else {
from = window;
from = win;
to = topLevelTarget;

@@ -99,2 +125,6 @@ }

);
leave.type = 'mouseleave';
leave.target = from;
leave.relatedTarget = to;
var enter = SyntheticMouseEvent.getPooled(

@@ -105,2 +135,5 @@ eventTypes.mouseEnter,

);
enter.type = 'mouseenter';
enter.target = to;
enter.relatedTarget = from;

@@ -107,0 +140,0 @@ EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);

@@ -47,2 +47,3 @@ /**

topDrop: null,
topError: null,
topFocus: null,

@@ -53,2 +54,3 @@ topInput: null,

topKeyUp: null,
topLoad: null,
topMouseDown: null,

@@ -60,2 +62,3 @@ topMouseMove: null,

topPaste: null,
topReset: null,
topScroll: null,

@@ -62,0 +65,0 @@ topSelectionChange: null,

/**
* 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
*/
var emptyFunction = require("./emptyFunction");
/**

@@ -25,13 +13,24 @@ * Upstream version of event listener. Does not take into account specific

/**
* Listens to bubbled events on a DOM node.
* Listen to DOM events during the bubble phase.
*
* @param {Element} el DOM element to register listener on.
* @param {string} handlerBaseName 'click'/'mouseover'
* @param {Function!} cb Callback function
* @param {DOMEventTarget} target DOM element to register listener on.
* @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
* @param {function} callback Callback function.
* @return {object} Object with a `remove` method.
*/
listen: function(el, handlerBaseName, cb) {
if (el.addEventListener) {
el.addEventListener(handlerBaseName, cb, false);
} else if (el.attachEvent) {
el.attachEvent('on' + handlerBaseName, cb);
listen: function(target, eventType, callback) {
if (target.addEventListener) {
target.addEventListener(eventType, callback, false);
return {
remove: function() {
target.removeEventListener(eventType, callback, false);
}
};
} else if (target.attachEvent) {
target.attachEvent('on' + eventType, callback);
return {
remove: function() {
target.detachEvent(eventType, callback);
}
};
}

@@ -41,19 +40,28 @@ },

/**
* Listens to captured events on a DOM node.
* Listen to DOM events during the capture phase.
*
* @see `EventListener.listen` for params.
* @throws Exception if addEventListener is not supported.
* @param {DOMEventTarget} target DOM element to register listener on.
* @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
* @param {function} callback Callback function.
* @return {object} Object with a `remove` method.
*/
capture: function(el, handlerBaseName, cb) {
if (!el.addEventListener) {
capture: function(target, eventType, callback) {
if (!target.addEventListener) {
if ("production" !== process.env.NODE_ENV) {
console.error(
'You are attempting to use addEventListener ' +
'in a browser that does not support it.' +
'This likely means that you will not receive events that ' +
'your application relies on (such as scroll).');
'Attempted to listen to events during the capture phase on a ' +
'browser that does not support the capture phase. Your application ' +
'will not receive some events.'
);
}
return;
return {
remove: emptyFunction
};
} else {
el.addEventListener(handlerBaseName, cb, true);
target.addEventListener(eventType, callback, true);
return {
remove: function() {
target.removeEventListener(eventType, callback, true);
}
};
}

@@ -60,0 +68,0 @@ }

@@ -21,6 +21,4 @@ /**

var CallbackRegistry = require("./CallbackRegistry");
var EventPluginRegistry = require("./EventPluginRegistry");
var EventPluginUtils = require("./EventPluginUtils");
var EventPropagators = require("./EventPropagators");
var ExecutionEnvironment = require("./ExecutionEnvironment");

@@ -31,4 +29,10 @@

var invariant = require("./invariant");
var isEventSupported = require("./isEventSupported");
/**
* Internal store for event listeners
*/
var listenerBank = {};
/**
* Internal queue of events that have accumulated their dispatches and are

@@ -62,2 +66,17 @@ * waiting to have their dispatches executed.

/**
* - `InstanceHandle`: [required] Module that performs logical traversals of DOM
* hierarchy given ids of the logical DOM elements involved.
*/
var InstanceHandle = null;
function validateInstanceHandle() {
var invalid = !InstanceHandle||
!InstanceHandle.traverseTwoPhase ||
!InstanceHandle.traverseEnterLeave;
if (invalid) {
throw new Error('InstanceHandle not injected before use!');
}
}
/**
* This is a unified interface for event plugins to be installed and configured.

@@ -92,7 +111,25 @@ *

/**
* @param {object} InjectedMount
* @public
*/
injectMount: EventPluginUtils.injection.injectMount,
/**
* @param {object} InjectedInstanceHandle
* @public
*/
injectInstanceHandle: EventPropagators.injection.injectInstanceHandle,
injectInstanceHandle: function(InjectedInstanceHandle) {
InstanceHandle = InjectedInstanceHandle;
if ("production" !== process.env.NODE_ENV) {
validateInstanceHandle();
}
},
getInstanceHandle: function() {
if ("production" !== process.env.NODE_ENV) {
validateInstanceHandle();
}
return InstanceHandle;
},
/**

@@ -111,13 +148,70 @@ * @param {array} InjectedEventPluginOrder

registrationNames: EventPluginRegistry.registrationNames,
registrationNameModules: EventPluginRegistry.registrationNameModules,
putListener: CallbackRegistry.putListener,
/**
* Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
*
* @param {string} id ID of the DOM element.
* @param {string} registrationName Name of listener (e.g. `onClick`).
* @param {?function} listener The callback to store.
*/
putListener: function(id, registrationName, listener) {
("production" !== process.env.NODE_ENV ? invariant(
ExecutionEnvironment.canUseDOM,
'Cannot call putListener() in a non-DOM environment.'
) : invariant(ExecutionEnvironment.canUseDOM));
("production" !== process.env.NODE_ENV ? invariant(
!listener || typeof listener === 'function',
'Expected %s listener to be a function, instead got type %s',
registrationName, typeof listener
) : invariant(!listener || typeof listener === 'function'));
getListener: CallbackRegistry.getListener,
if ("production" !== process.env.NODE_ENV) {
// IE8 has no API for event capturing and the `onScroll` event doesn't
// bubble.
if (registrationName === 'onScroll' &&
!isEventSupported('scroll', true)) {
console.warn('This browser doesn\'t support the `onScroll` event');
}
}
var bankForRegistrationName =
listenerBank[registrationName] || (listenerBank[registrationName] = {});
bankForRegistrationName[id] = listener;
},
deleteListener: CallbackRegistry.deleteListener,
/**
* @param {string} id ID of the DOM element.
* @param {string} registrationName Name of listener (e.g. `onClick`).
* @return {?function} The stored callback.
*/
getListener: function(id, registrationName) {
var bankForRegistrationName = listenerBank[registrationName];
return bankForRegistrationName && bankForRegistrationName[id];
},
deleteAllListeners: CallbackRegistry.deleteAllListeners,
/**
* Deletes a listener from the registration bank.
*
* @param {string} id ID of the DOM element.
* @param {string} registrationName Name of listener (e.g. `onClick`).
*/
deleteListener: function(id, registrationName) {
var bankForRegistrationName = listenerBank[registrationName];
if (bankForRegistrationName) {
delete bankForRegistrationName[id];
}
},
/**
* Deletes all listeners for the DOM element with the supplied ID.
*
* @param {string} id ID of the DOM element.
*/
deleteAllListeners: function(id) {
for (var registrationName in listenerBank) {
delete listenerBank[registrationName][id];
}
},
/**
* Allows registered plugins an opportunity to extract events from top-level

@@ -187,2 +281,13 @@ * native browser events.

) : invariant(!eventQueue));
},
/**
* These are needed for tests only. Do not use!
*/
__purge: function() {
listenerBank = {};
},
__getListenerBank: function() {
return listenerBank;
}

@@ -192,6 +297,2 @@

if (ExecutionEnvironment.canUseDOM) {
window.EventPluginHub = EventPluginHub;
}
module.exports = EventPluginHub;

@@ -66,7 +66,15 @@ /**

("production" !== process.env.NODE_ENV ? invariant(
publishEventForPlugin(publishedEvents[eventName], PluginModule),
publishEventForPlugin(
publishedEvents[eventName],
PluginModule,
eventName
),
'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
eventName,
pluginName
) : invariant(publishEventForPlugin(publishedEvents[eventName], PluginModule)));
) : invariant(publishEventForPlugin(
publishedEvents[eventName],
PluginModule,
eventName
)));
}

@@ -84,3 +92,3 @@ }

*/
function publishEventForPlugin(dispatchConfig, PluginModule) {
function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;

@@ -91,3 +99,7 @@ if (phasedRegistrationNames) {

var phasedRegistrationName = phasedRegistrationNames[phaseName];
publishRegistrationName(phasedRegistrationName, PluginModule);
publishRegistrationName(
phasedRegistrationName,
PluginModule,
eventName
);
}

@@ -97,3 +109,7 @@ }

} else if (dispatchConfig.registrationName) {
publishRegistrationName(dispatchConfig.registrationName, PluginModule);
publishRegistrationName(
dispatchConfig.registrationName,
PluginModule,
eventName
);
return true;

@@ -112,10 +128,12 @@ }

*/
function publishRegistrationName(registrationName, PluginModule) {
function publishRegistrationName(registrationName, PluginModule, eventName) {
("production" !== process.env.NODE_ENV ? invariant(
!EventPluginRegistry.registrationNames[registrationName],
!EventPluginRegistry.registrationNameModules[registrationName],
'EventPluginHub: More than one plugin attempted to publish the same ' +
'registration name, `%s`.',
registrationName
) : invariant(!EventPluginRegistry.registrationNames[registrationName]));
EventPluginRegistry.registrationNames[registrationName] = PluginModule;
) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
EventPluginRegistry.registrationNameDependencies[registrationName] =
PluginModule.eventTypes[eventName].dependencies;
}

@@ -138,5 +156,10 @@

*/
registrationNames: {},
registrationNameModules: {},
/**
* Mapping from registration name to event name
*/
registrationNameDependencies: {},
/**
* Injects an ordering of plugins (by plugin name). This allows the ordering

@@ -203,3 +226,3 @@ * to be decoupled from injection of the actual plugins so that ordering is

if (dispatchConfig.registrationName) {
return EventPluginRegistry.registrationNames[
return EventPluginRegistry.registrationNameModules[
dispatchConfig.registrationName

@@ -212,3 +235,3 @@ ] || null;

}
var PluginModule = EventPluginRegistry.registrationNames[
var PluginModule = EventPluginRegistry.registrationNameModules[
dispatchConfig.phasedRegistrationNames[phase]

@@ -235,6 +258,6 @@ ];

EventPluginRegistry.plugins.length = 0;
var registrationNames = EventPluginRegistry.registrationNames;
for (var registrationName in registrationNames) {
if (registrationNames.hasOwnProperty(registrationName)) {
delete registrationNames[registrationName];
var registrationNameModules = EventPluginRegistry.registrationNameModules;
for (var registrationName in registrationNameModules) {
if (registrationNameModules.hasOwnProperty(registrationName)) {
delete registrationNameModules[registrationName];
}

@@ -241,0 +264,0 @@ }

@@ -25,2 +25,24 @@ /**

/**
* Injected dependencies:
*/
/**
* - `Mount`: [required] Module that can convert between React dom IDs and
* actual node references.
*/
var injection = {
Mount: null,
injectMount: function(InjectedMount) {
injection.Mount = InjectedMount;
if ("production" !== process.env.NODE_ENV) {
("production" !== process.env.NODE_ENV ? invariant(
InjectedMount && InjectedMount.getNode,
'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
'is missing getNode.'
) : invariant(InjectedMount && InjectedMount.getNode));
}
}
};
var topLevelTypes = EventConstants.topLevelTypes;

@@ -43,2 +65,3 @@

var validateEventDispatches;

@@ -95,3 +118,6 @@ if ("production" !== process.env.NODE_ENV) {

function executeDispatch(event, listener, domID) {
listener(event, domID);
event.currentTarget = injection.Mount.getNode(domID);
var returnValue = listener(event, domID);
event.currentTarget = null;
return returnValue;
}

@@ -181,9 +207,12 @@

isStartish: isStartish,
executeDirectDispatch: executeDirectDispatch,
executeDispatch: executeDispatch,
executeDispatchesInOrder: executeDispatchesInOrder,
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
executeDirectDispatch: executeDirectDispatch,
hasDispatches: hasDispatches,
executeDispatch: executeDispatch
injection: injection,
useTouchEvents: false
};
module.exports = EventPluginUtils;

@@ -21,37 +21,12 @@ /**

var CallbackRegistry = require("./CallbackRegistry");
var EventConstants = require("./EventConstants");
var EventPluginHub = require("./EventPluginHub");
var accumulate = require("./accumulate");
var forEachAccumulated = require("./forEachAccumulated");
var getListener = CallbackRegistry.getListener;
var PropagationPhases = EventConstants.PropagationPhases;
var getListener = EventPluginHub.getListener;
/**
* 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 ("production" !== process.env.NODE_ENV) {
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

@@ -77,3 +52,2 @@ * "phases" of propagation. This finds listeners by a given phase.

}
injection.validate();
}

@@ -97,3 +71,3 @@ var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;

if (event && event.dispatchConfig.phasedRegistrationNames) {
injection.InstanceHandle.traverseTwoPhase(
EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
event.dispatchMarker,

@@ -135,5 +109,2 @@ accumulateDirectionalDispatches,

function accumulateTwoPhaseDispatches(events) {
if ("production" !== process.env.NODE_ENV) {
injection.validate();
}
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);

@@ -143,6 +114,3 @@ }

function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
if ("production" !== process.env.NODE_ENV) {
injection.validate();
}
injection.InstanceHandle.traverseEnterLeave(
EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
fromID,

@@ -158,5 +126,2 @@ toID,

function accumulateDirectDispatches(events) {
if ("production" !== process.env.NODE_ENV) {
injection.validate();
}
forEachAccumulated(events, accumulateDirectDispatchesSingle);

@@ -181,6 +146,5 @@ }

accumulateDirectDispatches: accumulateDirectDispatches,
accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches,
injection: injection
accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
};
module.exports = EventPropagators;

@@ -37,2 +37,5 @@ /**

canUseEventListeners:
canUseDOM && (window.addEventListener || window.attachEvent),
isInWorker: !canUseDOM // For now, this is true - might change in the future.

@@ -39,0 +42,0 @@

@@ -38,7 +38,10 @@ /**

) : invariant(!result.hasOwnProperty(name)));
result[name] = child;
if (child != null) {
result[name] = child;
}
}
/**
* Flattens children that are typically specified as `props.children`.
* Flattens children that are typically specified as `props.children`. Any null
* children will not be included in the resulting object.
* @return {!object} flattened children keyed by name.

@@ -45,0 +48,0 @@ */

@@ -23,8 +23,10 @@ /**

* not safe to call document.activeElement if there is nothing focused.
*
* The activeElement will be null only if the document body is not yet defined.
*/
function getActiveElement() /*?DOMElement*/ {
try {
return document.activeElement;
return document.activeElement || document.body;
} catch (e) {
return null;
return document.body;
}

@@ -34,2 +36,1 @@ }

module.exports = getActiveElement;

@@ -39,7 +39,12 @@ /**

'circle': true,
'defs': true,
'g': true,
'line': true,
'linearGradient': true,
'path': true,
'polygon': true,
'polyline': true,
'radialGradient': true,
'rect': true,
'stop': true,
'text': true

@@ -76,7 +81,12 @@ };

'circle': svgWrap,
'defs': svgWrap,
'g': svgWrap,
'line': svgWrap,
'linearGradient': svgWrap,
'path': svgWrap,
'polygon': svgWrap,
'polyline': svgWrap,
'radialGradient': svgWrap,
'rect': svgWrap,
'stop': svgWrap,
'text': svgWrap

@@ -83,0 +93,0 @@ };

@@ -33,5 +33,7 @@ /**

if (!contentKey && ExecutionEnvironment.canUseDOM) {
contentKey = 'innerText' in document.createElement('div') ?
'innerText' :
'textContent';
// Prefer textContent to innerText because many browsers support both but
// SVG <text> elements don't support innerText even when <div> does.
contentKey = 'textContent' in document.createElement('div') ?
'textContent' :
'innerText';
}

@@ -38,0 +40,0 @@ return contentKey;

@@ -35,4 +35,4 @@ /**

return {
x: document.documentElement.scrollLeft || document.body.scrollLeft,
y: document.documentElement.scrollTop || document.body.scrollTop
x: window.pageXOffset || document.documentElement.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop
};

@@ -39,0 +39,0 @@ }

@@ -22,4 +22,5 @@ /**

*
* Provide sprintf style format and arguments to provide information about
* what broke and what you were expecting.
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*

@@ -32,3 +33,8 @@ * The invariant message will be stripped in production, but the invariant

if (!condition) {
throw new Error('Invariant Violation');
var error = new Error(
'Minified exception occured; use the non-minified dev environment for ' +
'the full error message and additional helpful warnings.'
);
error.framesToPop = 1;
throw error;
}

@@ -48,6 +54,8 @@ }

var argIndex = 0;
throw new Error(
var error = new Error(
'Invariant Violation: ' +
format.replace(/%s/g, function() { return args[argIndex++]; })
);
error.framesToPop = 1; // we don't care about invariant's own frame
throw error;
}

@@ -54,0 +62,0 @@ };

@@ -23,9 +23,9 @@ /**

var testNode, useHasFeature;
var useHasFeature;
if (ExecutionEnvironment.canUseDOM) {
testNode = document.createElement('div');
useHasFeature =
document.implementation &&
document.implementation.hasFeature &&
// `hasFeature` always returns true in Firefox 19+.
// always returns true in newer browsers as per the standard.
// @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
document.implementation.hasFeature('', '') !== true;

@@ -49,17 +49,14 @@ }

function isEventSupported(eventNameSuffix, capture) {
if (!testNode || (capture && !testNode.addEventListener)) {
if (!ExecutionEnvironment.canUseDOM ||
capture && !('addEventListener' in document)) {
return false;
}
var element = document.createElement('div');
var eventName = 'on' + eventNameSuffix;
var isSupported = eventName in element;
var isSupported = eventName in document;
if (!isSupported) {
var element = document.createElement('div');
element.setAttribute(eventName, 'return;');
isSupported = typeof element[eventName] === 'function';
if (typeof element[eventName] !== 'undefined') {
element[eventName] = undefined;
}
element.removeAttribute(eventName);
}

@@ -72,3 +69,2 @@

element = null;
return isSupported;

@@ -75,0 +71,0 @@ }

@@ -69,5 +69,5 @@ /**

Array.isArray(one) && Array.isArray(two),
'Critical assumptions about the merge functions have been violated. ' +
'This is the fault of the merge functions themselves, not necessarily ' +
'the callers.'
'Tried to merge arrays, instead got %s and %s.',
one,
two
) : invariant(Array.isArray(one) && Array.isArray(two)));

@@ -91,5 +91,4 @@ },

!isTerminal(arg) && !Array.isArray(arg),
'Critical assumptions about the merge functions have been violated. ' +
'This is the fault of the merge functions themselves, not necessarily ' +
'the callers.'
'Tried to merge an object, instead got %s.',
arg
) : invariant(!isTerminal(arg) && !Array.isArray(arg)));

@@ -96,0 +95,0 @@ },

@@ -21,2 +21,4 @@ /**

var invariant = require("./invariant");
/**

@@ -75,2 +77,6 @@ * Static poolers. Several custom versions for each potential number of

var Klass = this;
("production" !== process.env.NODE_ENV ? invariant(
instance instanceof Klass,
'Trying to release an instance into a pool of a different type.'
) : invariant(instance instanceof Klass));
if (instance.destructor) {

@@ -77,0 +83,0 @@ instance.destructor();

@@ -21,4 +21,8 @@ /**

var DOMPropertyOperations = require("./DOMPropertyOperations");
var EventPluginUtils = require("./EventPluginUtils");
var ReactChildren = require("./ReactChildren");
var ReactComponent = require("./ReactComponent");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactContext = require("./ReactContext");
var ReactCurrentOwner = require("./ReactCurrentOwner");

@@ -36,9 +40,16 @@ var ReactDOM = require("./ReactDOM");

var onlyChild = require("./onlyChild");
ReactDefaultInjection.inject();
var React = {
Children: {
map: ReactChildren.map,
forEach: ReactChildren.forEach,
only: onlyChild
},
DOM: ReactDOM,
PropTypes: ReactPropTypes,
initializeTouchEvents: function(shouldUseTouch) {
ReactMount.useTouchEvents = shouldUseTouch;
EventPluginUtils.useTouchEvents = shouldUseTouch;
},

@@ -55,5 +66,5 @@ createClass: ReactCompositeComponent.createClass,

unmountComponentAtNode: ReactMount.unmountComponentAtNode,
unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode,
isValidClass: ReactCompositeComponent.isValidClass,
isValidComponent: ReactComponent.isValidComponent,
withContext: ReactContext.withContext,
__internals: {

@@ -63,2 +74,3 @@ Component: ReactComponent,

DOMComponent: ReactDOMComponent,
DOMPropertyOperations: DOMPropertyOperations,
InstanceHandles: ReactInstanceHandles,

@@ -71,6 +83,18 @@ Mount: ReactMount,

if ("production" !== process.env.NODE_ENV) {
var ExecutionEnvironment = require("./ExecutionEnvironment");
if (ExecutionEnvironment.canUseDOM &&
window.top === window.self &&
navigator.userAgent.indexOf('Chrome') > -1) {
console.debug(
'Download the React DevTools for a better development experience: ' +
'http://fb.me/react-devtools'
);
}
}
// Version exists only in the open-source version of React, not in Facebook's
// internal version.
React.version = '0.8.0';
React.version = '0.9.0-rc1';
module.exports = React;

@@ -46,12 +46,16 @@ /**

/**
* Warn if there's no key explicitly set on dynamic arrays of children.
* This allows us to keep track of children between updates.
* Warn if there's no key explicitly set on dynamic arrays of children or
* object keys are not valid. This allows us to keep track of children between
* updates.
*/
var ownerHasWarned = {};
var ownerHasExplicitKeyWarning = {};
var ownerHasPropertyWarning = {};
var NUMERIC_PROPERTY_REGEX = /^\d+$/;
/**
* Warn if the component doesn't have an explicit key assigned to it.
* This component is in an array. The array could grow and shrink or be
* reordered. All children, that hasn't already been validated, are required to
* reordered. All children that haven't already been validated are required to
* have a "key" property assigned to it.

@@ -75,6 +79,6 @@ *

var currentName = ReactCurrentOwner.current.constructor.displayName;
if (ownerHasWarned.hasOwnProperty(currentName)) {
if (ownerHasExplicitKeyWarning.hasOwnProperty(currentName)) {
return;
}
ownerHasWarned[currentName] = true;
ownerHasExplicitKeyWarning[currentName] = true;

@@ -86,4 +90,4 @@ var message = 'Each child in an array should have a unique "key" prop. ' +

var childOwnerName =
component.props.__owner__ &&
component.props.__owner__.constructor.displayName;
component._owner &&
component._owner.constructor.displayName;

@@ -96,2 +100,3 @@ // Usually the current owner is the offender, but if it accepts

message += ' See http://fb.me/react-warning-keys for more information.';
console.warn(message);

@@ -101,6 +106,32 @@ }

/**
* Ensure that every component either is passed in a static location or, if
* if it's passed in an array, has an explicit key property defined.
* Warn if the key is being defined as an object property but has an incorrect
* value.
*
* @internal
* @param {string} name Property name of the key.
* @param {ReactComponent} component Component that requires a key.
*/
function validatePropertyKey(name) {
if (NUMERIC_PROPERTY_REGEX.test(name)) {
// Name of the component whose render method tried to pass children.
var currentName = ReactCurrentOwner.current.constructor.displayName;
if (ownerHasPropertyWarning.hasOwnProperty(currentName)) {
return;
}
ownerHasPropertyWarning[currentName] = true;
console.warn(
'Child objects should have non-numeric keys so ordering is preserved. ' +
'Check the render method of ' + currentName + '. ' +
'See http://fb.me/react-warning-keys for more information.'
);
}
}
/**
* Ensure that every component either is passed in a static location, in an
* array with an explicit keys property defined, or in an object literal
* with valid key property.
*
* @internal
* @param {*} component Statically passed child of any type.

@@ -120,2 +151,6 @@ * @return {boolean}

component.__keyValidated__ = true;
} else if (component && typeof component === 'object') {
for (var name in component) {
validatePropertyKey(name, component);
}
}

@@ -157,6 +192,13 @@ }

isValidComponent: function(object) {
return !!(
object &&
typeof object.mountComponentIntoNode === 'function' &&
typeof object.receiveComponent === 'function'
if (!object || !object.type || !object.type.prototype) {
return false;
}
// This is the safer way of duck checking the type of instance this is.
// The object can be a generic descriptor but the type property refers to
// the constructor and it's prototype can be used to inspect the type that
// will actually get mounted.
var prototype = object.type.prototype;
return (
typeof prototype.mountComponentIntoNode === 'function' &&
typeof prototype.receiveComponent === 'function'
);

@@ -166,21 +208,4 @@ },

/**
* Generate a key string that identifies a component within a set.
*
* @param {*} component A component that could contain a manual key.
* @param {number} index Index that is used if a manual key is not provided.
* @return {string}
* @internal
*/
getKey: function(component, index) {
if (component && component.props && component.props.key != null) {
// Explicit key
return '{' + component.props.key + '}';
}
// Implicit key determined by the index in the set
return '[' + index + ']';
},
/**
* @internal
*/
LifeCycle: ComponentLifeCycle,

@@ -195,3 +220,3 @@

*/
DOMIDOperations: ReactComponentEnvironment.DOMIDOperations,
BackendIDOperations: ReactComponentEnvironment.BackendIDOperations,

@@ -272,13 +297,13 @@ /**

("production" !== process.env.NODE_ENV ? invariant(
!this.props.__owner__,
this.isMounted(),
'replaceProps(...): Can only update a mounted component.'
) : invariant(this.isMounted()));
("production" !== process.env.NODE_ENV ? invariant(
this._mountDepth === 0,
'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
'component with an owner. This is an anti-pattern since props will ' +
'component with a parent. 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.'
) : invariant(!this.props.__owner__));
("production" !== process.env.NODE_ENV ? invariant(
this.isMounted(),
'replaceProps(...): Can only update a mounted component.'
) : invariant(this.isMounted()));
) : invariant(this._mountDepth === 0));
this._pendingProps = props;

@@ -289,3 +314,3 @@ ReactUpdates.enqueueUpdate(this, callback);

/**
* Base constructor for all React component.
* Base constructor for all React components.
*

@@ -302,3 +327,3 @@ * Subclasses that override this method should make sure to invoke

// Record the component responsible for creating this component.
this.props.__owner__ = ReactCurrentOwner.current;
this._owner = ReactCurrentOwner.current;
// All components start unmounted.

@@ -310,2 +335,8 @@ this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;

// Unlike _pendingProps and _pendingCallbacks, we won't use null to
// indicate that nothing is pending because it's possible for a component
// to have a null owner. Instead, an owner change is pending when
// this._owner !== this._pendingOwner.
this._pendingOwner = this._owner;
// Children can be more than one argument

@@ -347,3 +378,5 @@ var childrenLength = arguments.length - 1;

!this.isMounted(),
'mountComponent(%s, ...): Can only mount an unmounted component.',
'mountComponent(%s, ...): Can only mount an unmounted component. ' +
'Make sure to avoid storing components between renders or reusing a ' +
'single component instance in multiple places.',
rootID

@@ -353,3 +386,3 @@ ) : invariant(!this.isMounted()));

if (props.ref != null) {
ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__);
ReactOwner.addComponentAsRefTo(this, props.ref, this._owner);
}

@@ -379,3 +412,3 @@ this._rootNodeID = rootID;

if (props.ref != null) {
ReactOwner.removeComponentAsRefFrom(this, props.ref, props.__owner__);
ReactOwner.removeComponentAsRefFrom(this, props.ref, this._owner);
}

@@ -403,2 +436,3 @@ ReactComponent.unmountIDFromEnvironment(this._rootNodeID);

) : invariant(this.isMounted()));
this._pendingOwner = nextComponent._owner;
this._pendingProps = nextComponent.props;

@@ -431,5 +465,7 @@ this._performUpdateIfNecessary(transaction);

var prevProps = this.props;
var prevOwner = this._owner;
this.props = this._pendingProps;
this._owner = this._pendingOwner;
this._pendingProps = null;
this.updateComponent(transaction, prevProps);
this.updateComponent(transaction, prevProps, prevOwner);
},

@@ -444,3 +480,3 @@

*/
updateComponent: function(transaction, prevProps) {
updateComponent: function(transaction, prevProps, prevOwner) {
var props = this.props;

@@ -450,7 +486,6 @@ // If either the owner or a `ref` has changed, make sure the newest owner

// has forgotten the reference to `this`.
if (props.__owner__ !== prevProps.__owner__ ||
props.ref !== prevProps.ref) {
if (this._owner !== prevOwner || props.ref !== prevProps.ref) {
if (prevProps.ref != null) {
ReactOwner.removeComponentAsRefFrom(
this, prevProps.ref, prevProps.__owner__
this, prevProps.ref, prevOwner
);

@@ -460,3 +495,3 @@ }

if (props.ref != null) {
ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__);
ReactOwner.addComponentAsRefTo(this, props.ref, this._owner);
}

@@ -515,3 +550,3 @@ }

isOwnedBy: function(owner) {
return this.props.__owner__ === owner;
return this._owner === owner;
},

@@ -528,3 +563,3 @@

getSiblingByRef: function(ref) {
var owner = this.props.__owner__;
var owner = this._owner;
if (!owner || !owner.refs) {

@@ -531,0 +566,0 @@ return null;

@@ -26,2 +26,3 @@ /**

var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");
var ReactReconcileTransaction = require("./ReactReconcileTransaction");

@@ -31,3 +32,2 @@

var invariant = require("./invariant");
var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup");

@@ -66,3 +66,3 @@

DOMIDOperations: ReactDOMIDOperations,
BackendIDOperations: ReactDOMIDOperations,

@@ -86,59 +86,77 @@ /**

*/
mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
("production" !== process.env.NODE_ENV ? invariant(
container && (
mountImageIntoNode: ReactPerf.measure(
'ReactComponentBrowserEnvironment',
'mountImageIntoNode',
function(markup, container, shouldReuseMarkup) {
("production" !== process.env.NODE_ENV ? invariant(
container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
),
'mountComponentIntoNode(...): Target container is not valid.'
) : invariant(container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
),
'mountComponentIntoNode(...): Target container is not valid.'
) : invariant(container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
)));
if (shouldReuseMarkup) {
if (ReactMarkupChecksum.canReuseMarkup(
markup,
getReactRootElementInContainer(container))) {
return;
} else {
if ("production" !== process.env.NODE_ENV) {
console.warn(
'React attempted to use reuse markup in a container but the ' +
'checksum was invalid. This generally means that you are using ' +
'server rendering and the markup generated on the server was ' +
'not what the client was expecting. React injected new markup ' +
'to compensate which works but you have lost many of the ' +
'benefits of server rendering. Instead, figure out why the ' +
'markup being generated is different on the client or server.'
);
container.nodeType === DOC_NODE_TYPE
)));
if (shouldReuseMarkup) {
if (ReactMarkupChecksum.canReuseMarkup(
markup,
getReactRootElementInContainer(container))) {
return;
} else {
("production" !== process.env.NODE_ENV ? invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document using ' +
'server rendering but the checksum was invalid. This usually ' +
'means you rendered a different component type or props on ' +
'the client from the one on the server, or your render() ' +
'methods are impure. React cannot handle this case due to ' +
'cross-browser quirks by rendering at the document root. You ' +
'should look for environment dependent code in your components ' +
'and ensure the props are the same client and server side.'
) : invariant(container.nodeType !== DOC_NODE_TYPE));
if ("production" !== process.env.NODE_ENV) {
console.warn(
'React attempted to use reuse markup in a container but the ' +
'checksum was invalid. This generally means that you are ' +
'using server rendering and the markup generated on the ' +
'server was not what the client was expecting. React injected' +
'new markup to compensate which works but you have lost many ' +
'of the benefits of server rendering. Instead, figure out ' +
'why the markup being generated is different on the client ' +
'or server.'
);
}
}
}
}
// You can't naively set the innerHTML of the entire document. You need
// to mutate documentElement which requires doing some crazy tricks. See
// mutateHTMLNodeWithMarkup()
if (container.nodeType === DOC_NODE_TYPE) {
mutateHTMLNodeWithMarkup(container.documentElement, markup);
return;
}
("production" !== process.env.NODE_ENV ? invariant(
container.nodeType !== DOC_NODE_TYPE,
'You\'re trying to render a component to the document but ' +
'you didn\'t use server rendering. We can\'t do this ' +
'without using server rendering due to cross-browser quirks. ' +
'See renderComponentToString() for server rendering.'
) : invariant(container.nodeType !== DOC_NODE_TYPE));
// 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);
// 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 {
parent.appendChild(container);
container.innerHTML = markup;
}
} else {
container.innerHTML = markup;
}
}
)
};
module.exports = ReactComponentBrowserEnvironment;

@@ -19,2 +19,4 @@ /**

"use strict";
var ReactComponentBrowserEnvironment =

@@ -21,0 +23,0 @@ require("./ReactComponentBrowserEnvironment");

@@ -22,2 +22,3 @@ /**

var ReactComponent = require("./ReactComponent");
var ReactContext = require("./ReactContext");
var ReactCurrentOwner = require("./ReactCurrentOwner");

@@ -28,2 +29,4 @@ var ReactErrorUtils = require("./ReactErrorUtils");

var ReactPropTransferer = require("./ReactPropTransferer");
var ReactPropTypeLocations = require("./ReactPropTypeLocations");
var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
var ReactUpdates = require("./ReactUpdates");

@@ -36,2 +39,3 @@

var objMap = require("./objMap");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");

@@ -96,2 +100,11 @@ /**

/**
* An object containing properties and methods that should be defined on
* the component's constructor instead of its prototype (static methods).
*
* @type {object}
* @optional
*/
statics: SpecPolicy.DEFINE_MANY,
/**
* Definition of prop types for this component.

@@ -102,5 +115,19 @@ *

*/
propTypes: SpecPolicy.DEFINE_ONCE,
propTypes: SpecPolicy.DEFINE_MANY,
/**
* Definition of context types for this component.
*
* @type {object}
* @optional
*/
contextTypes: SpecPolicy.DEFINE_MANY,
/**
* Definition of context types this component sets for its children.
*
* @type {object}
* @optional
*/
childContextTypes: SpecPolicy.DEFINE_MANY,

@@ -138,2 +165,8 @@ // ==== Definition methods ====

/**
* @return {object}
* @optional
*/
getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
/**
* Uses props from `this.props` and state from `this.state` to render the

@@ -187,3 +220,3 @@ * structure of the component.

*
* componentWillReceiveProps: function(nextProps) {
* componentWillReceiveProps: function(nextProps, nextContext) {
* this.setState({

@@ -205,9 +238,12 @@ * likesIncreasing: nextProps.likeCount > this.props.likeCount

* Invoked while deciding if the component should be updated as a result of
* receiving new props and state.
* receiving new props, state and/or context.
*
* 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.
* transition to the new props/state/context will not require a component
* update.
*
* shouldComponentUpdate: function(nextProps, nextState) {
* return !equal(nextProps, this.props) || !equal(nextState, this.state);
* shouldComponentUpdate: function(nextProps, nextState, nextContext) {
* return !equal(nextProps, this.props) ||
* !equal(nextState, this.state) ||
* !equal(nextContext, this.context);
* }

@@ -217,2 +253,3 @@ *

* @param {?object} nextState
* @param {?object} nextContext
* @return {boolean} True if the component should update.

@@ -225,3 +262,4 @@ * @optional

* Invoked when the component is about to update due to a transition from
* `this.props` and `this.state` to `nextProps` and `nextState`.
* `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
* and `nextContext`.
*

@@ -234,2 +272,3 @@ * Use this as an opportunity to perform preparation before an update occurs.

* @param {?object} nextState
* @param {?object} nextContext
* @param {ReactReconcileTransaction} transaction

@@ -248,2 +287,3 @@ * @optional

* @param {?object} prevState
* @param {?object} prevContext
* @param {DOMElement} rootNode DOM element representing the component.

@@ -288,21 +328,69 @@ * @optional

*
* Although these are declared in the specification when defining classes
* using `React.createClass`, they will not be on the component's prototype.
* Although these are declared like instance properties in the specification
* when defining classes using `React.createClass`, they are actually static
* and are accessible on the constructor instead of the prototype. Despite
* being static, they must be defined outside of the "statics" key under
* which all other static methods are defined.
*/
var RESERVED_SPEC_KEYS = {
displayName: function(Constructor, displayName) {
Constructor.displayName = displayName;
displayName: function(ConvenienceConstructor, displayName) {
ConvenienceConstructor.componentConstructor.displayName = displayName;
},
mixins: function(Constructor, mixins) {
mixins: function(ConvenienceConstructor, mixins) {
if (mixins) {
for (var i = 0; i < mixins.length; i++) {
mixSpecIntoComponent(Constructor, mixins[i]);
mixSpecIntoComponent(ConvenienceConstructor, mixins[i]);
}
}
},
propTypes: function(Constructor, propTypes) {
Constructor.propTypes = propTypes;
childContextTypes: function(ConvenienceConstructor, childContextTypes) {
var Constructor = ConvenienceConstructor.componentConstructor;
validateTypeDef(
Constructor,
childContextTypes,
ReactPropTypeLocations.childContext
);
Constructor.childContextTypes = merge(
Constructor.childContextTypes,
childContextTypes
);
},
contextTypes: function(ConvenienceConstructor, contextTypes) {
var Constructor = ConvenienceConstructor.componentConstructor;
validateTypeDef(
Constructor,
contextTypes,
ReactPropTypeLocations.context
);
Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
},
propTypes: function(ConvenienceConstructor, propTypes) {
var Constructor = ConvenienceConstructor.componentConstructor;
validateTypeDef(
Constructor,
propTypes,
ReactPropTypeLocations.prop
);
Constructor.propTypes = merge(Constructor.propTypes, propTypes);
},
statics: function(ConvenienceConstructor, statics) {
mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
}
};
function validateTypeDef(Constructor, typeDef, location) {
for (var propName in typeDef) {
if (typeDef.hasOwnProperty(propName)) {
("production" !== process.env.NODE_ENV ? invariant(
typeof typeDef[propName] == 'function',
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
'React.PropTypes.',
Constructor.displayName || 'ReactCompositeComponent',
ReactPropTypeLocationNames[location],
propName
) : invariant(typeof typeDef[propName] == 'function'));
}
}
}
function validateMethodOverride(proto, name) {

@@ -336,3 +424,2 @@ var specPolicy = ReactCompositeComponentInterface[name];

function validateLifeCycleOnReplaceState(instance) {

@@ -361,13 +448,26 @@ var compositeLifeCycleState = instance._compositeLifeCycleState;

*/
function mixSpecIntoComponent(Constructor, spec) {
function mixSpecIntoComponent(ConvenienceConstructor, spec) {
("production" !== process.env.NODE_ENV ? invariant(
!isValidClass(spec),
'ReactCompositeComponent: You\'re attempting to ' +
'use a component class as a mixin. Instead, just use a regular object.'
) : invariant(!isValidClass(spec)));
("production" !== process.env.NODE_ENV ? invariant(
!ReactComponent.isValidComponent(spec),
'ReactCompositeComponent: You\'re attempting to ' +
'use a component as a mixin. Instead, just use a regular object.'
) : invariant(!ReactComponent.isValidComponent(spec)));
var Constructor = ConvenienceConstructor.componentConstructor;
var proto = Constructor.prototype;
for (var name in spec) {
var property = spec[name];
if (!spec.hasOwnProperty(name) || !property) {
if (!spec.hasOwnProperty(name)) {
continue;
}
validateMethodOverride(proto, name);
if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
RESERVED_SPEC_KEYS[name](Constructor, property);
RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property);
} else {

@@ -380,3 +480,3 @@ // Setup methods on prototype:

var isInherited = name in proto;
var markedDontBind = property.__reactDontBind;
var markedDontBind = property && property.__reactDontBind;
var isFunction = typeof property === 'function';

@@ -413,2 +513,33 @@ var shouldAutoBind =

function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
if (!statics) {
return;
}
for (var name in statics) {
var property = statics[name];
if (!statics.hasOwnProperty(name) || !property) {
return;
}
var isInherited = name in ConvenienceConstructor;
var result = property;
if (isInherited) {
var existingProperty = ConvenienceConstructor[name];
var existingType = typeof existingProperty;
var propertyType = typeof property;
("production" !== process.env.NODE_ENV ? invariant(
existingType === 'function' && propertyType === 'function',
'ReactCompositeComponent: You are attempting to define ' +
'`%s` on your component more than once, but that is only supported ' +
'for functions, which are chained together. This conflict may be ' +
'due to a mixin.',
name
) : invariant(existingType === 'function' && propertyType === 'function'));
result = createChainedFunction(existingProperty, property);
}
ConvenienceConstructor[name] = result;
ConvenienceConstructor.componentConstructor[name] = result;
}
}
/**

@@ -449,6 +580,10 @@ * Merge two objects, but throw if both contain the same key.

return function mergedResult() {
return mergeObjectsWithNoDuplicateKeys(
one.apply(this, arguments),
two.apply(this, arguments)
);
var a = one.apply(this, arguments);
var b = two.apply(this, arguments);
if (a == null) {
return b;
} else if (b == null) {
return a;
}
return mergeObjectsWithNoDuplicateKeys(a, b);
};

@@ -472,2 +607,114 @@ }

if ("production" !== process.env.NODE_ENV) {
var unmountedPropertyWhitelist = {
constructor: true,
construct: true,
isOwnedBy: true, // should be deprecated but can have code mod (internal)
mountComponent: true,
mountComponentIntoNode: true,
props: true,
type: true,
_checkPropTypes: true,
_mountComponentIntoNode: true,
_processContext: true
};
var hasWarnedOnComponentType = {};
var warnIfUnmounted = function(instance, key) {
if (instance.__hasBeenMounted) {
return;
}
var name = instance.constructor.displayName || 'Unknown';
var owner = ReactCurrentOwner.current;
var ownerName = (owner && owner.constructor.displayName) || 'Unknown';
var warningKey = key + '|' + name + '|' + ownerName;
if (hasWarnedOnComponentType.hasOwnProperty(warningKey)) {
// We have already warned for this combination. Skip it this time.
return;
}
hasWarnedOnComponentType[warningKey] = true;
var context = owner ? ' in ' + ownerName + '.' : ' at the top level.';
var staticMethodExample = '<' + name + ' />.type.' + key + '(...)';
console.warn(
'Invalid access to component property "' + key + '" on ' + name +
context + ' See http://fb.me/react-warning-descriptors .' +
' Use a static method instead: ' + staticMethodExample
);
};
var defineMembraneProperty = function(membrane, prototype, key) {
Object.defineProperty(membrane, key, {
configurable: false,
enumerable: true,
get: function() {
if (this !== membrane) {
// When this is accessed through a prototype chain we need to check if
// this component was mounted.
warnIfUnmounted(this, key);
}
return prototype[key];
},
set: function(value) {
if (this !== membrane) {
// When this is accessed through a prototype chain, we first check if
// this component was mounted. Then we define a value on "this"
// instance, effectively disabling the membrane on that prototype
// chain.
warnIfUnmounted(this, key);
Object.defineProperty(this, key, {
enumerable: true,
configurable: true,
writable: true,
value: value
});
} else {
// Otherwise, this should modify the prototype
prototype[key] = value;
}
}
});
};
/**
* Creates a membrane prototype which wraps the original prototype. If any
* property is accessed in an unmounted state, a warning is issued.
*
* @param {object} prototype Original prototype.
* @return {object} The membrane prototype.
* @private
*/
var createMountWarningMembrane = function(prototype) {
try {
var membrane = Object.create(prototype);
for (var key in prototype) {
if (unmountedPropertyWhitelist.hasOwnProperty(key)) {
continue;
}
defineMembraneProperty(membrane, prototype, key);
}
membrane.mountComponent = function() {
this.__hasBeenMounted = true;
return prototype.mountComponent.apply(this, arguments);
};
return membrane;
} catch(x) {
// In IE8 define property will fail on non-DOM objects. If anything in
// the membrane creation fails, we'll bail out and just use the prototype
// without warnings.
return prototype;
}
};
}
/**

@@ -538,4 +785,10 @@ * `ReactCompositeComponent` maintains an auxiliary life cycle state in

ReactComponent.Mixin.construct.apply(this, arguments);
this.state = null;
this._pendingState = null;
this.context = this._processContext(ReactContext.current);
this._currentContext = ReactContext.current;
this._pendingContext = null;
this._compositeLifeCycleState = null;

@@ -578,3 +831,3 @@ },

this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
this._processProps(this.props);
this.props = this._processProps(this.props);

@@ -586,2 +839,8 @@ if (this.__reactAutoBindMap) {

this.state = this.getInitialState ? this.getInitialState() : null;
("production" !== process.env.NODE_ENV ? invariant(
typeof this.state === 'object' && !Array.isArray(this.state),
'%s.getInitialState(): must return an object or null',
this.constructor.displayName || 'ReactCompositeComponent'
) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
this._pendingState = null;

@@ -631,6 +890,7 @@ this._pendingForceUpdate = false;

ReactComponent.Mixin.unmountComponent.call(this);
this._renderedComponent.unmountComponent();
this._renderedComponent = null;
ReactComponent.Mixin.unmountComponent.call(this);
if (this.refs) {

@@ -664,2 +924,14 @@ this.refs = null;

setState: function(partialState, callback) {
("production" !== process.env.NODE_ENV ? invariant(
typeof partialState === 'object' || partialState == null,
'setState(...): takes an object of state variables to update.'
) : invariant(typeof partialState === 'object' || partialState == null));
if ("production" !== process.env.NODE_ENV) {
if (partialState == null) {
console.warn(
'setState(...): You passed an undefined or null state object; ' +
'instead, use forceUpdate().'
);
}
}
// Merge with `_pendingState` if it exists, otherwise with existing state.

@@ -691,28 +963,106 @@ this.replaceState(

/**
* Filters the context object to only contain keys specified in
* `contextTypes`, and asserts that they are valid.
*
* @param {object} context
* @return {?object}
* @private
*/
_processContext: function(context) {
var maskedContext = null;
var contextTypes = this.constructor.contextTypes;
if (contextTypes) {
maskedContext = {};
for (var contextName in contextTypes) {
maskedContext[contextName] = context[contextName];
}
if ("production" !== process.env.NODE_ENV) {
this._checkPropTypes(
contextTypes,
maskedContext,
ReactPropTypeLocations.context
);
}
}
return maskedContext;
},
/**
* @param {object} currentContext
* @return {object}
* @private
*/
_processChildContext: function(currentContext) {
var childContext = this.getChildContext && this.getChildContext();
var displayName = this.constructor.displayName || 'ReactCompositeComponent';
if (childContext) {
("production" !== process.env.NODE_ENV ? invariant(
typeof this.constructor.childContextTypes === 'object',
'%s.getChildContext(): childContextTypes must be defined in order to ' +
'use getChildContext().',
displayName
) : invariant(typeof this.constructor.childContextTypes === 'object'));
if ("production" !== process.env.NODE_ENV) {
this._checkPropTypes(
this.constructor.childContextTypes,
childContext,
ReactPropTypeLocations.childContext
);
}
for (var name in childContext) {
("production" !== process.env.NODE_ENV ? invariant(
name in this.constructor.childContextTypes,
'%s.getChildContext(): key "%s" is not defined in childContextTypes.',
displayName,
name
) : invariant(name in this.constructor.childContextTypes));
}
return merge(currentContext, childContext);
}
return currentContext;
},
/**
* Processes props by setting default values for unspecified props and
* asserting that the props are valid.
* asserting that the props are valid. Does not mutate its argument; returns
* a new props object with defaults merged in.
*
* @param {object} props
* @param {object} newProps
* @return {object}
* @private
*/
_processProps: function(props) {
var propName;
_processProps: function(newProps) {
var props = merge(newProps);
var defaultProps = this._defaultProps;
for (propName in defaultProps) {
if (!(propName in props)) {
for (var propName in defaultProps) {
if (typeof props[propName] === 'undefined') {
props[propName] = defaultProps[propName];
}
}
var propTypes = this.constructor.propTypes;
if (propTypes) {
var componentName = this.constructor.displayName;
for (propName in propTypes) {
var checkProp = propTypes[propName];
if (checkProp) {
checkProp(props, propName, componentName);
}
if ("production" !== process.env.NODE_ENV) {
var propTypes = this.constructor.propTypes;
if (propTypes) {
this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop);
}
}
return props;
},
/**
* Assert that the props are valid
*
* @param {object} propTypes Map of prop name to a ReactPropType
* @param {object} props
* @param {string} location e.g. "prop", "context", "child context"
* @private
*/
_checkPropTypes: function(propTypes, props, location) {
var componentName = this.constructor.displayName;
for (var propName in propTypes) {
if (propTypes.hasOwnProperty(propName)) {
propTypes[propName](props, propName, componentName, location);
}
}
},
performUpdateIfNecessary: function() {

@@ -739,2 +1089,3 @@ var compositeLifeCycleState = this._compositeLifeCycleState;

this._pendingState == null &&
this._pendingContext == null &&
!this._pendingForceUpdate) {

@@ -744,6 +1095,9 @@ return;

var nextFullContext = this._pendingContext || this._currentContext;
var nextContext = this._processContext(nextFullContext);
this._pendingContext = null;
var nextProps = this.props;
if (this._pendingProps != null) {
nextProps = this._pendingProps;
this._processProps(nextProps);
nextProps = this._processProps(this._pendingProps);
this._pendingProps = null;

@@ -753,3 +1107,3 @@

if (this.componentWillReceiveProps) {
this.componentWillReceiveProps(nextProps, transaction);
this.componentWillReceiveProps(nextProps, nextContext);
}

@@ -760,19 +1114,37 @@ }

// Unlike props, state, and context, we specifically don't want to set
// _pendingOwner to null here because it's possible for a component to have
// a null owner, so we instead make `this._owner === this._pendingOwner`
// mean that there's no owner change pending.
var nextOwner = this._pendingOwner;
var nextState = this._pendingState || this.state;
this._pendingState = null;
if (this._pendingForceUpdate ||
!this.shouldComponentUpdate ||
this.shouldComponentUpdate(nextProps, nextState)) {
this._pendingForceUpdate = false;
// 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;
try {
if (this._pendingForceUpdate ||
!this.shouldComponentUpdate ||
this.shouldComponentUpdate(nextProps, nextState, nextContext)) {
this._pendingForceUpdate = false;
// Will set `this.props`, `this.state` and `this.context`.
this._performComponentUpdate(
nextProps,
nextOwner,
nextState,
nextFullContext,
nextContext,
transaction
);
} else {
// If it's determined that a component should not update, we still want
// to set props and state.
this.props = nextProps;
this._owner = nextOwner;
this.state = nextState;
this._currentContext = nextFullContext;
this.context = nextContext;
}
} finally {
this._compositeLifeCycleState = null;
}
this._compositeLifeCycleState = null;
},

@@ -785,18 +1157,39 @@

* @param {object} nextProps Next object to set as properties.
* @param {?ReactComponent} nextOwner Next component to set as owner
* @param {?object} nextState Next object to set as state.
* @param {?object} nextFullContext Next object to set as _currentContext.
* @param {?object} nextContext Next object to set as context.
* @param {ReactReconcileTransaction} transaction
* @private
*/
_performComponentUpdate: function(nextProps, nextState, transaction) {
_performComponentUpdate: function(
nextProps,
nextOwner,
nextState,
nextFullContext,
nextContext,
transaction
) {
var prevProps = this.props;
var prevOwner = this._owner;
var prevState = this.state;
var prevContext = this.context;
if (this.componentWillUpdate) {
this.componentWillUpdate(nextProps, nextState, transaction);
this.componentWillUpdate(nextProps, nextState, nextContext);
}
this.props = nextProps;
this._owner = nextOwner;
this.state = nextState;
this._currentContext = nextFullContext;
this.context = nextContext;
this.updateComponent(transaction, prevProps, prevState);
this.updateComponent(
transaction,
prevProps,
prevOwner,
prevState,
prevContext
);

@@ -806,3 +1199,3 @@ if (this.componentDidUpdate) {

this,
this.componentDidUpdate.bind(this, prevProps, prevState)
this.componentDidUpdate.bind(this, prevProps, prevState, prevContext)
);

@@ -812,2 +1205,18 @@ }

receiveComponent: function(nextComponent, transaction) {
if (nextComponent === this) {
// Since props and context are immutable after the component is
// mounted, we can do a cheap identity compare here to determine
// if this is a superfluous reconcile.
return;
}
this._pendingContext = nextComponent._currentContext;
ReactComponent.Mixin.receiveComponent.call(
this,
nextComponent,
transaction
);
},
/**

@@ -821,3 +1230,5 @@ * Updates the component's currently mounted DOM representation.

* @param {object} prevProps
* @param {?ReactComponent} prevOwner
* @param {?object} prevState
* @param {?object} prevContext
* @internal

@@ -829,13 +1240,18 @@ * @overridable

'updateComponent',
function(transaction, prevProps, prevState) {
ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
var currentComponent = this._renderedComponent;
function(transaction, prevProps, prevOwner, prevState, prevContext) {
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevProps,
prevOwner
);
var prevComponent = this._renderedComponent;
var nextComponent = this._renderValidatedComponent();
if (currentComponent.constructor === nextComponent.constructor) {
currentComponent.receiveComponent(nextComponent, transaction);
if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
prevComponent.receiveComponent(nextComponent, 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 prevComponentID = prevComponent._rootNodeID;
prevComponent.unmountComponent();
this._renderedComponent = nextComponent;

@@ -847,4 +1263,4 @@ var nextMarkup = nextComponent.mountComponent(

);
ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID(
currentComponentID,
ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
prevComponentID,
nextMarkup

@@ -893,21 +1309,25 @@ );

*/
_renderValidatedComponent: function() {
var renderedComponent;
ReactCurrentOwner.current = this;
try {
renderedComponent = this.render();
} catch (error) {
// IE8 requires `catch` in order to use `finally`.
throw error;
} finally {
ReactCurrentOwner.current = null;
_renderValidatedComponent: ReactPerf.measure(
'ReactCompositeComponent',
'_renderValidatedComponent',
function() {
var renderedComponent;
var previousContext = ReactContext.current;
ReactContext.current = this._processChildContext(this._currentContext);
ReactCurrentOwner.current = this;
try {
renderedComponent = this.render();
} finally {
ReactContext.current = previousContext;
ReactCurrentOwner.current = null;
}
("production" !== process.env.NODE_ENV ? invariant(
ReactComponent.isValidComponent(renderedComponent),
'%s.render(): A valid ReactComponent must be returned. You may have ' +
'returned null, undefined, an array, or some other invalid object.',
this.constructor.displayName || 'ReactCompositeComponent'
) : invariant(ReactComponent.isValidComponent(renderedComponent)));
return renderedComponent;
}
("production" !== process.env.NODE_ENV ? invariant(
ReactComponent.isValidComponent(renderedComponent),
'%s.render(): A valid ReactComponent must be returned. You may have ' +
'returned null, undefined, an array, or some other invalid object.',
this.constructor.displayName || 'ReactCompositeComponent'
) : invariant(ReactComponent.isValidComponent(renderedComponent)));
return renderedComponent;
},
),

@@ -947,3 +1367,3 @@ /**

var _bind = boundMethod.bind;
boundMethod.bind = function(newThis) {
boundMethod.bind = function(newThis ) {var args=Array.prototype.slice.call(arguments,1);
// User is trying to bind() an autobound method; we effectively will

@@ -957,3 +1377,3 @@ // ignore the value of "this" that the user is trying to use, so

);
} else if (arguments.length === 1) {
} else if (!args.length) {
console.warn(

@@ -969,4 +1389,3 @@ 'bind(): You are binding a component method to the component. ' +

reboundMethod.__reactBoundMethod = method;
reboundMethod.__reactBoundArguments =
Array.prototype.slice.call(arguments, 1);
reboundMethod.__reactBoundArguments = args;
return reboundMethod;

@@ -986,2 +1405,14 @@ };

/**
* Checks if a value is a valid component constructor.
*
* @param {*}
* @return {boolean}
* @public
*/
function isValidClass(componentClass) {
return componentClass instanceof Function &&
'componentConstructor' in componentClass &&
componentClass.componentConstructor instanceof Function;
}
/**
* Module for creating composite components.

@@ -1011,4 +1442,14 @@ *

Constructor.prototype.constructor = Constructor;
mixSpecIntoComponent(Constructor, spec);
var ConvenienceConstructor = function(props, children) {
var instance = new Constructor();
instance.construct.apply(instance, arguments);
return instance;
};
ConvenienceConstructor.componentConstructor = Constructor;
Constructor.ConvenienceConstructor = ConvenienceConstructor;
ConvenienceConstructor.originalSpec = spec;
mixSpecIntoComponent(ConvenienceConstructor, spec);
("production" !== process.env.NODE_ENV ? invariant(

@@ -1030,2 +1471,10 @@ Constructor.prototype.render,

// Expose the convience constructor on the prototype so that it can be
// easily accessed on descriptors. E.g. <Foo />.type === Foo.type and for
// static methods like <Foo />.type.staticMethod();
// This should not be named constructor since this may not be the function
// that created the descriptor, and it may not even be a constructor.
ConvenienceConstructor.type = Constructor;
Constructor.prototype.type = Constructor;
// Reduce time spent doing lookups by setting these on the prototype.

@@ -1038,26 +1487,12 @@ for (var methodName in ReactCompositeComponentInterface) {

var ConvenienceConstructor = function(props, children) {
var instance = new Constructor();
instance.construct.apply(instance, arguments);
return instance;
};
ConvenienceConstructor.componentConstructor = Constructor;
ConvenienceConstructor.originalSpec = spec;
if ("production" !== process.env.NODE_ENV) {
Constructor.prototype = createMountWarningMembrane(Constructor.prototype);
}
return ConvenienceConstructor;
},
/**
* Checks if a value is a valid component constructor.
*
* @param {*}
* @return {boolean}
* @public
*/
isValidClass: function(componentClass) {
return componentClass instanceof Function &&
'componentConstructor' in componentClass &&
componentClass.componentConstructor instanceof Function;
}
isValidClass: isValidClass
};
module.exports = ReactCompositeComponent;

@@ -21,36 +21,44 @@ /**

var ReactDOM = require("./ReactDOM");
var ReactDOMButton = require("./ReactDOMButton");
var ReactDOMForm = require("./ReactDOMForm");
var ReactDOMInput = require("./ReactDOMInput");
var ReactDOMOption = require("./ReactDOMOption");
var ReactDOMSelect = require("./ReactDOMSelect");
var ReactDOMTextarea = require("./ReactDOMTextarea");
var ReactEventEmitter = require("./ReactEventEmitter");
var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback");
var ReactPerf = require("./ReactPerf");
var ReactInjection = require("./ReactInjection");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var DefaultDOMPropertyConfig = require("./DefaultDOMPropertyConfig");
var DOMProperty = require("./DOMProperty");
var ChangeEventPlugin = require("./ChangeEventPlugin");
var ClientReactRootIndex = require("./ClientReactRootIndex");
var CompositionEventPlugin = require("./CompositionEventPlugin");
var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
var EventPluginHub = require("./EventPluginHub");
var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin");
var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback");
var ReactDOM = require("./ReactDOM");
var ReactDOMButton = require("./ReactDOMButton");
var ReactDOMForm = require("./ReactDOMForm");
var ReactDOMImg = require("./ReactDOMImg");
var ReactDOMInput = require("./ReactDOMInput");
var ReactDOMOption = require("./ReactDOMOption");
var ReactDOMSelect = require("./ReactDOMSelect");
var ReactDOMTextarea = require("./ReactDOMTextarea");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactMount = require("./ReactMount");
var SelectEventPlugin = require("./SelectEventPlugin");
var ServerReactRootIndex = require("./ServerReactRootIndex");
var SimpleEventPlugin = require("./SimpleEventPlugin");
var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy");
var ReactUpdates = require("./ReactUpdates");
var createFullPageComponent = require("./createFullPageComponent");
function inject() {
ReactEventEmitter.TopLevelCallbackCreator = ReactEventTopLevelCallback;
ReactInjection.EventEmitter.injectTopLevelCallbackCreator(
ReactEventTopLevelCallback
);
/**
* Inject module for resolving DOM hierarchy and plugin ordering.
* Inject modules for resolving DOM hierarchy and plugin ordering.
*/
EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder);
EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
ReactInjection.EventPluginHub.injectMount(ReactMount);

@@ -61,3 +69,3 @@ /**

*/
EventPluginHub.injection.injectEventPluginsByName({
ReactInjection.EventPluginHub.injectEventPluginsByName({
SimpleEventPlugin: SimpleEventPlugin,

@@ -71,20 +79,36 @@ EnterLeaveEventPlugin: EnterLeaveEventPlugin,

ReactDOM.injection.injectComponentClasses({
ReactInjection.DOM.injectComponentClasses({
button: ReactDOMButton,
form: ReactDOMForm,
img: ReactDOMImg,
input: ReactDOMInput,
option: ReactDOMOption,
select: ReactDOMSelect,
textarea: ReactDOMTextarea
textarea: ReactDOMTextarea,
html: createFullPageComponent(ReactDOM.html),
head: createFullPageComponent(ReactDOM.head),
title: createFullPageComponent(ReactDOM.title),
body: createFullPageComponent(ReactDOM.body)
});
DOMProperty.injection.injectDOMPropertyConfig(DefaultDOMPropertyConfig);
ReactInjection.DOMProperty.injectDOMPropertyConfig(DefaultDOMPropertyConfig);
ReactInjection.Updates.injectBatchingStrategy(
ReactDefaultBatchingStrategy
);
ReactInjection.RootIndex.injectCreateReactRootIndex(
ExecutionEnvironment.canUseDOM ?
ClientReactRootIndex.createReactRootIndex :
ServerReactRootIndex.createReactRootIndex
);
if ("production" !== process.env.NODE_ENV) {
ReactPerf.injection.injectMeasure(require("./ReactDefaultPerf").measure);
var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
if ((/[?&]react_perf\b/).test(url)) {
var ReactDefaultPerf = require("./ReactDefaultPerf");
ReactDefaultPerf.start();
}
}
ReactUpdates.injection.injectBatchingStrategy(
ReactDefaultBatchingStrategy
);
}

@@ -91,0 +115,0 @@

@@ -22,387 +22,224 @@ /**

var DOMProperty = require("./DOMProperty");
var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");
var performanceNow = require("./performanceNow");
var ReactDefaultPerf = {};
function roundFloat(val) {
return Math.floor(val * 100) / 100;
}
if ("production" !== process.env.NODE_ENV) {
ReactDefaultPerf = {
/**
* Gets the stored information for a given object's function.
*
* @param {string} objName
* @param {string} fnName
* @return {?object}
*/
getInfo: function(objName, fnName) {
if (!this.info[objName] || !this.info[objName][fnName]) {
return null;
}
return this.info[objName][fnName];
},
var ReactDefaultPerf = {
_allMeasurements: [], // last item in the list is the current one
_injected: false,
/**
* Gets the logs pertaining to a given object's function.
*
* @param {string} objName
* @param {string} fnName
* @return {?array<object>}
*/
getLogs: function(objName, fnName) {
if (!this.getInfo(objName, fnName)) {
return null;
}
return this.logs.filter(function(log) {
return log.objName === objName && log.fnName === fnName;
});
},
start: function() {
if (!ReactDefaultPerf._injected) {
ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
}
/**
* Runs through the logs and builds an array of arrays, where each array
* walks through the mounting/updating of each component underneath.
*
* @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]'
* @return {array<array>}
*/
getRawRenderHistory: function(rootID) {
var history = [];
/**
* Since logs are added after the method returns, the logs are in a sense
* upside-down: the inner-most elements from mounting/updating are logged
* first, and the last addition to the log is the top renderComponent.
* Therefore, we flip the logs upside down for ease of processing, and
* reverse the history array at the end so the earliest event has index 0.
*/
var logs = this.logs.filter(function(log) {
return log.reactID.indexOf(rootID) === 0;
}).reverse();
ReactDefaultPerf._allMeasurements.length = 0;
ReactPerf.enableMeasure = true;
},
var subHistory = [];
logs.forEach(function(log, i) {
if (i && log.reactID === rootID && logs[i - 1].reactID !== rootID) {
subHistory.length && history.push(subHistory);
subHistory = [];
}
subHistory.push(log);
});
if (subHistory.length) {
history.push(subHistory);
}
return history.reverse();
},
stop: function() {
ReactPerf.enableMeasure = false;
},
/**
* Runs through the logs and builds an array of strings, where each string
* is a multiline formatted way of walking through the mounting/updating
* underneath.
*
* @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]'
* @return {array<string>}
*/
getRenderHistory: function(rootID) {
var history = this.getRawRenderHistory(rootID);
getLastMeasurements: function() {
return ReactDefaultPerf._allMeasurements;
},
return history.map(function(subHistory) {
var headerString = (
'log# Component (execution time) [bloat from logging]\n' +
'================================================================\n'
);
return headerString + subHistory.map(function(log) {
// Add two spaces for every layer in the reactID.
var indents = '\t' + Array(log.reactID.split('.[').length).join(' ');
var delta = _microTime(log.timing.delta);
var bloat = _microTime(log.timing.timeToLog);
printExclusive: function(measurements) {
measurements = measurements || ReactDefaultPerf._allMeasurements;
var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
console.table(summary.map(function(item) {
return {
'Component class name': item.componentName,
'Total inclusive time (ms)': roundFloat(item.inclusive),
'Total exclusive time (ms)': roundFloat(item.exclusive),
'Exclusive time per instance (ms)': roundFloat(item.exclusive / item.count),
'Instances': item.count
};
}));
console.log(
'Total time:',
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
);
},
return log.index + indents + log.name + ' (' + delta + 'ms)' +
' [' + bloat + 'ms]';
}).join('\n');
});
},
printInclusive: function(measurements) {
measurements = measurements || ReactDefaultPerf._allMeasurements;
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
console.table(summary.map(function(item) {
return {
'Owner > component': item.componentName,
'Inclusive time (ms)': roundFloat(item.time),
'Instances': item.count
};
}));
console.log(
'Total time:',
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
);
},
/**
* Print the render history from `getRenderHistory` using console.log.
* This is currently the best way to display perf data from
* any React component; working on that.
*
* @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]'
* @param {number} index
*/
printRenderHistory: function(rootID, index) {
var history = this.getRenderHistory(rootID);
if (!history[index]) {
console.warn(
'Index', index, 'isn\'t available! ' +
'The render history is', history.length, 'long.'
);
return;
}
console.log(
'Loading render history #' + (index + 1) +
' of ' + history.length + ':\n' + history[index]
);
},
printWasted: function(measurements) {
measurements = measurements || ReactDefaultPerf._allMeasurements;
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
measurements,
true
);
console.table(summary.map(function(item) {
return {
'Owner > component': item.componentName,
'Wasted time (ms)': item.time,
'Instances': item.count
};
}));
console.log(
'Total time:',
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
);
},
/**
* Prints the heatmap legend to console, showing how the colors correspond
* with render times. This relies on console.log styles.
*/
printHeatmapLegend: function() {
if (!this.options.heatmap.enabled) {
return;
}
var max = this.info.React
&& this.info.React.renderComponent
&& this.info.React.renderComponent.max;
if (max) {
var logStr = 'Heatmap: ';
for (var ii = 0; ii <= 10 * max; ii += max) {
logStr += '%c ' + (Math.round(ii) / 10) + 'ms ';
}
console.log(
logStr,
'background-color: hsla(100, 100%, 50%, 0.6);',
'background-color: hsla( 90, 100%, 50%, 0.6);',
'background-color: hsla( 80, 100%, 50%, 0.6);',
'background-color: hsla( 70, 100%, 50%, 0.6);',
'background-color: hsla( 60, 100%, 50%, 0.6);',
'background-color: hsla( 50, 100%, 50%, 0.6);',
'background-color: hsla( 40, 100%, 50%, 0.6);',
'background-color: hsla( 30, 100%, 50%, 0.6);',
'background-color: hsla( 20, 100%, 50%, 0.6);',
'background-color: hsla( 10, 100%, 50%, 0.6);',
'background-color: hsla( 0, 100%, 50%, 0.6);'
);
}
},
printDOM: function(measurements) {
measurements = measurements || ReactDefaultPerf._allMeasurements;
var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
console.table(summary.map(function(item) {
var result = {};
result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
result['type'] = item.type;
result['args'] = JSON.stringify(item.args);
return result;
}));
console.log(
'Total time:',
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
);
},
/**
* Measure a given function with logging information, and calls a callback
* if there is one.
*
* @param {string} objName
* @param {string} fnName
* @param {function} func
* @return {function}
*/
measure: function(objName, fnName, func) {
var info = _getNewInfo(objName, fnName);
_recordWrite: function(id, fnName, totalTime, args) {
// TODO: totalTime isn't that useful since it doesn't count paints/reflows
var writes =
ReactDefaultPerf
._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
.writes;
writes[id] = writes[id] || [];
writes[id].push({
type: fnName,
time: totalTime,
args: args
});
},
var fnArgs = _getFnArguments(func);
measure: function(moduleName, fnName, func) {
return function() {var args=Array.prototype.slice.call(arguments,0);
var totalTime;
var rv;
var start;
return function() {
var timeBeforeFn = performanceNow();
var fnReturn = func.apply(this, arguments);
var timeAfterFn = performanceNow();
if (fnName === '_renderNewRootComponent' ||
fnName === 'flushBatchedUpdates') {
// A "measurement" is a set of metrics recorded for each flush. We want
// to group the metrics for a given flush together so we can look at the
// components that rendered and the DOM operations that actually
// happened to determine the amount of "wasted work" performed.
ReactDefaultPerf._allMeasurements.push({
exclusive: {},
inclusive: {},
counts: {},
writes: {},
displayNames: {},
totalTime: 0
});
start = performanceNow();
rv = func.apply(this, args);
ReactDefaultPerf._allMeasurements[
ReactDefaultPerf._allMeasurements.length - 1
].totalTime = performanceNow() - start;
return rv;
} else if (moduleName === 'ReactDOMIDOperations' ||
moduleName === 'ReactComponentBrowserEnvironment') {
start = performanceNow();
rv = func.apply(this, args);
totalTime = performanceNow() - start;
/**
* Hold onto arguments in a readable way: args[1] -> args.component.
* args is also passed to the callback, so if you want to save an
* argument in the log, do so in the callback.
*/
var args = {};
for (var i = 0; i < arguments.length; i++) {
args[fnArgs[i]] = arguments[i];
if (fnName === 'mountImageIntoNode') {
var mountID = ReactMount.getID(args[1]);
ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
} else if (fnName === 'dangerouslyProcessChildrenUpdates') {
// special format
args[0].forEach(function(update) {
var writeArgs = {};
if (update.fromIndex !== null) {
writeArgs.fromIndex = update.fromIndex;
}
if (update.toIndex !== null) {
writeArgs.toIndex = update.toIndex;
}
if (update.textContent !== null) {
writeArgs.textContent = update.textContent;
}
if (update.markupIndex !== null) {
writeArgs.markup = args[1][update.markupIndex];
}
ReactDefaultPerf._recordWrite(
update.parentID,
update.type,
totalTime,
writeArgs
);
});
} else {
// basic format
ReactDefaultPerf._recordWrite(
args[0],
fnName,
totalTime,
Array.prototype.slice.call(args, 1)
);
}
return rv;
} else if (moduleName === 'ReactCompositeComponent' && (
fnName === 'mountComponent' ||
fnName === 'updateComponent' || // TODO: receiveComponent()?
fnName === '_renderValidatedComponent')) {
var log = {
index: ReactDefaultPerf.logs.length,
fnName: fnName,
objName: objName,
timing: {
before: timeBeforeFn,
after: timeAfterFn,
delta: timeAfterFn - timeBeforeFn
}
};
var rootNodeID = fnName === 'mountComponent' ?
args[0] :
this._rootNodeID;
var isRender = fnName === '_renderValidatedComponent';
var entry = ReactDefaultPerf._allMeasurements[
ReactDefaultPerf._allMeasurements.length - 1
];
ReactDefaultPerf.logs.push(log);
if (isRender) {
entry.counts[rootNodeID] = entry.counts[rootNodeID] || 0;
entry.counts[rootNodeID] += 1;
}
/**
* The callback gets:
* - this (the component)
* - the original method's arguments
* - what the method returned
* - the log object, and
* - the wrapped method's info object.
*/
var callback = _getCallback(objName, fnName);
callback && callback(this, args, fnReturn, log, info);
start = performanceNow();
rv = func.apply(this, args);
totalTime = performanceNow() - start;
log.timing.timeToLog = performanceNow() - timeAfterFn;
var typeOfLog = isRender ? entry.exclusive : entry.inclusive;
typeOfLog[rootNodeID] = typeOfLog[rootNodeID] || 0;
typeOfLog[rootNodeID] += totalTime;
return fnReturn;
};
},
entry.displayNames[rootNodeID] = {
current: this.constructor.displayName,
owner: this._owner ? this._owner.constructor.displayName : '<root>'
};
/**
* Holds information on wrapped objects/methods.
* For instance, ReactDefaultPerf.info.React.renderComponent
*/
info: {},
/**
* Holds all of the logs. Filter this to pull desired information.
*/
logs: [],
/**
* Toggle settings for ReactDefaultPerf
*/
options: {
/**
* The heatmap sets the background color of the React containers
* according to how much total time has been spent rendering them.
* The most temporally expensive component is set as pure red,
* and the others are colored from green to red as a fraction
* of that max component time.
*/
heatmap: {
enabled: true
return rv;
} else {
return func.apply(this, args);
}
}
};
/**
* Gets a info area for a given object's function, adding a new one if
* necessary.
*
* @param {string} objName
* @param {string} fnName
* @return {object}
*/
var _getNewInfo = function(objName, fnName) {
var info = ReactDefaultPerf.getInfo(objName, fnName);
if (info) {
return info;
}
ReactDefaultPerf.info[objName] = ReactDefaultPerf.info[objName] || {};
return ReactDefaultPerf.info[objName][fnName] = {
getLogs: function() {
return ReactDefaultPerf.getLogs(objName, fnName);
}
};
};
}
};
/**
* Gets a list of the argument names from a function's definition.
* This is useful for storing arguments by their names within wrapFn().
*
* @param {function} fn
* @return {array<string>}
*/
var _getFnArguments = function(fn) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var fnStr = fn.toString().replace(STRIP_COMMENTS, '');
fnStr = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')'));
return fnStr.match(/([^\s,]+)/g);
};
/**
* Store common callbacks within ReactDefaultPerf.
*
* @param {string} objName
* @param {string} fnName
* @return {?function}
*/
var _getCallback = function(objName, fnName) {
switch (objName + '.' + fnName) {
case 'React.renderComponent':
return _renderComponentCallback;
case 'ReactDOMComponent.mountComponent':
case 'ReactDOMComponent.updateComponent':
return _nativeComponentCallback;
case 'ReactCompositeComponent.mountComponent':
case 'ReactCompositeComponent.updateComponent':
return _compositeComponentCallback;
default:
return null;
}
};
/**
* Callback function for React.renderComponent
*
* @param {object} component
* @param {object} args
* @param {?object} fnReturn
* @param {object} log
* @param {object} info
*/
var _renderComponentCallback =
function(component, args, fnReturn, log, info) {
log.name = args.nextComponent.constructor.displayName || '[unknown]';
log.reactID = fnReturn._rootNodeID || null;
if (ReactDefaultPerf.options.heatmap.enabled) {
var container = args.container;
if (!container.loggedByReactDefaultPerf) {
container.loggedByReactDefaultPerf = true;
info.components = info.components || [];
info.components.push(container);
}
container.count = container.count || 0;
container.count += log.timing.delta;
info.max = info.max || 0;
if (container.count > info.max) {
info.max = container.count;
info.components.forEach(function(component) {
_setHue(component, 100 - 100 * component.count / info.max);
});
} else {
_setHue(container, 100 - 100 * container.count / info.max);
}
}
};
/**
* Callback function for ReactDOMComponent
*
* @param {object} component
* @param {object} args
* @param {?object} fnReturn
* @param {object} log
* @param {object} info
*/
var _nativeComponentCallback =
function(component, args, fnReturn, log, info) {
log.name = component.tagName || '[unknown]';
log.reactID = component._rootNodeID;
};
/**
* Callback function for ReactCompositeComponent
*
* @param {object} component
* @param {object} args
* @param {?object} fnReturn
* @param {object} log
* @param {object} info
*/
var _compositeComponentCallback =
function(component, args, fnReturn, log, info) {
log.name = component.constructor.displayName || '[unknown]';
log.reactID = component._rootNodeID;
};
/**
* Using the hsl() background-color attribute, colors an element.
*
* @param {DOMElement} el
* @param {number} hue [0 for red, 120 for green, 240 for blue]
*/
var _setHue = function(el, hue) {
el.style.backgroundColor = 'hsla(' + hue + ', 100%, 50%, 0.6)';
};
/**
* Round to the thousandth place.
* @param {number} time
* @return {number}
*/
var _microTime = function(time) {
return Math.round(time * 1000) / 1000;
};
}
module.exports = ReactDefaultPerf;

@@ -53,2 +53,10 @@ /**

};
// Expose the constructor on the ConvenienceConstructor and prototype so that
// it can be easily easily accessed on descriptors.
// E.g. <div />.type === div.type
ConvenienceConstructor.type = Constructor;
Constructor.prototype.type = Constructor;
Constructor.ConvenienceConstructor = ConvenienceConstructor;
ConvenienceConstructor.componentConstructor = Constructor;

@@ -178,7 +186,12 @@ return ConvenienceConstructor;

circle: false,
defs: false,
g: false,
line: false,
linearGradient: false,
path: false,
polygon: false,
polyline: false,
radialGradient: false,
rect: false,
stop: false,
svg: false,

@@ -185,0 +198,0 @@ text: false

@@ -21,2 +21,3 @@ /**

var AutoFocusMixin = require("./AutoFocusMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");

@@ -48,3 +49,6 @@ var ReactDOM = require("./ReactDOM");

var ReactDOMButton = ReactCompositeComponent.createClass({
displayName: 'ReactDOMButton',
mixins: [AutoFocusMixin],
render: function() {

@@ -51,0 +55,0 @@ var props = {};

@@ -27,4 +27,4 @@ /**

var ReactEventEmitter = require("./ReactEventEmitter");
var ReactMount = require("./ReactMount");
var ReactMultiChild = require("./ReactMultiChild");
var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");

@@ -38,5 +38,5 @@

var putListener = ReactEventEmitter.putListener;
var deleteListener = ReactEventEmitter.deleteListener;
var registrationNames = ReactEventEmitter.registrationNames;
var listenTo = ReactEventEmitter.listenTo;
var registrationNameModules = ReactEventEmitter.registrationNameModules;

@@ -48,2 +48,4 @@ // For quickly matching children type, to test if can be treated as content.

var ELEMENT_NODE_TYPE = 1;
/**

@@ -68,2 +70,18 @@ * @param {?object} props

function putListener(id, registrationName, listener, transaction) {
var container = ReactMount.findReactContainerForID(id);
if (container) {
var doc = container.nodeType === ELEMENT_NODE_TYPE ?
container.ownerDocument :
container;
listenTo(registrationName, doc);
}
transaction.getPutListenerQueue().enqueuePutListener(
id,
registrationName,
listener
);
}
/**

@@ -104,3 +122,3 @@ * @constructor ReactDOMComponent

return (
this._createOpenTagMarkup() +
this._createOpenTagMarkupAndPutListeners(transaction) +
this._createContentMarkup(transaction) +

@@ -121,5 +139,6 @@ this._tagClose

* @private
* @param {ReactReconcileTransaction} transaction
* @return {string} Markup of opening tag.
*/
_createOpenTagMarkup: function() {
_createOpenTagMarkupAndPutListeners: function(transaction) {
var props = this.props;

@@ -136,4 +155,4 @@ var ret = this._tagOpen;

}
if (registrationNames[propKey]) {
putListener(this._rootNodeID, propKey, propValue);
if (registrationNameModules[propKey]) {
putListener(this._rootNodeID, propKey, propValue, transaction);
} else {

@@ -154,4 +173,4 @@ if (propKey === STYLE) {

var escapedID = escapeTextForBrowser(this._rootNodeID);
return ret + ' ' + ReactMount.ATTR_NAME + '="' + escapedID + '">';
var idMarkup = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
return ret + ' ' + idMarkup + '>';
},

@@ -211,5 +230,10 @@

'updateComponent',
function(transaction, prevProps) {
ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
this._updateDOMProperties(prevProps);
function(transaction, prevProps, prevOwner) {
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevProps,
prevOwner
);
this._updateDOMProperties(prevProps, transaction);
this._updateDOMChildren(prevProps, transaction);

@@ -232,4 +256,5 @@ }

* @param {object} lastProps
* @param {ReactReconcileTransaction} transaction
*/
_updateDOMProperties: function(lastProps) {
_updateDOMProperties: function(lastProps, transaction) {
var nextProps = this.props;

@@ -252,3 +277,3 @@ var propKey;

}
} else if (registrationNames[propKey]) {
} else if (registrationNameModules[propKey]) {
deleteListener(this._rootNodeID, propKey);

@@ -258,3 +283,3 @@ } else if (

DOMProperty.isCustomAttribute(propKey)) {
ReactComponent.DOMIDOperations.deletePropertyByID(
ReactComponent.BackendIDOperations.deletePropertyByID(
this._rootNodeID,

@@ -296,8 +321,8 @@ propKey

}
} else if (registrationNames[propKey]) {
putListener(this._rootNodeID, propKey, nextProp);
} else if (registrationNameModules[propKey]) {
putListener(this._rootNodeID, propKey, nextProp, transaction);
} else if (
DOMProperty.isStandardName[propKey] ||
DOMProperty.isCustomAttribute(propKey)) {
ReactComponent.DOMIDOperations.updatePropertyByID(
ReactComponent.BackendIDOperations.updatePropertyByID(
this._rootNodeID,

@@ -310,3 +335,3 @@ propKey,

if (styleUpdates) {
ReactComponent.DOMIDOperations.updateStylesByID(
ReactComponent.BackendIDOperations.updateStylesByID(
this._rootNodeID,

@@ -360,3 +385,3 @@ styleUpdates

if (lastHtml !== nextHtml) {
ReactComponent.DOMIDOperations.updateInnerHTMLByID(
ReactComponent.BackendIDOperations.updateInnerHTMLByID(
this._rootNodeID,

@@ -378,5 +403,5 @@ nextHtml

unmountComponent: function() {
this.unmountChildren();
ReactEventEmitter.deleteAllListeners(this._rootNodeID);
ReactComponent.Mixin.unmountComponent.call(this);
this.unmountChildren();
}

@@ -383,0 +408,0 @@

@@ -36,2 +36,4 @@ /**

var ReactDOMForm = ReactCompositeComponent.createClass({
displayName: 'ReactDOMForm',
render: function() {

@@ -44,7 +46,12 @@ // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,

componentDidMount: function(node) {
componentDidMount: function() {
ReactEventEmitter.trapBubbledEvent(
EventConstants.topLevelTypes.topReset,
'reset',
this.getDOMNode()
);
ReactEventEmitter.trapBubbledEvent(
EventConstants.topLevelTypes.topSubmit,
'submit',
node
this.getDOMNode()
);

@@ -51,0 +58,0 @@ }

@@ -28,4 +28,4 @@ /**

var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");
var getTextContentAccessor = require("./getTextContentAccessor");
var invariant = require("./invariant");

@@ -45,15 +45,7 @@

/**
* The DOM property to use when setting text content.
*
* @type {string}
* @private
*/
var textContentAccessor = getTextContentAccessor() || 'NA';
var useWhitespaceWorkaround;
var LEADING_SPACE = /^ /;
/**
* Operations used to process updates to DOM nodes. This is made injectable via
* `ReactComponent.DOMIDOperations`.
* `ReactComponent.BackendIDOperations`.
*/

@@ -71,19 +63,23 @@ var ReactDOMIDOperations = {

*/
updatePropertyByID: function(id, name, value) {
var node = ReactMount.getNode(id);
("production" !== process.env.NODE_ENV ? invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
updatePropertyByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updatePropertyByID',
function(id, name, value) {
var node = ReactMount.getNode(id);
("production" !== process.env.NODE_ENV ? invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertantly setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (value != null) {
DOMPropertyOperations.setValueForProperty(node, name, value);
} else {
DOMPropertyOperations.deleteValueForProperty(node, name);
// If we're updating to null or undefined, we should remove the property
// from the DOM node instead of inadvertantly setting to a string. This
// brings us in line with the same behavior we have on initial render.
if (value != null) {
DOMPropertyOperations.setValueForProperty(node, name, value);
} else {
DOMPropertyOperations.deleteValueForProperty(node, name);
}
}
},
),

@@ -98,11 +94,15 @@ /**

*/
deletePropertyByID: function(id, name, value) {
var node = ReactMount.getNode(id);
("production" !== process.env.NODE_ENV ? invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
DOMPropertyOperations.deleteValueForProperty(node, name, value);
},
deletePropertyByID: ReactPerf.measure(
'ReactDOMIDOperations',
'deletePropertyByID',
function(id, name, value) {
var node = ReactMount.getNode(id);
("production" !== process.env.NODE_ENV ? invariant(
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
'updatePropertyByID(...): %s',
INVALID_PROPERTY_ERRORS[name]
) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
DOMPropertyOperations.deleteValueForProperty(node, name, value);
}
),

@@ -117,6 +117,10 @@ /**

*/
updateStylesByID: function(id, styles) {
var node = ReactMount.getNode(id);
CSSPropertyOperations.setValueForStyles(node, styles);
},
updateStylesByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateStylesByID',
function(id, styles) {
var node = ReactMount.getNode(id);
CSSPropertyOperations.setValueForStyles(node, styles);
}
),

@@ -130,9 +134,39 @@ /**

*/
updateInnerHTMLByID: function(id, html) {
var node = ReactMount.getNode(id);
// HACK: IE8- normalize whitespace in innerHTML, removing leading spaces.
// @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
node.innerHTML = html.replace(LEADING_SPACE, '&nbsp;');
},
updateInnerHTMLByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateInnerHTMLByID',
function(id, html) {
var node = ReactMount.getNode(id);
// IE8: When updating a just created node with innerHTML only leading
// whitespace is removed. When updating an existing node with innerHTML
// whitespace in root TextNodes is also collapsed.
// @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
if (useWhitespaceWorkaround === undefined) {
// Feature detection; only IE8 is known to behave improperly like this.
var temp = document.createElement('div');
temp.innerHTML = ' ';
useWhitespaceWorkaround = temp.innerHTML === '';
}
if (useWhitespaceWorkaround) {
// Magic theory: IE8 supposedly differentiates between added and updated
// nodes when processing innerHTML, innerHTML on updated nodes suffers
// from worse whitespace behavior. Re-adding a node like this triggers
// the initial and more favorable whitespace behavior.
node.parentNode.replaceChild(node, node);
}
if (useWhitespaceWorkaround && html.match(/^[ \r\n\t\f]/)) {
// Recover leading whitespace by temporarily prepending any character.
// \uFEFF has the potential advantage of being zero-width/invisible.
node.innerHTML = '\uFEFF' + html;
node.firstChild.deleteData(0, 1);
} else {
node.innerHTML = html;
}
}
),
/**

@@ -145,6 +179,10 @@ * Updates a DOM node's text content set by `props.content`.

*/
updateTextContentByID: function(id, content) {
var node = ReactMount.getNode(id);
node[textContentAccessor] = content;
},
updateTextContentByID: ReactPerf.measure(
'ReactDOMIDOperations',
'updateTextContentByID',
function(id, content) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.updateTextContent(node, content);
}
),

@@ -159,6 +197,10 @@ /**

*/
dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
},
dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
'ReactDOMIDOperations',
'dangerouslyReplaceNodeWithMarkupByID',
function(id, markup) {
var node = ReactMount.getNode(id);
DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
}
),

@@ -172,11 +214,14 @@ /**

*/
dangerouslyProcessChildrenUpdates: function(updates, markup) {
for (var i = 0; i < updates.length; i++) {
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
'ReactDOMIDOperations',
'dangerouslyProcessChildrenUpdates',
function(updates, markup) {
for (var i = 0; i < updates.length; i++) {
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
}
DOMChildrenOperations.processUpdates(updates, markup);
}
DOMChildrenOperations.processUpdates(updates, markup);
}
)
};
module.exports = ReactDOMIDOperations;

@@ -21,4 +21,5 @@ /**

var AutoFocusMixin = require("./AutoFocusMixin");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var LinkedValueMixin = require("./LinkedValueMixin");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactCompositeComponent = require("./ReactCompositeComponent");

@@ -53,4 +54,6 @@ var ReactDOM = require("./ReactDOM");

var ReactDOMInput = ReactCompositeComponent.createClass({
mixins: [LinkedValueMixin],
displayName: 'ReactDOMInput',
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
getInitialState: function() {

@@ -75,8 +78,9 @@ var defaultValue = this.props.defaultValue;

props.defaultValue = null;
props.checked =
this.props.checked != null ? this.props.checked : this.state.checked;
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
props.value = value != null ? value : this.state.value;
var checked = LinkedValueUtils.getChecked(this);
props.checked = checked != null ? checked : this.state.checked;
props.onChange = this._handleChange;

@@ -87,4 +91,4 @@

componentDidMount: function(rootNode) {
var id = ReactMount.getID(rootNode);
componentDidMount: function() {
var id = ReactMount.getID(this.getDOMNode());
instancesByReactID[id] = this;

@@ -99,3 +103,4 @@ },

componentDidUpdate: function(prevProps, prevState, rootNode) {
componentDidUpdate: function(prevProps, prevState, prevContext) {
var rootNode = this.getDOMNode();
if (this.props.checked != null) {

@@ -109,3 +114,3 @@ DOMPropertyOperations.setValueForProperty(

var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
if (value != null) {

@@ -120,6 +125,6 @@ // Cast `value` to a string to ensure the value is set correctly. While

var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;

@@ -135,2 +140,8 @@ }

var rootNode = this.getDOMNode();
var queryRoot = rootNode;
while (queryRoot.parentNode) {
queryRoot = queryRoot.parentNode;
}
// If `rootNode.form` was non-null, then we could try `form.elements`,

@@ -141,8 +152,9 @@ // but that sometimes behaves strangely in IE8. We could also try using

// the input might not even be in a form, let's just use the global
// `getElementsByName` to ensure we don't miss anything.
var group = document.getElementsByName(name);
// `querySelectorAll` to ensure we don't miss anything.
var group = queryRoot.querySelectorAll(
'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
for (var i = 0, groupLen = group.length; i < groupLen; i++) {
var otherNode = group[i];
if (otherNode === rootNode ||
otherNode.nodeName !== 'INPUT' || otherNode.type !== 'radio' ||
otherNode.form !== rootNode.form) {

@@ -149,0 +161,0 @@ continue;

@@ -31,2 +31,3 @@ /**

var ReactDOMOption = ReactCompositeComponent.createClass({
displayName: 'ReactDOMOption',

@@ -33,0 +34,0 @@ componentWillMount: function() {

@@ -21,3 +21,4 @@ /**

var LinkedValueMixin = require("./LinkedValueMixin");
var AutoFocusMixin = require("./AutoFocusMixin");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactCompositeComponent = require("./ReactCompositeComponent");

@@ -59,16 +60,25 @@ var ReactDOM = require("./ReactDOM");

* If `value` is supplied, updates <option> elements on mount and update.
* @param {ReactComponent} component Instance of ReactDOMSelect
* @param {?*} propValue For uncontrolled components, null/undefined. For
* controlled components, a string (or with `multiple`, a list of strings).
* @private
*/
function updateOptions() {
/*jshint validthis:true */
var propValue = this.getValue();
var value = propValue != null ? propValue : this.state.value;
var options = this.getDOMNode().options;
var selectedValue = '' + value;
function updateOptions(component, propValue) {
var multiple = component.props.multiple;
var value = propValue != null ? propValue : component.state.value;
var options = component.getDOMNode().options;
var selectedValue, i, l;
if (multiple) {
selectedValue = {};
for (i = 0, l = value.length; i < l; ++i) {
selectedValue['' + value[i]] = true;
}
} else {
selectedValue = '' + value;
}
for (i = 0, l = options.length; i < l; i++) {
var selected = multiple ?
selectedValue.hasOwnProperty(options[i].value) :
options[i].value === selectedValue;
for (var i = 0, l = options.length; i < l; i++) {
var selected = this.props.multiple ?
selectedValue.indexOf(options[i].value) >= 0 :
selected = options[i].value === selectedValue;
if (selected !== options[i].selected) {

@@ -96,4 +106,6 @@ options[i].selected = selected;

var ReactDOMSelect = ReactCompositeComponent.createClass({
mixins: [LinkedValueMixin],
displayName: 'ReactDOMSelect',
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
propTypes: {

@@ -131,12 +143,19 @@ defaultValue: selectValueType,

componentDidMount: updateOptions,
componentDidMount: function() {
updateOptions(this, LinkedValueUtils.getValue(this));
},
componentDidUpdate: updateOptions,
componentDidUpdate: function() {
var value = LinkedValueUtils.getValue(this);
if (value != null) {
updateOptions(this, value);
}
},
_handleChange: function(event) {
var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;

@@ -143,0 +162,0 @@ }

@@ -21,4 +21,5 @@ /**

var AutoFocusMixin = require("./AutoFocusMixin");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var LinkedValueMixin = require("./LinkedValueMixin");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactCompositeComponent = require("./ReactCompositeComponent");

@@ -49,4 +50,6 @@ var ReactDOM = require("./ReactDOM");

var ReactDOMTextarea = ReactCompositeComponent.createClass({
mixins: [LinkedValueMixin],
displayName: 'ReactDOMTextarea',
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
getInitialState: function() {

@@ -80,3 +83,3 @@ var defaultValue = this.props.defaultValue;

}
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);
return {

@@ -100,3 +103,3 @@ // We save the initial value so that `ReactDOMComponent` doesn't update

var props = merge(this.props);
var value = this.getValue();
var value = LinkedValueUtils.getValue(this);

@@ -117,5 +120,6 @@ ("production" !== process.env.NODE_ENV ? invariant(

componentDidUpdate: function(prevProps, prevState, rootNode) {
var value = this.getValue();
componentDidUpdate: function(prevProps, prevState, prevContext) {
var value = LinkedValueUtils.getValue(this);
if (value != null) {
var rootNode = this.getDOMNode();
// Cast `value` to a string to ensure the value is set correctly. While

@@ -129,6 +133,6 @@ // browsers typically do this as necessary, jsdom doesn't.

var returnValue;
var onChange = this.getOnChange();
var onChange = LinkedValueUtils.getOnChange(this);
if (onChange) {
this._isChanging = true;
returnValue = onChange(event);
returnValue = onChange.call(this, event);
this._isChanging = false;

@@ -135,0 +139,0 @@ }

@@ -20,7 +20,9 @@ /**

"use strict";
var ReactErrorUtils = {
/**
* Creates a guarded version of a function. This is supposed to make debugging
* of event handlers easier. This implementation provides only basic error
* logging and re-throws the error.
* of event handlers easier. To aid debugging with the browser's debugger,
* this currently simply returns the original function.
*

@@ -32,14 +34,3 @@ * @param {function} func Function to be executed

guard: function(func, name) {
if ("production" !== process.env.NODE_ENV) {
return function guarded() {
try {
return func.apply(this, arguments);
} catch(ex) {
console.error(name + ': ' + ex.message);
throw ex;
}
};
} else {
return func;
}
return func;
}

@@ -46,0 +37,0 @@ };

@@ -25,2 +25,3 @@ /**

var EventPluginHub = require("./EventPluginHub");
var EventPluginRegistry = require("./EventPluginRegistry");
var ExecutionEnvironment = require("./ExecutionEnvironment");

@@ -64,12 +65,12 @@ var ReactEventEmitterMixin = require("./ReactEventEmitterMixin");

* | | . | | +-----------+ | utilities |
* | +-----------.---------+ | +------------+
* | | | . +----|---------+
* +-----|------+ . | ^ +-----------+
* | . | | |Enter/Leave|
* + . | +-------+|Plugin |
* +-------------+ . v +-----------+
* | application | . +----------+
* |-------------| . | callback |
* | | . | registry |
* | | . +----------+
* | +-----------.--->| | +------------+
* | | | . +--------------+
* +-----|------+ . ^ +-----------+
* | . | |Enter/Leave|
* + . +-------+|Plugin |
* +-------------+ . +-----------+
* | application | .
* |-------------| .
* | | .
* | | .
* +-------------+ .

@@ -80,3 +81,62 @@ * .

var alreadyListeningTo = {};
var isMonitoringScrollValue = false;
var reactTopListenersCounter = 0;
// For events like 'submit' which don't consistently bubble (which we trap at a
// lower node than `document`), binding at `document` would cause duplicate
// events so we don't include them here
var topEventMapping = {
topBlur: 'blur',
topChange: 'change',
topClick: 'click',
topCompositionEnd: 'compositionend',
topCompositionStart: 'compositionstart',
topCompositionUpdate: 'compositionupdate',
topContextMenu: 'contextmenu',
topCopy: 'copy',
topCut: 'cut',
topDoubleClick: 'dblclick',
topDrag: 'drag',
topDragEnd: 'dragend',
topDragEnter: 'dragenter',
topDragExit: 'dragexit',
topDragLeave: 'dragleave',
topDragOver: 'dragover',
topDragStart: 'dragstart',
topDrop: 'drop',
topFocus: 'focus',
topInput: 'input',
topKeyDown: 'keydown',
topKeyPress: 'keypress',
topKeyUp: 'keyup',
topMouseDown: 'mousedown',
topMouseMove: 'mousemove',
topMouseOut: 'mouseout',
topMouseOver: 'mouseover',
topMouseUp: 'mouseup',
topPaste: 'paste',
topScroll: 'scroll',
topSelectionChange: 'selectionchange',
topTouchCancel: 'touchcancel',
topTouchEnd: 'touchend',
topTouchMove: 'touchmove',
topTouchStart: 'touchstart',
topWheel: 'wheel'
};
/**
* To ensure no conflicts with other potential React instances on the page
*/
var topListenersIDKey = "_reactListenersID" + String(Math.random()).slice(2);
function getListeningForDocument(mountAt) {
if (mountAt[topListenersIDKey] == null) {
mountAt[topListenersIDKey] = reactTopListenersCounter++;
alreadyListeningTo[mountAt[topListenersIDKey]] = {};
}
return alreadyListeningTo[mountAt[topListenersIDKey]];
}
/**
* Traps top-level events by using event bubbling.

@@ -118,17 +178,2 @@ *

/**
* Listens to window scroll and resize events. We cache scroll values so that
* application code can access them without triggering reflows.
*
* NOTE: Scroll events do not bubble.
*
* @private
* @see http://www.quirksmode.org/dom/events/scroll.html
*/
function registerScrollValueMonitoring() {
var refresh = ViewportMetrics.refreshScrollValues;
EventListener.listen(window, 'scroll', refresh);
EventListener.listen(window, 'resize', refresh);
}
/**
* `ReactEventEmitter` is used to attach top-level event listeners. For example:

@@ -150,33 +195,9 @@ *

/**
* Ensures that top-level event delegation listeners are installed.
*
* 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 {DOMDocument} contentDocument DOM document to listen on
*/
ensureListening: function(touchNotMouse, contentDocument) {
("production" !== process.env.NODE_ENV ? invariant(
ExecutionEnvironment.canUseDOM,
'ensureListening(...): Cannot toggle event listening in a Worker ' +
'thread. This is likely a bug in the framework. Please report ' +
'immediately.'
) : invariant(ExecutionEnvironment.canUseDOM));
("production" !== process.env.NODE_ENV ? invariant(
ReactEventEmitter.TopLevelCallbackCreator,
'ensureListening(...): Cannot be called without a top level callback ' +
'creator being injected.'
) : invariant(ReactEventEmitter.TopLevelCallbackCreator));
// Call out to base implementation.
ReactEventEmitterMixin.ensureListening.call(
ReactEventEmitter,
{
touchNotMouse: touchNotMouse,
contentDocument: contentDocument
}
);
injection: {
/**
* @param {function} TopLevelCallbackCreator
*/
injectTopLevelCallbackCreator: function(TopLevelCallbackCreator) {
ReactEventEmitter.TopLevelCallbackCreator = TopLevelCallbackCreator;
}
},

@@ -228,104 +249,80 @@

*
* @param {boolean} touchNotMouse Listen to touch events instead of mouse.
* @param {string} registrationName Name of listener (e.g. `onClick`).
* @param {DOMDocument} contentDocument Document which owns the container
* @private
* @see http://www.quirksmode.org/dom/events/keys.html.
*/
listenAtTopLevel: function(touchNotMouse, contentDocument) {
("production" !== process.env.NODE_ENV ? invariant(
!contentDocument._isListening,
'listenAtTopLevel(...): Cannot setup top-level listener more than once.'
) : invariant(!contentDocument._isListening));
var topLevelTypes = EventConstants.topLevelTypes;
listenTo: function(registrationName, contentDocument) {
var mountAt = contentDocument;
var isListening = getListeningForDocument(mountAt);
var dependencies = EventPluginRegistry.
registrationNameDependencies[registrationName];
registerScrollValueMonitoring();
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.topContextMenu, 'contextmenu', 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.topInput, 'input', mountAt);
trapBubbledEvent(topLevelTypes.topChange, 'change', mountAt);
trapBubbledEvent(
topLevelTypes.topSelectionChange,
'selectionchange',
mountAt
);
var topLevelTypes = EventConstants.topLevelTypes;
for (var i = 0, l = dependencies.length; i < l; i++) {
var dependency = dependencies[i];
if (!isListening[dependency]) {
var topLevelType = topLevelTypes[dependency];
trapBubbledEvent(
topLevelTypes.topCompositionEnd,
'compositionend',
mountAt
);
trapBubbledEvent(
topLevelTypes.topCompositionStart,
'compositionstart',
mountAt
);
trapBubbledEvent(
topLevelTypes.topCompositionUpdate,
'compositionupdate',
mountAt
);
if (topLevelType === topLevelTypes.topWheel) {
if (isEventSupported('wheel')) {
trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt);
} else if (isEventSupported('mousewheel')) {
trapBubbledEvent(topLevelTypes.topWheel, 'mousewheel', mountAt);
} else {
// Firefox needs to capture a different mouse scroll event.
// @see http://www.quirksmode.org/dom/events/tests/scroll.html
trapBubbledEvent(
topLevelTypes.topWheel,
'DOMMouseScroll',
mountAt);
}
} else if (topLevelType === topLevelTypes.topScroll) {
if (isEventSupported('drag')) {
trapBubbledEvent(topLevelTypes.topDrag, 'drag', mountAt);
trapBubbledEvent(topLevelTypes.topDragEnd, 'dragend', mountAt);
trapBubbledEvent(topLevelTypes.topDragEnter, 'dragenter', mountAt);
trapBubbledEvent(topLevelTypes.topDragExit, 'dragexit', mountAt);
trapBubbledEvent(topLevelTypes.topDragLeave, 'dragleave', mountAt);
trapBubbledEvent(topLevelTypes.topDragOver, 'dragover', mountAt);
trapBubbledEvent(topLevelTypes.topDragStart, 'dragstart', mountAt);
trapBubbledEvent(topLevelTypes.topDrop, 'drop', mountAt);
}
if (isEventSupported('scroll', true)) {
trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt);
} else {
trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window);
}
} else if (topLevelType === topLevelTypes.topFocus ||
topLevelType === topLevelTypes.topBlur) {
if (isEventSupported('wheel')) {
trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt);
} else if (isEventSupported('mousewheel')) {
trapBubbledEvent(topLevelTypes.topWheel, 'mousewheel', mountAt);
} else {
// Firefox needs to capture a different mouse scroll event.
// @see http://www.quirksmode.org/dom/events/tests/scroll.html
trapBubbledEvent(topLevelTypes.topWheel, 'DOMMouseScroll', mountAt);
}
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);
}
// IE<9 does not support capturing so just trap the bubbled event there.
if (isEventSupported('scroll', true)) {
trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt);
} else {
trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window);
}
// to make sure blur and focus event listeners are only attached once
isListening[topLevelTypes.topBlur] = true;
isListening[topLevelTypes.topFocus] = true;
} else if (topEventMapping[dependency]) {
trapBubbledEvent(topLevelType, topEventMapping[dependency], mountAt);
}
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);
isListening[dependency] = true;
}
}
},
if (isEventSupported('copy')) {
trapBubbledEvent(topLevelTypes.topCopy, 'copy', mountAt);
trapBubbledEvent(topLevelTypes.topCut, 'cut', mountAt);
trapBubbledEvent(topLevelTypes.topPaste, 'paste', mountAt);
/**
* Listens to window scroll and resize events. We cache scroll values so that
* application code can access them without triggering reflows.
*
* NOTE: Scroll events do not bubble.
*
* @see http://www.quirksmode.org/dom/events/scroll.html
*/
ensureScrollValueMonitoring: function(){
if (!isMonitoringScrollValue) {
var refresh = ViewportMetrics.refreshScrollValues;
EventListener.listen(window, 'scroll', refresh);
EventListener.listen(window, 'resize', refresh);
isMonitoringScrollValue = true;
}
},
registrationNames: EventPluginHub.registrationNames,
registrationNameModules: EventPluginHub.registrationNameModules,

@@ -346,3 +343,2 @@ putListener: EventPluginHub.putListener,

module.exports = ReactEventEmitter;

@@ -30,36 +30,4 @@ /**

var ReactEventEmitterMixin = {
/**
* Whether or not `ensureListening` has been invoked.
* @type {boolean}
* @private
*/
_isListening: false,
/**
* Function, must be implemented. Listens to events on the top level of the
* application.
*
* @abstract
*
* listenAtTopLevel: null,
*/
/**
* Ensures that top-level event delegation listeners are installed.
*
* 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 {*} config Configuration passed through to `listenAtTopLevel`.
*/
ensureListening: function(config) {
if (!config.contentDocument._reactIsListening) {
this.listenAtTopLevel(config.touchNotMouse, config.contentDocument);
config.contentDocument._reactIsListening = true;
}
},
/**
* Streams a fired top-level event to `EventPluginHub` where plugins have the

@@ -66,0 +34,0 @@ * opportunity to create `ReactEvent`s to be dispatched.

@@ -23,2 +23,3 @@ /**

var ReactEventEmitter = require("./ReactEventEmitter");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactMount = require("./ReactMount");

@@ -35,2 +36,20 @@

/**
* Finds the parent React component of `node`.
*
* @param {*} node
* @return {?DOMEventTarget} Parent container, or `null` if the specified node
* is not nested.
*/
function findParent(node) {
// TODO: It may be a good idea to cache this to prevent unnecessary DOM
// traversal, but caching is difficult to do correctly without using a
// mutation observer to listen for all DOM changes.
var nodeID = ReactMount.getID(node);
var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
var container = ReactMount.findReactContainerForID(rootID);
var parent = ReactMount.getFirstReactDOM(container);
return parent;
}
/**
* Top-level callback creator used to implement event handling using delegation.

@@ -71,17 +90,18 @@ * This is used via dependency injection.

}
// TODO: Remove when synthetic events are ready, this is for IE<9.
if (nativeEvent.srcElement &&
nativeEvent.srcElement !== nativeEvent.target) {
nativeEvent.target = nativeEvent.srcElement;
}
var topLevelTarget = ReactMount.getFirstReactDOM(
getEventTarget(nativeEvent)
) || window;
var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
ReactEventEmitter.handleTopLevel(
topLevelType,
topLevelTarget,
topLevelTargetID,
nativeEvent
);
// Loop through the hierarchy, in case there's any nested components.
while (topLevelTarget) {
var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
ReactEventEmitter.handleTopLevel(
topLevelType,
topLevelTarget,
topLevelTargetID,
nativeEvent
);
topLevelTarget = findParent(topLevelTarget);
}
};

@@ -88,0 +108,0 @@ }

@@ -22,2 +22,4 @@ /**

var ReactRootIndex = require("./ReactRootIndex");
var invariant = require("./invariant");

@@ -34,11 +36,2 @@

/**
* Size of the reactRoot ID space. We generate random numbers for React root
* IDs and if there's a collision the events and DOM update system will
* get confused. If we assume 100 React components per page, and a user
* loads 1 page per minute 24/7 for 50 years, with a mount point space of
* 9,999,999 the likelihood of never having a collision is 99.997%.
*/
var GLOBAL_MOUNT_POINT_MAX = 9999999;
/**
* Creates a DOM ID prefix to use when mounting React components.

@@ -51,3 +44,3 @@ *

function getReactRootIDString(index) {
return SEPARATOR + 'r[' + index.toString(36) + ']';
return SEPARATOR + index.toString(36);
}

@@ -181,3 +174,4 @@

* 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.
* not be the same, and there must exist a parent path between them. If the
* callback returns `false`, traversal is stopped.
*

@@ -211,6 +205,7 @@ * @param {?string} start ID at which to start traversal.

for (var id = start; /* until break */; id = traverse(id, stop)) {
var ret;
if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
cb(id, traverseUp, arg);
ret = cb(id, traverseUp, arg);
}
if (id === stop) {
if (ret === false || id === stop) {
// Only break //after// visiting `stop`.

@@ -237,6 +232,8 @@ break;

/**
* Constructs a React root ID
* @return {string} A React root ID.
*/
createReactRootID: function() {
return getReactRootIDString(
Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX)
);
return getReactRootIDString(ReactRootIndex.createReactRootIndex());
},

@@ -253,3 +250,3 @@

createReactID: function(rootID, name) {
return rootID + SEPARATOR + name;
return rootID + name;
},

@@ -266,4 +263,7 @@

getReactRootIDFromNodeID: function(id) {
var regexResult = /\.r\[[^\]]+\]/.exec(id);
return regexResult && regexResult[0];
if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
var index = id.indexOf(SEPARATOR, 1);
return index > -1 ? id.substr(0, index) : id;
}
return null;
},

@@ -313,2 +313,18 @@

/**
* Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
* example, passing `.0.$row-0.1` would result in `cb` getting called
* with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
*
* 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
*/
traverseAncestors: function(targetID, cb, arg) {
traverseParentPath('', targetID, cb, arg, true, false);
},
/**
* Exposed for unit testing.

@@ -315,0 +331,0 @@ * @private

@@ -42,3 +42,3 @@ /**

* We have provided some sugary mixins to make the creation and
* consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin.
* consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
*/

@@ -45,0 +45,0 @@

@@ -21,13 +21,15 @@ /**

var DOMProperty = require("./DOMProperty");
var ReactEventEmitter = require("./ReactEventEmitter");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactPerf = require("./ReactPerf");
var $ = require("./$");
var containsNode = require("./containsNode");
var getReactRootElementInContainer = require("./getReactRootElementInContainer");
var invariant = require("./invariant");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
var SEPARATOR = ReactInstanceHandles.SEPARATOR;
var ATTR_NAME = 'data-reactid';
var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
var nodeCache = {};

@@ -49,2 +51,5 @@

// Used to store breadth-first search state in findComponentRoot.
var findComponentRootReusableArray = [];
/**

@@ -163,3 +168,30 @@ * @param {DOMElement} container DOM element that may contain a React component.

var deepestNodeSoFar = null;
function findDeepestCachedAncestorImpl(ancestorID) {
var ancestor = nodeCache[ancestorID];
if (ancestor && isValid(ancestor, ancestorID)) {
deepestNodeSoFar = ancestor;
} else {
// This node isn't populated in the cache, so presumably none of its
// descendants are. Break out of the loop.
return false;
}
}
/**
* Return the deepest cached node whose ID is a prefix of `targetID`.
*/
function findDeepestCachedAncestor(targetID) {
deepestNodeSoFar = null;
ReactInstanceHandles.traverseAncestors(
targetID,
findDeepestCachedAncestorImpl
);
var foundNode = deepestNodeSoFar;
deepestNodeSoFar = null;
return foundNode;
}
/**
* Mounting is the process of initializing a React component by creatings its

@@ -169,6 +201,9 @@ * representative DOM elements and inserting them into a supplied `container`.

*
* ReactMount.renderComponent(component, $('container'));
* ReactMount.renderComponent(
* component,
* document.getElementById('container')
* );
*
* <div id="container"> <-- Supplied `container`.
* <div data-reactid=".r[3]"> <-- Rendered reactRoot of React
* <div data-reactid=".3"> <-- Rendered reactRoot of React
* // ... component.

@@ -181,7 +216,2 @@ * </div>

var ReactMount = {
/**
* Safety guard to prevent accidentally rendering over the entire HTML tree.
*/
allowFullPageRender: false,
/** Time spent generating markup. */

@@ -212,26 +242,2 @@ totalInstantiationTime: 0,

/**
* Ensures that 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 {DOMElement} container container we're rendering into
*
* @private
*/
prepareEnvironmentForDOM: function(container) {
("production" !== process.env.NODE_ENV ? invariant(
container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
),
'prepareEnvironmentForDOM(...): Target container is not a DOM element.'
) : invariant(container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
)));
var doc = container.nodeType === ELEMENT_NODE_TYPE ?
container.ownerDocument :
container;
ReactEventEmitter.ensureListening(ReactMount.useTouchEvents, doc);
},
/**
* Take a component that's already mounted into the DOM and replace its props

@@ -263,3 +269,4 @@ * @param {ReactComponent} prevComponent component instance already in the DOM

/**
* Register a component into the instance map and start the events system.
* Register a component into the instance map and starts scroll value
* monitoring
* @param {ReactComponent} nextComponent component instance to render

@@ -270,4 +277,15 @@ * @param {DOMElement} container container to render into

_registerComponent: function(nextComponent, container) {
ReactMount.prepareEnvironmentForDOM(container);
("production" !== process.env.NODE_ENV ? invariant(
container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
),
'_registerComponent(...): Target container is not a DOM element.'
) : invariant(container && (
container.nodeType === ELEMENT_NODE_TYPE ||
container.nodeType === DOC_NODE_TYPE
)));
ReactEventEmitter.ensureScrollValueMonitoring();
var reactRootID = ReactMount.registerContainer(container);

@@ -285,22 +303,26 @@ instancesByReactRootID[reactRootID] = nextComponent;

*/
_renderNewRootComponent: function(
nextComponent,
container,
shouldReuseMarkup) {
var reactRootID = ReactMount._registerComponent(nextComponent, container);
nextComponent.mountComponentIntoNode(
reactRootID,
container,
shouldReuseMarkup
);
_renderNewRootComponent: ReactPerf.measure(
'ReactMount',
'_renderNewRootComponent',
function(
nextComponent,
container,
shouldReuseMarkup) {
var reactRootID = ReactMount._registerComponent(nextComponent, container);
nextComponent.mountComponentIntoNode(
reactRootID,
container,
shouldReuseMarkup
);
if ("production" !== process.env.NODE_ENV) {
// Record the root element in case it later gets transplanted.
rootElementsByReactRootID[reactRootID] =
getReactRootElementInContainer(container);
if ("production" !== process.env.NODE_ENV) {
// Record the root element in case it later gets transplanted.
rootElementsByReactRootID[reactRootID] =
getReactRootElementInContainer(container);
}
return nextComponent;
}
),
return nextComponent;
},
/**

@@ -319,8 +341,8 @@ * Renders a React component into the DOM in the supplied `container`.

renderComponent: function(nextComponent, container, callback) {
var registeredComponent = instancesByReactRootID[getReactRootID(container)];
var prevComponent = instancesByReactRootID[getReactRootID(container)];
if (registeredComponent) {
if (registeredComponent.constructor === nextComponent.constructor) {
if (prevComponent) {
if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
return ReactMount._updateRootComponent(
registeredComponent,
prevComponent,
nextComponent,

@@ -339,3 +361,3 @@ container,

var shouldReuseMarkup = containerHasReactMarkup && !registeredComponent;
var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;

@@ -347,3 +369,3 @@ var component = ReactMount._renderNewRootComponent(

);
callback && callback();
callback && callback.call(component);
return component;

@@ -375,3 +397,9 @@ },

constructAndRenderComponentByID: function(constructor, props, id) {
return ReactMount.constructAndRenderComponent(constructor, props, $(id));
var domNode = document.getElementById(id);
("production" !== process.env.NODE_ENV ? invariant(
domNode,
'Tried to get element with id of "%s" but it is not present on the page.',
id
) : invariant(domNode));
return ReactMount.constructAndRenderComponent(constructor, props, domNode);
},

@@ -381,3 +409,3 @@

* Registers a container node into which React components will be rendered.
* This also creates the "reatRoot" ID that will be assigned to the element
* This also creates the "reactRoot" ID that will be assigned to the element
* rendered within.

@@ -425,16 +453,2 @@ *

/**
* @deprecated
*/
unmountAndReleaseReactRootNode: function() {
if ("production" !== process.env.NODE_ENV) {
console.warn(
'unmountAndReleaseReactRootNode() has been renamed to ' +
'unmountComponentAtNode() and will be removed in the next ' +
'version of React.'
);
}
return ReactMount.unmountComponentAtNode.apply(this, arguments);
},
/**
* Unmounts a component and removes it from the DOM.

@@ -551,22 +565,35 @@ *

/**
* Finds a node with the supplied `id` inside of the supplied `ancestorNode`.
* Exploits the ID naming scheme to perform the search quickly.
* Finds a node with the supplied `targetID` inside of the supplied
* `ancestorNode`. Exploits the ID naming scheme to perform the search
* quickly.
*
* @param {DOMEventTarget} ancestorNode Search from this root.
* @pararm {string} id ID of the DOM representation of the component.
* @return {DOMEventTarget} DOM node with the supplied `id`.
* @pararm {string} targetID ID of the DOM representation of the component.
* @return {DOMEventTarget} DOM node with the supplied `targetID`.
* @internal
*/
findComponentRoot: function(ancestorNode, id) {
var firstChildren = [ancestorNode.firstChild];
findComponentRoot: function(ancestorNode, targetID) {
var firstChildren = findComponentRootReusableArray;
var childIndex = 0;
var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
firstChildren[0] = deepestAncestor.firstChild;
firstChildren.length = 1;
while (childIndex < firstChildren.length) {
var child = firstChildren[childIndex++];
var targetChild;
while (child) {
var childID = ReactMount.getID(child);
if (childID) {
if (id === childID) {
return child;
} else if (ReactInstanceHandles.isAncestorIDOf(childID, id)) {
// Even if we find the node we're looking for, we finish looping
// through its siblings to ensure they're cached so that we don't have
// to revisit this node again. Otherwise, we make n^2 calls to getID
// when visiting the many children of a single node in order.
if (targetID === childID) {
targetChild = child;
} else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
// If we find a child whose ID is an ancestor of the given ID,

@@ -578,9 +605,4 @@ // then we can be sure that we only want to search the subtree

firstChildren.push(child.firstChild);
break;
} else {
// TODO This should not be necessary if the ID hierarchy is
// correct, but is occasionally necessary if the DOM has been
// modified in unexpected ways.
firstChildren.push(child.firstChild);
}
} else {

@@ -594,18 +616,24 @@ // If this child had no ID, then there's a chance that it was

}
child = child.nextSibling;
}
if (targetChild) {
// Emptying firstChildren/findComponentRootReusableArray is
// not necessary for correctness, but it helps the GC reclaim
// any nodes that were left at the end of the search.
firstChildren.length = 0;
return targetChild;
}
}
if ("production" !== process.env.NODE_ENV) {
console.error(
'Error while invoking `findComponentRoot` with the following ' +
'ancestor node:',
ancestorNode
);
}
firstChildren.length = 0;
("production" !== process.env.NODE_ENV ? invariant(
false,
'findComponentRoot(..., %s): Unable to find element. This probably ' +
'means the DOM was unexpectedly mutated (e.g. by the browser).',
id,
'means the DOM was unexpectedly mutated (e.g., by the browser). ' +
'Try inspecting the child nodes of the element with React ID `%s`.',
targetID,
ReactMount.getID(ancestorNode)

@@ -620,4 +648,2 @@ ) : invariant(false));

ATTR_NAME: ATTR_NAME,
getReactRootID: getReactRootID,

@@ -631,7 +657,5 @@

purgeID: purgeID,
injection: {}
purgeID: purgeID
};
module.exports = ReactMount;

@@ -69,3 +69,3 @@ /**

var callback = queue[i].callback;
callback.call(component, component.getDOMNode());
callback.call(component);
}

@@ -72,0 +72,0 @@ queue.length = 0;

@@ -26,17 +26,5 @@ /**

var flattenChildren = require("./flattenChildren");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
/**
* Given a `curChild` and `newChild`, determines if `curChild` should be
* updated as opposed to being destroyed or replaced.
*
* @param {?ReactComponent} curChild
* @param {?ReactComponent} newChild
* @return {boolean} True if `curChild` should be updated with `newChild`.
* @protected
*/
function shouldUpdateChild(curChild, newChild) {
return curChild && newChild && curChild.constructor === newChild.constructor;
}
/**
* Updating children of a component may trigger recursive updates. The depth is

@@ -157,3 +145,3 @@ * used to batch recursive updates to render markup more efficiently.

if (updateQueue.length) {
ReactComponent.DOMIDOperations.dangerouslyProcessChildrenUpdates(
ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
updateQueue,

@@ -208,5 +196,5 @@ markupQueue

var child = children[name];
if (children.hasOwnProperty(name) && child) {
if (children.hasOwnProperty(name)) {
// Inlined for performance, see `ReactInstanceHandles.createReactID`.
var rootID = this._rootNodeID + '.' + name;
var rootID = this._rootNodeID + name;
var mountImage = child.mountComponent(

@@ -217,3 +205,2 @@ rootID,

);
child._mountImage = mountImage;
child._mountIndex = index;

@@ -235,2 +222,3 @@ mountImages.push(mountImage);

updateDepth++;
var errorThrown = true;
try {

@@ -240,4 +228,3 @@ var prevChildren = this._renderedChildren;

for (var name in prevChildren) {
if (prevChildren.hasOwnProperty(name) &&
prevChildren[name]) {
if (prevChildren.hasOwnProperty(name)) {
this._unmountChildByName(prevChildren[name], name);

@@ -248,9 +235,9 @@ }

this.setTextContent(nextContent);
} catch (error) {
errorThrown = false;
} finally {
updateDepth--;
updateDepth || clearQueue();
throw error;
if (!updateDepth) {
errorThrown ? clearQueue() : processQueue();
}
}
updateDepth--;
updateDepth || processQueue();
},

@@ -267,11 +254,12 @@

updateDepth++;
var errorThrown = true;
try {
this._updateChildren(nextNestedChildren, transaction);
} catch (error) {
errorThrown = false;
} finally {
updateDepth--;
updateDepth || clearQueue();
throw error;
if (!updateDepth) {
errorThrown ? clearQueue() : processQueue();
}
}
updateDepth--;
updateDepth || processQueue();
},

@@ -305,3 +293,3 @@

var nextChild = nextChildren[name];
if (shouldUpdateChild(prevChild, nextChild)) {
if (shouldUpdateReactComponent(prevChild, nextChild)) {
this.moveChild(prevChild, nextIndex, lastIndex);

@@ -317,11 +305,7 @@ lastIndex = Math.max(prevChild._mountIndex, lastIndex);

}
if (nextChild) {
this._mountChildByNameAtIndex(
nextChild, name, nextIndex, transaction
);
}
this._mountChildByNameAtIndex(
nextChild, name, nextIndex, transaction
);
}
if (nextChild) {
nextIndex++;
}
nextIndex++;
}

@@ -331,3 +315,2 @@ // Remove children that are no longer present.

if (prevChildren.hasOwnProperty(name) &&
prevChildren[name] &&
!(nextChildren && nextChildren[name])) {

@@ -349,3 +332,4 @@ this._unmountChildByName(prevChildren[name], name);

var renderedChild = renderedChildren[name];
if (renderedChild && renderedChild.unmountComponent) {
// TODO: When is this not true?
if (renderedChild.unmountComponent) {
renderedChild.unmountComponent();

@@ -378,6 +362,7 @@ }

* @param {ReactComponent} child Component to create.
* @param {string} mountImage Markup to insert.
* @protected
*/
createChild: function(child) {
enqueueMarkup(this._rootNodeID, child._mountImage, child._mountIndex);
createChild: function(child, mountImage) {
enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
},

@@ -418,3 +403,3 @@

// Inlined for performance, see `ReactInstanceHandles.createReactID`.
var rootID = this._rootNodeID + '.' + name;
var rootID = this._rootNodeID + name;
var mountImage = child.mountComponent(

@@ -425,5 +410,4 @@ rootID,

);
child._mountImage = mountImage;
child._mountIndex = index;
this.createChild(child);
this.createChild(child, mountImage);
this._renderedChildren = this._renderedChildren || {};

@@ -443,5 +427,5 @@ this._renderedChildren[name] = child;

_unmountChildByName: function(child, name) {
// TODO: When is this not true?
if (ReactComponent.isValidComponent(child)) {
this.removeChild(child);
child._mountImage = null;
child._mountIndex = null;

@@ -448,0 +432,0 @@ child.unmountComponent();

@@ -19,2 +19,4 @@ /**

"use strict";
var keyMirror = require("./keyMirror");

@@ -21,0 +23,0 @@

@@ -80,3 +80,7 @@ /**

ReactOwner.isValidOwner(owner),
'addComponentAsRefTo(...): Only a ReactOwner can have refs.'
'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
'usually means that you\'re trying to add a ref to a component that ' +
'doesn\'t have an owner (that is, was not created inside of another ' +
'component\'s `render` method). Try rendering this component inside of ' +
'a new top-level component which will hold the ref.'
) : invariant(ReactOwner.isValidOwner(owner)));

@@ -98,3 +102,7 @@ owner.attachRef(ref, component);

ReactOwner.isValidOwner(owner),
'removeComponentAsRefFrom(...): Only a ReactOwner can have refs.'
'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
'usually means that you\'re trying to remove a ref to a component that ' +
'doesn\'t have an owner (that is, was not created inside of another ' +
'component\'s `render` method). Try rendering this component inside of ' +
'a new top-level component which will hold the ref.'
) : invariant(ReactOwner.isValidOwner(owner)));

@@ -101,0 +109,0 @@ // Check that `component` is still the current ref because we do not want to

@@ -22,2 +22,6 @@ /**

/**
* ReactPerf is a general AOP system designed to measure performance. This
* module only has the hooks: see ReactDefaultPerf for the analysis tool.
*/
var ReactPerf = {

@@ -37,3 +41,3 @@ /**

/**
* Use this to wrap methods you want to measure.
* Use this to wrap methods you want to measure. Zero overhead in production.
*

@@ -71,9 +75,2 @@ * @param {string} objName

if ("production" !== process.env.NODE_ENV) {
var ExecutionEnvironment = require("./ExecutionEnvironment");
var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
ReactPerf.enableMeasure = ReactPerf.enableMeasure ||
(/[?&]react_perf\b/).test(url);
}
/**

@@ -80,0 +77,0 @@ * Simply passes through the measured function, without measuring it.

@@ -45,2 +45,4 @@ /**

* Transfer strategies dictate how props are transferred by `transferPropsTo`.
* NOTE: if you add any more exceptions to this list you should be sure to
* update `cloneWithProps()` accordingly.
*/

@@ -57,2 +59,6 @@ var TransferStrategies = {

/**
* Never transfer the `key` prop.
*/
key: emptyFunction,
/**
* Never transfer the `ref` prop.

@@ -78,2 +84,29 @@ */

/**
* Merge two props objects using TransferStrategies.
*
* @param {object} oldProps original props (they take precedence)
* @param {object} newProps new props to merge in
* @return {object} a new object containing both sets of props merged.
*/
mergeProps: function(oldProps, newProps) {
var props = merge(oldProps);
for (var thisKey in newProps) {
if (!newProps.hasOwnProperty(thisKey)) {
continue;
}
var transferStrategy = TransferStrategies[thisKey];
if (transferStrategy) {
transferStrategy(props, thisKey, newProps[thisKey]);
} else if (!props.hasOwnProperty(thisKey)) {
props[thisKey] = newProps[thisKey];
}
}
return props;
},
/**
* @lends {ReactPropTransferer.prototype}

@@ -98,3 +131,3 @@ */

("production" !== process.env.NODE_ENV ? invariant(
component.props.__owner__ === this,
component._owner === this,
'%s: You can\'t call transferPropsTo() on a component that you ' +

@@ -105,22 +138,9 @@ 'don\'t own, %s. This usually means you are calling ' +

component.constructor.displayName
) : invariant(component.props.__owner__ === this));
) : invariant(component._owner === this));
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;
component.props = ReactPropTransferer.mergeProps(
component.props,
this.props
);
return component;

@@ -130,5 +150,4 @@ }

}
};
module.exports = ReactPropTransferer;

@@ -21,4 +21,7 @@ /**

var ReactComponent = require("./ReactComponent");
var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
var warning = require("./warning");
var createObjectFrom = require("./createObjectFrom");
var invariant = require("./invariant");

@@ -58,3 +61,3 @@ /**

* var propValue = props[propName];
* invariant(
* warning(
* propValue == null ||

@@ -83,6 +86,14 @@ * typeof propValue === 'string' ||

shape: createShapeTypeChecker,
oneOf: createEnumTypeChecker,
oneOfType: createUnionTypeChecker,
arrayOf: createArrayOfTypeChecker,
instanceOf: createInstanceTypeChecker
instanceOf: createInstanceTypeChecker,
renderable: createRenderableTypeChecker(),
component: createComponentTypeChecker(),
any: createAnyTypeChecker()
};

@@ -92,16 +103,61 @@

function isRenderable(propValue) {
switch(typeof propValue) {
case 'number':
case 'string':
return true;
case 'object':
if (Array.isArray(propValue)) {
return propValue.every(isRenderable);
}
if (ReactComponent.isValidComponent(propValue)) {
return true;
}
for (var k in propValue) {
if (!isRenderable(propValue[k])) {
return false;
}
}
return true;
default:
return false;
}
}
// Equivalent of typeof but with special handling for arrays
function getPropType(propValue) {
var propType = typeof propValue;
if (propType === 'object' && Array.isArray(propValue)) {
return 'array';
}
return propType;
}
function createAnyTypeChecker() {
function validateAnyType(
shouldWarn, propValue, propName, componentName, location
) {
return true; // is always valid
}
return createChainableTypeChecker(validateAnyType);
}
function createPrimitiveTypeChecker(expectedType) {
function validatePrimitiveType(propValue, propName, componentName) {
var propType = typeof propValue;
if (propType === 'object' && Array.isArray(propValue)) {
propType = 'array';
function validatePrimitiveType(
shouldWarn, propValue, propName, componentName, location
) {
var propType = getPropType(propValue);
var isValid = propType === expectedType;
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` of type `%s` supplied to `%s`, expected `%s`.',
ReactPropTypeLocationNames[location],
propName,
propType,
componentName,
expectedType
);
}
("production" !== process.env.NODE_ENV ? invariant(
propType === expectedType,
'Invalid prop `%s` of type `%s` supplied to `%s`, expected `%s`.',
propName,
propType,
componentName,
expectedType
) : invariant(propType === expectedType));
return isValid;
}

@@ -113,10 +169,17 @@ return createChainableTypeChecker(validatePrimitiveType);

var expectedEnum = createObjectFrom(expectedValues);
function validateEnumType(propValue, propName, componentName) {
("production" !== process.env.NODE_ENV ? invariant(
expectedEnum[propValue],
'Invalid prop `%s` supplied to `%s`, expected one of %s.',
propName,
componentName,
JSON.stringify(Object.keys(expectedEnum))
) : invariant(expectedEnum[propValue]));
function validateEnumType(
shouldWarn, propValue, propName, componentName, location
) {
var isValid = expectedEnum[propValue];
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` supplied to `%s`, expected one of %s.',
ReactPropTypeLocationNames[location],
propName,
componentName,
JSON.stringify(Object.keys(expectedEnum))
);
}
return isValid;
}

@@ -126,11 +189,47 @@ return createChainableTypeChecker(validateEnumType);

function createShapeTypeChecker(shapeTypes) {
function validateShapeType(
shouldWarn, propValue, propName, componentName, location
) {
var propType = getPropType(propValue);
var isValid = propType === 'object';
if (isValid) {
for (var key in shapeTypes) {
var checker = shapeTypes[key];
if (checker && !checker(propValue, key, componentName, location)) {
return false;
}
}
}
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` of type `%s` supplied to `%s`, expected `object`.',
ReactPropTypeLocationNames[location],
propName,
propType,
componentName
);
}
return isValid;
}
return createChainableTypeChecker(validateShapeType);
}
function createInstanceTypeChecker(expectedClass) {
function validateInstanceType(propValue, propName, componentName) {
("production" !== process.env.NODE_ENV ? invariant(
propValue instanceof expectedClass,
'Invalid prop `%s` supplied to `%s`, expected instance of `%s`.',
propName,
componentName,
expectedClass.name || ANONYMOUS
) : invariant(propValue instanceof expectedClass));
function validateInstanceType(
shouldWarn, propValue, propName, componentName, location
) {
var isValid = propValue instanceof expectedClass;
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` supplied to `%s`, expected instance of `%s`.',
ReactPropTypeLocationNames[location],
propName,
componentName,
expectedClass.name || ANONYMOUS
);
}
return isValid;
}

@@ -140,26 +239,128 @@ return createChainableTypeChecker(validateInstanceType);

function createArrayOfTypeChecker(propTypeChecker) {
function validateArrayType(
shouldWarn, propValue, propName, componentName, location
) {
var isValid = Array.isArray(propValue);
if (isValid) {
for (var i = 0; i < propValue.length; i++) {
if (!propTypeChecker(propValue, i, componentName, location)) {
return false;
}
}
}
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` supplied to `%s`, expected an array.',
ReactPropTypeLocationNames[location],
propName,
componentName
);
}
return isValid;
}
return createChainableTypeChecker(validateArrayType);
}
function createRenderableTypeChecker() {
function validateRenderableType(
shouldWarn, propValue, propName, componentName, location
) {
var isValid = isRenderable(propValue);
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` supplied to `%s`, expected a renderable prop.',
ReactPropTypeLocationNames[location],
propName,
componentName
);
}
return isValid;
}
return createChainableTypeChecker(validateRenderableType);
}
function createComponentTypeChecker() {
function validateComponentType(
shouldWarn, propValue, propName, componentName, location
) {
var isValid = ReactComponent.isValidComponent(propValue);
if (shouldWarn) {
warning(
isValid,
'Invalid %s `%s` supplied to `%s`, expected a React component.',
ReactPropTypeLocationNames[location],
propName,
componentName
);
}
return isValid;
}
return createChainableTypeChecker(validateComponentType);
}
function createUnionTypeChecker(arrayOfValidators) {
return function(props, propName, componentName, location) {
var isValid = false;
for (var ii = 0; ii < arrayOfValidators.length; ii++) {
var validate = arrayOfValidators[ii];
if (typeof validate.weak === 'function') {
validate = validate.weak;
}
if (validate(props, propName, componentName, location)) {
isValid = true;
break;
}
}
warning(
isValid,
'Invalid %s `%s` supplied to `%s`.',
ReactPropTypeLocationNames[location],
propName,
componentName || ANONYMOUS
);
return isValid;
};
}
function createChainableTypeChecker(validate) {
function createTypeChecker(isRequired) {
function checkType(props, propName, componentName) {
var propValue = props[propName];
if (propValue != null) {
// Only validate if there is a value to check.
validate(propValue, propName, componentName || ANONYMOUS);
} else {
("production" !== process.env.NODE_ENV ? invariant(
!isRequired,
'Required prop `%s` was not specified in `%s`.',
function checkType(
isRequired, shouldWarn, props, propName, componentName, location
) {
var propValue = props[propName];
if (propValue != null) {
// Only validate if there is a value to check.
return validate(
shouldWarn,
propValue,
propName,
componentName || ANONYMOUS,
location
);
} else {
var isValid = !isRequired;
if (shouldWarn) {
warning(
isValid,
'Required %s `%s` was not specified in `%s`.',
ReactPropTypeLocationNames[location],
propName,
componentName || ANONYMOUS
) : invariant(!isRequired));
);
}
return isValid;
}
if (!isRequired) {
checkType.isRequired = createTypeChecker(true);
}
return checkType;
}
return createTypeChecker(false);
var checker = checkType.bind(null, false, true);
checker.weak = checkType.bind(null, false, false);
checker.isRequired = checkType.bind(null, true, true);
checker.weak.isRequired = checkType.bind(null, true, false);
checker.isRequired.weak = checker.weak.isRequired;
return checker;
}
module.exports = Props;

@@ -27,2 +27,3 @@ /**

var ReactMountReady = require("./ReactMountReady");
var ReactPutListenerQueue = require("./ReactPutListenerQueue");
var Transaction = require("./Transaction");

@@ -92,2 +93,12 @@

var PUT_LISTENER_QUEUEING = {
initialize: function() {
this.putListenerQueue.reset();
},
close: function() {
this.putListenerQueue.putListeners();
}
};
/**

@@ -99,2 +110,3 @@ * Executed within the scope of the `Transaction` instance. Consider these as

var TRANSACTION_WRAPPERS = [
PUT_LISTENER_QUEUEING,
SELECTION_RESTORATION,

@@ -122,2 +134,3 @@ EVENT_SUPPRESSION,

this.reactMountReady = ReactMountReady.getPooled(null);
this.putListenerQueue = ReactPutListenerQueue.getPooled();
}

@@ -149,2 +162,6 @@

getPutListenerQueue: function() {
return this.putListenerQueue;
},
/**

@@ -157,2 +174,5 @@ * `PooledClass` looks for this, and will invoke this before allowing this

this.reactMountReady = null;
ReactPutListenerQueue.release(this.putListenerQueue);
this.putListenerQueue = null;
}

@@ -159,0 +179,0 @@ };

@@ -30,8 +30,5 @@ /**

* @param {ReactComponent} component
* @param {function} callback
* @return {string} the markup
*/
function renderComponentToString(component, callback) {
// We use a callback API to keep the API async in case in the future we ever
// need it, but in reality this is a synchronous operation.
function renderComponentToString(component) {
("production" !== process.env.NODE_ENV ? invariant(

@@ -43,5 +40,6 @@ ReactComponent.isValidComponent(component),

("production" !== process.env.NODE_ENV ? invariant(
typeof callback === 'function',
'renderComponentToString(): You must pass a function as a callback.'
) : invariant(typeof callback === 'function'));
!(arguments.length === 2 && typeof arguments[1] === 'function'),
'renderComponentToString(): This function became synchronous and now ' +
'returns the generated markup. Please remove the second parameter.'
) : invariant(!(arguments.length === 2 && typeof arguments[1] === 'function')));

@@ -52,6 +50,5 @@ var id = ReactInstanceHandles.createReactRootID();

try {
transaction.perform(function() {
return transaction.perform(function() {
var markup = component.mountComponent(id, transaction, 0);
markup = ReactMarkupChecksum.addChecksumToMarkup(markup);
callback(markup);
return ReactMarkupChecksum.addChecksumToMarkup(markup);
}, null);

@@ -58,0 +55,0 @@ } finally {

@@ -22,4 +22,4 @@ /**

var DOMPropertyOperations = require("./DOMPropertyOperations");
var ReactComponent = require("./ReactComponent");
var ReactMount = require("./ReactMount");

@@ -69,3 +69,3 @@ var escapeTextForBrowser = require("./escapeTextForBrowser");

return (
'<span ' + ReactMount.ATTR_NAME + '="' + escapeTextForBrowser(rootID) + '">' +
'<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
escapeTextForBrowser(this.props.text) +

@@ -87,3 +87,3 @@ '</span>'

this.props.text = nextProps.text;
ReactComponent.DOMIDOperations.updateTextContentByID(
ReactComponent.BackendIDOperations.updateTextContentByID(
this._rootNodeID,

@@ -97,2 +97,7 @@ nextProps.text

// Expose the constructor on itself and the prototype for consistency with other
// descriptors.
ReactTextComponent.type = ReactTextComponent;
ReactTextComponent.prototype.type = ReactTextComponent;
module.exports = ReactTextComponent;

@@ -22,13 +22,13 @@ /**

var React = require("./React");
var ReactTransitionableChild = require("./ReactTransitionableChild");
var ReactTransitionKeySet = require("./ReactTransitionKeySet");
var ReactTransitionChildMapping = require("./ReactTransitionChildMapping");
var cloneWithProps = require("./cloneWithProps");
var emptyFunction = require("./emptyFunction");
var merge = require("./merge");
var ReactTransitionGroup = React.createClass({
propTypes: {
transitionName: React.PropTypes.string.isRequired,
transitionEnter: React.PropTypes.bool,
transitionLeave: React.PropTypes.bool,
onTransition: React.PropTypes.func,
component: React.PropTypes.func
component: React.PropTypes.func,
childFactory: React.PropTypes.func
},

@@ -38,74 +38,149 @@

return {
transitionEnter: true,
transitionLeave: true,
component: React.DOM.span
component: React.DOM.span,
childFactory: emptyFunction.thatReturnsArgument
};
},
getInitialState: function() {
return {
children: ReactTransitionChildMapping.getChildMapping(this.props.children)
};
},
componentWillReceiveProps: function(nextProps) {
var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
nextProps.children
);
var prevChildMapping = this.state.children;
this.setState({
children: ReactTransitionChildMapping.mergeChildMappings(
prevChildMapping,
nextChildMapping
)
});
var key;
for (key in nextChildMapping) {
if (!prevChildMapping.hasOwnProperty(key) &&
!this.currentlyTransitioningKeys[key]) {
this.keysToEnter.push(key);
}
}
for (key in prevChildMapping) {
if (!nextChildMapping.hasOwnProperty(key) &&
!this.currentlyTransitioningKeys[key]) {
this.keysToLeave.push(key);
}
}
// If we want to someday check for reordering, we could do it here.
},
componentWillMount: function() {
// _transitionGroupCurrentKeys stores the union of previous *and* next keys.
// If this were a component we'd store it as state, however, since this must
// be a mixin, we need to keep the result of the union of keys in each
// call to animateChildren() which happens in render(), so we can't
// call setState() in there.
this._transitionGroupCurrentKeys = {};
this.currentlyTransitioningKeys = {};
this.keysToEnter = [];
this.keysToLeave = [];
},
componentDidUpdate: function() {
if (this.props.onTransition) {
this.props.onTransition();
var keysToEnter = this.keysToEnter;
this.keysToEnter = [];
keysToEnter.forEach(this.performEnter);
var keysToLeave = this.keysToLeave;
this.keysToLeave = [];
keysToLeave.forEach(this.performLeave);
},
performEnter: function(key) {
this.currentlyTransitioningKeys[key] = true;
var component = this.refs[key];
if (component.componentWillEnter) {
component.componentWillEnter(
this._handleDoneEntering.bind(this, key)
);
} else {
this._handleDoneEntering(key);
}
},
/**
* Render some children in a transitionable way.
*/
renderTransitionableChildren: function(sourceChildren) {
var children = {};
var childMapping = ReactTransitionKeySet.getChildMapping(sourceChildren);
_handleDoneEntering: function(key) {
var component = this.refs[key];
if (component.componentDidEnter) {
component.componentDidEnter();
}
var currentKeys = ReactTransitionKeySet.mergeKeySets(
this._transitionGroupCurrentKeys,
ReactTransitionKeySet.getKeySet(sourceChildren)
delete this.currentlyTransitioningKeys[key];
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children
);
for (var key in currentKeys) {
// Here is how we keep the nodes in the DOM. ReactTransitionableChild
// knows how to hold onto its child if it changes to undefined. Here, we
// may look up an old key in the new children, and it may switch to
// undefined. React's reconciler will keep the ReactTransitionableChild
// instance alive such that we can animate it.
if (childMapping[key] || this.props.transitionLeave) {
children[key] = ReactTransitionableChild({
name: this.props.transitionName,
enter: this.props.transitionEnter,
onDoneLeaving: this._handleDoneLeaving.bind(this, key)
}, childMapping[key]);
}
if (!currentChildMapping.hasOwnProperty(key)) {
// This was removed before it had fully entered. Remove it.
this.performLeave(key);
}
},
this._transitionGroupCurrentKeys = currentKeys;
performLeave: function(key) {
this.currentlyTransitioningKeys[key] = true;
return children;
var component = this.refs[key];
if (component.componentWillLeave) {
component.componentWillLeave(this._handleDoneLeaving.bind(this, key));
} else {
// Note that this is somewhat dangerous b/c it calls setState()
// again, effectively mutating the component before all the work
// is done.
this._handleDoneLeaving(key);
}
},
_handleDoneLeaving: function(key) {
// When the leave animation finishes, we should blow away the actual DOM
// node.
delete this._transitionGroupCurrentKeys[key];
this.forceUpdate();
var component = this.refs[key];
if (component.componentDidLeave) {
component.componentDidLeave();
}
delete this.currentlyTransitioningKeys[key];
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children
);
if (currentChildMapping.hasOwnProperty(key)) {
// This entered again before it fully left. Add it again.
this.performEnter(key);
} else {
var newChildren = merge(this.state.children);
delete newChildren[key];
this.setState({children: newChildren});
}
},
render: function() {
return this.transferPropsTo(
this.props.component(
{
transitionName: null,
transitionEnter: null,
transitionLeave: null,
component: null
},
this.renderTransitionableChildren(this.props.children)
)
);
// TODO: we could get rid of the need for the wrapper node
// by cloning a single child
var childrenToRender = {};
for (var key in this.state.children) {
var child = this.state.children[key];
if (child) {
// You may need to apply reactive updates to a child as it is leaving.
// The normal React way to do it won't work since the child will have
// already been removed. In case you need this behavior you can provide
// a childFactory function to wrap every child, even the ones that are
// leaving.
childrenToRender[key] = cloneWithProps(
this.props.childFactory(child),
{ref: key}
);
}
}
return this.transferPropsTo(this.props.component(null, childrenToRender));
}

@@ -112,0 +187,0 @@ });

@@ -21,2 +21,4 @@ /**

var ReactPerf = require("./ReactPerf");
var invariant = require("./invariant");

@@ -79,13 +81,14 @@

function flushBatchedUpdates() {
// Run these in separate functions so the JIT can optimize
try {
runBatchedUpdates();
} catch (e) {
// IE 8 requires catch to use finally.
throw e;
} finally {
clearDirtyComponents();
var flushBatchedUpdates = ReactPerf.measure(
'ReactUpdates',
'flushBatchedUpdates',
function() {
// Run these in separate functions so the JIT can optimize
try {
runBatchedUpdates();
} finally {
clearDirtyComponents();
}
}
}
);

@@ -107,3 +110,3 @@ /**

component.performUpdateIfNecessary();
callback && callback();
callback && callback.call(component);
return;

@@ -110,0 +113,0 @@ }

@@ -30,10 +30,15 @@ /**

var React = require("./React");
var ReactCSSTransitionGroup = require("./ReactCSSTransitionGroup");
var ReactTransitionGroup = require("./ReactTransitionGroup");
var cx = require("./cx");
var cloneWithProps = require("./cloneWithProps");
React.addons = {
LinkedStateMixin: LinkedStateMixin,
CSSTransitionGroup: ReactCSSTransitionGroup,
TransitionGroup: ReactTransitionGroup,
classSet: cx,
LinkedStateMixin: LinkedStateMixin,
TransitionGroup: ReactTransitionGroup
cloneWithProps: cloneWithProps
};

@@ -40,0 +45,0 @@

@@ -22,5 +22,3 @@ /**

var EventConstants = require("./EventConstants");
var EventPluginHub = require("./EventPluginHub");
var EventPropagators = require("./EventPropagators");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var ReactInputSelection = require("./ReactInputSelection");

@@ -41,15 +39,17 @@ var SyntheticEvent = require("./SyntheticEvent");

captured: keyOf({onSelectCapture: null})
}
},
dependencies: [
topLevelTypes.topBlur,
topLevelTypes.topContextMenu,
topLevelTypes.topFocus,
topLevelTypes.topKeyDown,
topLevelTypes.topMouseDown,
topLevelTypes.topMouseUp,
topLevelTypes.topSelectionChange
]
}
};
var useSelectionChange = false;
if (ExecutionEnvironment.canUseDOM) {
useSelectionChange = 'onselectionchange' in document;
}
var activeElement = null;
var activeElementID = null;
var activeNativeEvent = null;
var lastSelection = null;

@@ -101,4 +101,8 @@ var mouseDown = false;

// Ensure we have the right element, and that the user is not dragging a
// selection (this matches native `select` event behavior).
if (mouseDown || activeElement != getActiveElement()) {
// selection (this matches native `select` event behavior). In HTML5, select
// fires only on input and textarea thus if there's no focused element we
// won't dispatch.
if (mouseDown ||
activeElement == null ||
activeElement != getActiveElement()) {
return;

@@ -128,20 +132,2 @@ }

/**
* Handle deferred event. And manually dispatch synthetic events.
*/
function dispatchDeferredSelectEvent() {
if (!activeNativeEvent) {
return;
}
var syntheticEvent = constructSelectEvent(activeNativeEvent);
activeNativeEvent = null;
// Enqueue and process the abstract event manually.
if (syntheticEvent) {
EventPluginHub.enqueueEvents(syntheticEvent);
EventPluginHub.processEventQueue();
}
}
/**
* This plugin creates an `onSelect` event that normalizes select events

@@ -206,13 +192,10 @@ * across form elements.

// sometimes when it hasn't).
// Firefox doesn't support selectionchange, so check selection status
// after each key entry. The selection changes after keydown and before
// keyup, but we check on keydown as well in the case of holding down a
// key, when multiple keydown events are fired but only one keyup is.
case topLevelTypes.topSelectionChange:
case topLevelTypes.topKeyDown:
case topLevelTypes.topKeyUp:
return constructSelectEvent(nativeEvent);
// Firefox doesn't support selectionchange, so check selection status
// after each key entry.
case topLevelTypes.topKeyDown:
if (!useSelectionChange) {
activeNativeEvent = nativeEvent;
setTimeout(dispatchDeferredSelectEvent, 0);
}
break;
}

@@ -219,0 +202,0 @@ }

@@ -22,2 +22,3 @@ /**

var EventConstants = require("./EventConstants");
var EventPluginUtils = require("./EventPluginUtils");
var EventPropagators = require("./EventPropagators");

@@ -29,2 +30,3 @@ var SyntheticClipboardEvent = require("./SyntheticClipboardEvent");

var SyntheticMouseEvent = require("./SyntheticMouseEvent");
var SyntheticDragEvent = require("./SyntheticDragEvent");
var SyntheticTouchEvent = require("./SyntheticTouchEvent");

@@ -154,2 +156,14 @@ var SyntheticUIEvent = require("./SyntheticUIEvent");

},
load: {
phasedRegistrationNames: {
bubbled: keyOf({onLoad: true}),
captured: keyOf({onLoadCapture: true})
}
},
error: {
phasedRegistrationNames: {
bubbled: keyOf({onError: true}),
captured: keyOf({onErrorCapture: true})
}
},
// Note: We do not allow listening to mouseOver events. Instead, use the

@@ -169,2 +183,14 @@ // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.

},
mouseOut: {
phasedRegistrationNames: {
bubbled: keyOf({onMouseOut: true}),
captured: keyOf({onMouseOutCapture: true})
}
},
mouseOver: {
phasedRegistrationNames: {
bubbled: keyOf({onMouseOver: true}),
captured: keyOf({onMouseOverCapture: true})
}
},
mouseUp: {

@@ -182,2 +208,8 @@ phasedRegistrationNames: {

},
reset: {
phasedRegistrationNames: {
bubbled: keyOf({onReset: true}),
captured: keyOf({onResetCapture: true})
}
},
scroll: {

@@ -242,2 +274,3 @@ phasedRegistrationNames: {

topDrop: eventTypes.drop,
topError: eventTypes.error,
topFocus: eventTypes.focus,

@@ -248,6 +281,10 @@ topInput: eventTypes.input,

topKeyUp: eventTypes.keyUp,
topLoad: eventTypes.load,
topMouseDown: eventTypes.mouseDown,
topMouseMove: eventTypes.mouseMove,
topMouseOut: eventTypes.mouseOut,
topMouseOver: eventTypes.mouseOver,
topMouseUp: eventTypes.mouseUp,
topPaste: eventTypes.paste,
topReset: eventTypes.reset,
topScroll: eventTypes.scroll,

@@ -262,2 +299,6 @@ topSubmit: eventTypes.submit,

for (var topLevelType in topLevelEventsToDispatchConfig) {
topLevelEventsToDispatchConfig[topLevelType].dependencies = [topLevelType];
}
var SimpleEventPlugin = {

@@ -276,3 +317,3 @@

executeDispatch: function(event, listener, domID) {
var returnValue = listener(event, domID);
var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
if (returnValue === false) {

@@ -302,4 +343,7 @@ event.stopPropagation();

var EventConstructor;
switch(topLevelType) {
switch (topLevelType) {
case topLevelTypes.topInput:
case topLevelTypes.topLoad:
case topLevelTypes.topError:
case topLevelTypes.topReset:
case topLevelTypes.topSubmit:

@@ -328,2 +372,9 @@ // HTML Events

case topLevelTypes.topDoubleClick:
case topLevelTypes.topMouseDown:
case topLevelTypes.topMouseMove:
case topLevelTypes.topMouseOut:
case topLevelTypes.topMouseOver:
case topLevelTypes.topMouseUp:
EventConstructor = SyntheticMouseEvent;
break;
case topLevelTypes.topDrag:

@@ -337,6 +388,3 @@ case topLevelTypes.topDragEnd:

case topLevelTypes.topDrop:
case topLevelTypes.topMouseDown:
case topLevelTypes.topMouseMove:
case topLevelTypes.topMouseUp:
EventConstructor = SyntheticMouseEvent;
EventConstructor = SyntheticDragEvent;
break;

@@ -343,0 +391,0 @@ case topLevelTypes.topTouchCancel:

@@ -29,3 +29,9 @@ /**

var ClipboardEventInterface = {
clipboardData: null
clipboardData: function(event) {
return (
'clipboardData' in event ?
event.clipboardData :
window.clipboardData
);
}
};

@@ -32,0 +38,0 @@

@@ -36,3 +36,4 @@ /**

target: getEventTarget,
currentTarget: null,
// currentTarget is set when dispatching; no use in copying it here
currentTarget: emptyFunction.thatReturnsNull,
eventPhase: null,

@@ -39,0 +40,0 @@ bubbles: null,

@@ -24,2 +24,4 @@ /**

var getEventKey = require("./getEventKey");
/**

@@ -30,4 +32,3 @@ * @interface KeyboardEvent

var KeyboardEventInterface = {
'char': null,
key: null,
key: getEventKey,
location: null,

@@ -41,2 +42,3 @@ ctrlKey: null,

// Legacy Interface
'char': null,
charCode: null,

@@ -43,0 +45,0 @@ keyCode: null,

@@ -30,3 +30,2 @@ /**

deltaX: function(event) {
// NOTE: IE<9 does not support x-axis delta.
return (

@@ -40,11 +39,15 @@ 'deltaX' in event ? event.deltaX :

return (
// Normalize (up is positive).
'deltaY' in event ? -event.deltaY :
// Fallback to `wheelDeltaY` for Webkit.
'wheelDeltaY' in event ? event.wheelDeltaY :
// Fallback to `wheelDelta` for IE<9.
'wheelDelta' in event ? event.wheelDelta : 0
'deltaY' in event ? event.deltaY :
// Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
'wheelDeltaY' in event ? -event.wheelDeltaY :
// Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
'wheelDelta' in event ? -event.wheelDelta : 0
);
},
deltaZ: null,
// Browsers without "deltaMode" is reporting in raw wheel delta where one
// notch on the scroll is always +/- 120, roughly equivalent to pixels.
// A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
// ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
deltaMode: null

@@ -51,0 +54,0 @@ };

@@ -30,3 +30,3 @@ /**

* 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
* should not be run while it is already being run. You would typically create a
* single instance of a `Transaction` for reuse multiple times, that potentially

@@ -71,3 +71,3 @@ * is used to wrap several different methods. Wrappers are extremely simple -

* reconciliation takes place in a worker thread.
* - Invoking any collected `componentDidRender` callbacks after rendering new
* - Invoking any collected `componentDidUpdate` callbacks after rendering new
* content.

@@ -151,10 +151,14 @@ * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue

var memberStart = Date.now();
var errorToThrow = null;
var errorThrown;
var ret;
try {
this.initializeAll();
this._isInTransaction = true;
// Catching errors makes debugging more difficult, so we start with
// errorThrown set to true before setting it to false after calling
// close -- if it's still set to true in the finally block, it means
// one of these calls threw.
errorThrown = true;
this.initializeAll(0);
ret = method.call(scope, a, b, c, d, e, f);
} catch (error) {
// IE8 requires `catch` in order to use `finally`.
errorToThrow = error;
errorThrown = false;
} finally {

@@ -164,31 +168,36 @@ var memberEnd = Date.now();

try {
this.closeAll();
} catch (closeError) {
// If `method` throws, prefer to show that stack trace over any thrown
// by invoking `closeAll`.
errorToThrow = errorToThrow || closeError;
if (errorThrown) {
// If `method` throws, prefer to show that stack trace over any thrown
// by invoking `closeAll`.
try {
this.closeAll(0);
} catch (err) {
}
} else {
// Since `method` didn't throw, we don't want to silence the exception
// here.
this.closeAll(0);
}
} finally {
this._isInTransaction = false;
}
}
if (errorToThrow) {
throw errorToThrow;
}
return ret;
},
initializeAll: function() {
this._isInTransaction = true;
initializeAll: function(startIndex) {
var transactionWrappers = this.transactionWrappers;
var wrapperInitTimes = this.timingMetrics.wrapperInitTimes;
var errorToThrow = null;
for (var i = 0; i < transactionWrappers.length; i++) {
for (var i = startIndex; i < transactionWrappers.length; i++) {
var initStart = Date.now();
var wrapper = transactionWrappers[i];
try {
// Catching errors makes debugging more difficult, so we start with the
// OBSERVED_ERROR state before overwriting it with the real return value
// of initialize -- if it's still set to OBSERVED_ERROR in the finally
// block, it means wrapper.initialize threw.
this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
this.wrapperInitData[i] = wrapper.initialize ?
wrapper.initialize.call(this) :
null;
} catch (initError) {
// Prefer to show the stack trace of the first error.
errorToThrow = errorToThrow || initError;
this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
} finally {

@@ -198,7 +207,14 @@ var curInitTime = wrapperInitTimes[i];

wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart);
if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
// The initializer for wrapper i threw an error; initialize the
// remaining wrappers but silence any exceptions from them to ensure
// that the first error is the one to bubble up.
try {
this.initializeAll(i + 1);
} catch (err) {
}
}
}
}
if (errorToThrow) {
throw errorToThrow;
}
},

@@ -212,3 +228,3 @@

*/
closeAll: function() {
closeAll: function(startIndex) {
("production" !== process.env.NODE_ENV ? invariant(

@@ -220,14 +236,17 @@ this.isInTransaction(),

var wrapperCloseTimes = this.timingMetrics.wrapperCloseTimes;
var errorToThrow = null;
for (var i = 0; i < transactionWrappers.length; i++) {
for (var i = startIndex; i < transactionWrappers.length; i++) {
var wrapper = transactionWrappers[i];
var closeStart = Date.now();
var initData = this.wrapperInitData[i];
var errorThrown;
try {
// Catching errors makes debugging more difficult, so we start with
// errorThrown set to true before setting it to false after calling
// close -- if it's still set to true in the finally block, it means
// wrapper.close threw.
errorThrown = true;
if (initData !== Transaction.OBSERVED_ERROR) {
wrapper.close && wrapper.close.call(this, initData);
}
} catch (closeError) {
// Prefer to show the stack trace of the first error.
errorToThrow = errorToThrow || closeError;
errorThrown = false;
} finally {

@@ -237,9 +256,15 @@ var closeEnd = Date.now();

wrapperCloseTimes[i] = (curCloseTime || 0) + (closeEnd - closeStart);
if (errorThrown) {
// The closer for wrapper i threw an error; close the remaining
// wrappers but silence any exceptions from them to ensure that the
// first error is the one to bubble up.
try {
this.closeAll(i + 1);
} catch (e) {
}
}
}
}
this.wrapperInitData.length = 0;
this._isInTransaction = false;
if (errorToThrow) {
throw errorToThrow;
}
}

@@ -246,0 +271,0 @@ };

@@ -21,3 +21,3 @@ /**

var ReactComponent = require("./ReactComponent");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactTextComponent = require("./ReactTextComponent");

@@ -27,2 +27,5 @@

var SEPARATOR = ReactInstanceHandles.SEPARATOR;
var SUBSEPARATOR = ':';
/**

@@ -36,3 +39,55 @@ * TODO: Test that:

var userProvidedKeyEscaperLookup = {
'=': '=0',
'.': '=1',
':': '=2'
};
var userProvidedKeyEscapeRegex = /[=.:]/g;
function userProvidedKeyEscaper(match) {
return userProvidedKeyEscaperLookup[match];
}
/**
* Generate a key string that identifies a component within a set.
*
* @param {*} component A component that could contain a manual key.
* @param {number} index Index that is used if a manual key is not provided.
* @return {string}
*/
function getComponentKey(component, index) {
if (component && component.props && component.props.key != null) {
// Explicit key
return wrapUserProvidedKey(component.props.key);
}
// Implicit key determined by the index in the set
return index.toString(36);
}
/**
* Escape a component key so that it is safe to use in a reactid.
*
* @param {*} key Component key to be escaped.
* @return {string} An escaped string.
*/
function escapeUserProvidedKey(text) {
return ('' + text).replace(
userProvidedKeyEscapeRegex,
userProvidedKeyEscaper
);
}
/**
* Wrap a `key` value explicitly provided by the user to distinguish it from
* implicitly-generated keys generated by a component's index in its parent.
*
* @param {string} key Value of a user-provided `key` attribute
* @return {string}
*/
function wrapUserProvidedKey(key) {
return '$' + escapeUserProvidedKey(key);
}
/**
* @param {?*} children Children tree container.

@@ -52,3 +107,7 @@ * @param {!string} nameSoFar Name of the key path so far.

var child = children[i];
var nextName = nameSoFar + ReactComponent.getKey(child, i);
var nextName = (
nameSoFar +
(nameSoFar ? SUBSEPARATOR : SEPARATOR) +
getComponentKey(child, i)
);
var nextIndex = indexSoFar + subtreeCount;

@@ -68,6 +127,5 @@ subtreeCount += traverseAllChildrenImpl(

// so that it's consistent if the number of children grows
var storageName = isOnlyChild ?
ReactComponent.getKey(children, 0):
nameSoFar;
if (children === null || children === undefined || type === 'boolean') {
var storageName =
isOnlyChild ? SEPARATOR + getComponentKey(children, 0) : nameSoFar;
if (children == null || type === 'boolean') {
// All of the above are perceived as null.

@@ -90,3 +148,7 @@ callback(traverseContext, null, storageName, indexSoFar);

children[key],
nameSoFar + '{' + key + '}',
(
nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
wrapUserProvidedKey(key) + SUBSEPARATOR +
getComponentKey(children[key], 0)
),
indexSoFar + subtreeCount,

@@ -93,0 +155,0 @@ callback,

{
"name": "react",
"version": "0.8.0",
"version": "0.9.0-rc1",
"keywords": [

@@ -19,3 +19,2 @@ "react"

"react.js",
"ReactJSErrors.js",
"lib/"

@@ -32,3 +31,3 @@ ],

"peerDependencies": {
"envify": "~0.2.0"
"envify": "~1.0.1"
},

@@ -35,0 +34,0 @@ "browserify": {

module.exports = require('./lib/React');
if ('production' !== process.env.NODE_ENV) {
module.exports = require('./ReactJSErrors').wrap(module.exports);
}

@@ -8,14 +8,6 @@ # react

## The `react` npm package has recently changed!
If you're looking for jeffbski's [React.js](https://github.com/jeffbski/react) project, it's now in `npm` as `autoflow` rather than `react`.
## Example Usage
```js
// Previously, you might access React with react-tools.
var React = require('react-tools').React;
// Now you can access React directly with react-core.
var React = require('react');

@@ -22,0 +14,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc