From 20bea94ab6b91c85b171dcf86baba0a64169d508 Mon Sep 17 00:00:00 2001 From: Giulio Cesare Solaroli Date: Fri, 30 Aug 2013 15:56:53 +0000 Subject: First release of /delta version --- (limited to 'frontend/delta/js/React/react-0.4.1.js') diff --git a/frontend/delta/js/React/react-0.4.1.js b/frontend/delta/js/React/react-0.4.1.js new file mode 100644 index 0000000..d029de2 --- a/dev/null +++ b/frontend/delta/js/React/react-0.4.1.js @@ -0,0 +1,11491 @@ +/* + +Copyright 2008-2013 Clipperz Srl + +This file is part of Clipperz, the online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + +* Clipperz is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Affero General Public License for more details. + +* You should have received a copy of the GNU Affero General Public + License along with Clipperz. If not, see http://www.gnu.org/licenses/. + +*/ + +/** + * React v0.4.1 + */ +(function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()})(function(){var define,ses,bootstrap,module,exports; +return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * + * @param {object} styles + * @return {?string} + */ + createMarkupForStyles: function(styles) { + var serialized = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if (styleValue != null) { + serialized += processStyleName(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue) + ';'; + } + } + return serialized || null; + }, + + /** + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles + */ + setValueForStyles: function(node, styles) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = dangerousStyleValue(styleName, styles[styleName]); + if (styleValue) { + style[styleName] = styleValue; + } else { + var expansion = CSSProperty.shorthandPropertyExpansions[styleName]; + if (expansion) { + // Shorthand property that IE8 won't like unsetting, so unset each + // component to placate it + for (var individualStyleName in expansion) { + style[individualStyleName] = ''; + } + } else { + style[styleName] = ''; + } + } + } + } + +}; + +module.exports = CSSPropertyOperations; + +},{"./CSSProperty":2,"./dangerousStyleValue":65,"./escapeTextForBrowser":67,"./hyphenate":76,"./memoizeStringOnly":83}],4:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule CallbackRegistry + * @typechecks static-only + */ + +"use strict"; + +var listenerBank = {}; + +/** + * Stores "listeners" by `registrationName`/`id`. There should be at most one + * "listener" per `registrationName`/`id` in the `listenerBank`. + * + * Access listeners via `listenerBank[registrationName][id]`. + * + * @class CallbackRegistry + * @internal + */ +var CallbackRegistry = { + + /** + * 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) { + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, + + /** + * @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]; + }, + + /** + * 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]; + } + }, + + /** + * This is needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + } + +}; + +module.exports = CallbackRegistry; + +},{}],5:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ChangeEventPlugin + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var SyntheticEvent = require("./SyntheticEvent"); + +var isEventSupported = require("./isEventSupported"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; + +var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: keyOf({onChange: null}), + captured: keyOf({onChangeCapture: null}) + } + } +}; + +/** + * For IE shims + */ +var activeElement = null; +var activeElementID = null; +var activeElementValue = null; +var activeElementValueProp = null; + + +/** + * SECTION: handle `change` event + */ +function shouldUseChangeEvent(elem) { + return ( + elem.nodeName === 'SELECT' || + (elem.nodeName === 'INPUT' && elem.type === 'file') + ); +} + +var doesChangeEventBubble = false; +if (ExecutionEnvironment.canUseDOM) { + // See `handleChange` comment below + doesChangeEventBubble = isEventSupported('change') && ( + !('documentMode' in document) || document.documentMode > 8 + ); +} + +function manualDispatchChangeEvent(nativeEvent) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + activeElementID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + + // 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 + // process the abstract event manually. + EventPluginHub.enqueueEvents(event); + EventPluginHub.processEventQueue(); +} + +function startWatchingForChangeEventIE8(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElement.attachEvent('onchange', manualDispatchChangeEvent); +} + +function stopWatchingForChangeEventIE8() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onchange', manualDispatchChangeEvent); + activeElement = null; + activeElementID = null; +} + +function getTargetIDForChangeEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topChange) { + return topLevelTargetID; + } +} +function handleEventsForChangeEventIE8( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForChangeEventIE8(); + startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForChangeEventIE8(); + } +} + + +/** + * SECTION: handle `input` event + */ +var isInputEventSupported = false; +if (ExecutionEnvironment.canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events + isInputEventSupported = isEventSupported('input') && ( + !('documentMode' in document) || document.documentMode > 9 + ); +} + + +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + 'color': true, + 'date': true, + 'datetime': true, + 'datetime-local': true, + 'email': true, + 'month': true, + 'number': true, + 'password': true, + 'range': true, + 'search': true, + 'tel': true, + 'text': true, + 'time': true, + 'url': true, + 'week': true +}; + +function shouldUseInputEvent(elem) { + return ( + (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) || + elem.nodeName === 'TEXTAREA' + ); +} + +/** + * (For old IE.) Replacement getter/setter for the `value` property that gets + * set on the active element. + */ +var newValueProp = { + get: function() { + return activeElementValueProp.get.call(this); + }, + set: function(val) { + // Cast to a string so we can do equality checks. + activeElementValue = '' + val; + activeElementValueProp.set.call(this, val); + } +}; + +/** + * (For old IE.) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ +function startWatchingForValueChange(target, targetID) { + activeElement = target; + activeElementID = targetID; + activeElementValue = target.value; + activeElementValueProp = Object.getOwnPropertyDescriptor( + target.constructor.prototype, + 'value' + ); + + Object.defineProperty(activeElement, 'value', newValueProp); + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} + +/** + * (For old IE.) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + + // delete restores the original property definition + delete activeElement.value; + activeElement.detachEvent('onpropertychange', handlePropertyChange); + + activeElement = null; + activeElementID = null; + activeElementValue = null; + activeElementValueProp = null; +} + +/** + * (For old IE.) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== 'value') { + return; + } + var value = nativeEvent.srcElement.value; + if (value === activeElementValue) { + return; + } + activeElementValue = value; + + manualDispatchChangeEvent(nativeEvent); +} + +/** + * If a `change` event should be fired, returns the target's ID. + */ +function getTargetIDForInputEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topInput) { + // In modern browsers (i.e., not IE8 or IE9), the input event is exactly + // what we want so fall through here and trigger an abstract event + return topLevelTargetID; + } +} + +// For IE8 and IE9. +function handleEventsForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topFocus) { + // In IE8, we can capture almost all .value changes by adding a + // propertychange handler and looking for events with propertyName + // equal to 'value' + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(topLevelTarget, topLevelTargetID); + } else if (topLevelType === topLevelTypes.topBlur) { + stopWatchingForValueChange(); + } +} + +// For IE8 and IE9. +function getTargetIDForInputEventIE( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topSelectionChange || + topLevelType === topLevelTypes.topKeyUp || + topLevelType === topLevelTypes.topKeyDown) { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + if (activeElement && activeElement.value !== activeElementValue) { + activeElementValue = activeElement.value; + return activeElementID; + } + } +} + + +/** + * SECTION: handle `click` event + */ +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + return ( + elem.nodeName === 'INPUT' && + (elem.type === 'checkbox' || elem.type === 'radio') + ); +} + +function getTargetIDForClickEvent( + topLevelType, + topLevelTarget, + topLevelTargetID) { + if (topLevelType === topLevelTypes.topClick) { + return topLevelTargetID; + } +} + +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. + * + * Supported elements are: + * - input (see `supportedInputTypes`) + * - textarea + * - select + */ +var ChangeEventPlugin = { + + eventTypes: eventTypes, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + + var getTargetIDFunc, handleEventFunc; + if (shouldUseChangeEvent(topLevelTarget)) { + if (doesChangeEventBubble) { + getTargetIDFunc = getTargetIDForChangeEvent; + } else { + handleEventFunc = handleEventsForChangeEventIE8; + } + } else if (shouldUseInputEvent(topLevelTarget)) { + if (isInputEventSupported) { + getTargetIDFunc = getTargetIDForInputEvent; + } else { + getTargetIDFunc = getTargetIDForInputEventIE; + handleEventFunc = handleEventsForInputEventIE; + } + } else if (shouldUseClickEvent(topLevelTarget)) { + getTargetIDFunc = getTargetIDForClickEvent; + } + + if (getTargetIDFunc) { + var targetID = getTargetIDFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + if (targetID) { + var event = SyntheticEvent.getPooled( + eventTypes.change, + targetID, + nativeEvent + ); + EventPropagators.accumulateTwoPhaseDispatches(event); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc( + topLevelType, + topLevelTarget, + topLevelTargetID + ); + } + } + +}; + +module.exports = ChangeEventPlugin; + +})() +},{"./EventConstants":13,"./EventPluginHub":15,"./EventPropagators":18,"./ExecutionEnvironment":19,"./SyntheticEvent":51,"./isEventSupported":79,"./keyOf":82}],6:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMChildrenOperations + */ + +// Empty blocks improve readability so disable that warning +// jshint -W035 + +"use strict"; + +var Danger = require("./Danger"); + +var insertNodeAt = require("./insertNodeAt"); +var keyOf = require("./keyOf"); +var throwIf = require("./throwIf"); + +var NON_INCREASING_OPERATIONS; +if (true) { + NON_INCREASING_OPERATIONS = + 'DOM child management operations must be provided in order ' + + 'of increasing destination index. This is likely an issue with ' + + 'the core framework.'; +} + +var MOVE_NODE_AT_ORIG_INDEX = keyOf({moveFrom: null}); +var INSERT_MARKUP = keyOf({insertMarkup: null}); +var REMOVE_AT = keyOf({removeAt: null}); + +/** + * In order to carry out movement of DOM nodes without knowing their IDs, we + * have to first store knowledge about nodes' original indices before beginning + * to carry out the sequence of operations. Once we begin the sequence, the DOM + * indices in future instructions are no longer valid. + * + * @param {Element} parent Parent DOM node. + * @param {Object} childOperations Description of child operations. + * @return {Array?} Sparse array containing elements by their current index in + * the DOM. + */ +var _getNodesByOriginalIndex = function(parent, childOperations) { + var nodesByOriginalIndex; // Sparse array. + var childOperation; + var origIndex; + for (var i = 0; i < childOperations.length; i++) { + childOperation = childOperations[i]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.moveFrom; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; + } else if (REMOVE_AT in childOperation) { + nodesByOriginalIndex = nodesByOriginalIndex || []; + origIndex = childOperation.removeAt; + nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex]; + } + } + return nodesByOriginalIndex; +}; + +/** + * Removes DOM elements from their parent, or moved. + * @param {Element} parent Parent DOM node. + * @param {Array} nodesByOriginalIndex Child nodes by their original index + * (potentially sparse.) + */ +var _removeChildrenByOriginalIndex = function(parent, nodesByOriginalIndex) { + for (var j = 0; j < nodesByOriginalIndex.length; j++) { + var nodeToRemove = nodesByOriginalIndex[j]; + if (nodeToRemove) { // We used a sparse array. + parent.removeChild(nodesByOriginalIndex[j]); + } + } +}; + +/** + * Once all nodes that will be removed or moved - are removed from the parent + * node, we can begin the process of placing nodes into their final locations. + * We must perform all operations in the order of the final DOM index - + * otherwise, we couldn't count on the fact that an insertion at index X, will + * remain at index X. This will iterate through the child operations, adding + * content where needed, skip over removals (they've already been removed) and + * insert "moved" Elements that were previously removed. The "moved" elements + * are only temporarily removed from the parent, so that index calculations can + * be manageable and perform well in the cases that matter. + */ +var _placeNodesAtDestination = + function(parent, childOperations, nodesByOriginalIndex) { + var origNode; + var finalIndex; + var lastFinalIndex = -1; + var childOperation; + for (var k = 0; k < childOperations.length; k++) { + childOperation = childOperations[k]; + if (MOVE_NODE_AT_ORIG_INDEX in childOperation) { + origNode = nodesByOriginalIndex[childOperation.moveFrom]; + finalIndex = childOperation.finalIndex; + insertNodeAt(parent, origNode, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } + } else if (REMOVE_AT in childOperation) { + } else if (INSERT_MARKUP in childOperation) { + finalIndex = childOperation.finalIndex; + var markup = childOperation.insertMarkup; + Danger.dangerouslyInsertMarkupAt(parent, markup, finalIndex); + if (true) { + throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS); + lastFinalIndex = finalIndex; + } + } + } + }; + +var manageChildren = function(parent, childOperations) { + var nodesByOriginalIndex = _getNodesByOriginalIndex(parent, childOperations); + if (nodesByOriginalIndex) { + _removeChildrenByOriginalIndex(parent, nodesByOriginalIndex); + } + _placeNodesAtDestination(parent, childOperations, nodesByOriginalIndex); +}; + +/** + * Also reexport all of the dangerous functions. It helps to have all dangerous + * functions located in a single module `Danger`. + */ +var DOMChildrenOperations = { + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + manageChildren: manageChildren +}; + +module.exports = DOMChildrenOperations; + +})() +},{"./Danger":9,"./insertNodeAt":77,"./keyOf":82,"./throwIf":89}],7:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMProperty + * @typechecks static-only + */ + +/*jslint bitwise: true */ + +"use strict"; + +var invariant = require("./invariant"); + +var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_ATTRIBUTE: 0x1, + MUST_USE_PROPERTY: 0x2, + HAS_BOOLEAN_VALUE: 0x4, + HAS_SIDE_EFFECTS: 0x8, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function(domPropertyConfig) { + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push( + domPropertyConfig.isCustomAttribute + ); + } + + for (var propName in Properties) { + invariant( + !DOMProperty.isStandardName[propName], + 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + + '\'%s\' which has already been injected. You may be accidentally ' + + 'injecting the same DOM property config twice, or you may be ' + + 'injecting two configs that have conflicting property names.', + propName + ); + + DOMProperty.isStandardName[propName] = true; + + DOMProperty.getAttributeName[propName] = + DOMAttributeNames[propName] || propName.toLowerCase(); + + DOMProperty.getPropertyName[propName] = + DOMPropertyNames[propName] || propName; + + var mutationMethod = DOMMutationMethods[propName]; + if (mutationMethod) { + DOMProperty.getMutationMethod[propName] = mutationMethod; + } + + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = + propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE; + DOMProperty.mustUseProperty[propName] = + propConfig & DOMPropertyInjection.MUST_USE_PROPERTY; + DOMProperty.hasBooleanValue[propName] = + propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE; + DOMProperty.hasSideEffects[propName] = + propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS; + + invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot use require using both attribute and property: %s', + propName + ); + invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ); + } + } +}; +var defaultValueCache = {}; + +/** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ +var DOMProperty = { + + /** + * Checks whether a property name is a standard property. + * @type {Object} + */ + isStandardName: {}, + + /** + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} + */ + getAttributeName: {}, + + /** + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} + */ + getPropertyName: {}, + + /** + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} + */ + getMutationMethod: {}, + + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, + + /** + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} + */ + mustUseProperty: {}, + + /** + * Whether the property should be removed when set to a falsey value. + * @type {Object} + */ + hasBooleanValue: {}, + + /** + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. We must ensure that + * the value is only set if it has changed. + * @type {Object} + */ + hasSideEffects: {}, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function(attributeName) { + return DOMProperty._isCustomAttributeFunctions.some( + function(isCustomAttributeFn) { + return isCustomAttributeFn.call(null, attributeName); + } + ); + }, + + /** + * Returns the default property value for a DOM property (i.e., not an + * attribute). Most default values are '' or false, but not all. Worse yet, + * some (in particular, `type`) vary depending on the type of element. + * + * TODO: Is it better to grab all the possible properties when creating an + * element to avoid having to create the same element twice? + */ + getDefaultValueForProperty: function(nodeName, prop) { + var nodeDefaults = defaultValueCache[nodeName]; + var testElement; + if (!nodeDefaults) { + defaultValueCache[nodeName] = nodeDefaults = {}; + } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + + injection: DOMPropertyInjection +}; + +module.exports = DOMProperty; + +},{"./invariant":78}],8:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DOMPropertyOperations + * @typechecks static-only + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var escapeTextForBrowser = require("./escapeTextForBrowser"); +var memoizeStringOnly = require("./memoizeStringOnly"); + +var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { + return escapeTextForBrowser(name) + '="'; +}); + +/** + * Operations for dealing with DOM properties. + */ +var DOMPropertyOperations = { + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName[name]) { + if (value == null || DOMProperty.hasBooleanValue[name] && !value) { + return ''; + } + var attributeName = DOMProperty.getAttributeName[name]; + return processAttributeNameAndPrefix(attributeName) + + escapeTextForBrowser(value) + '"'; + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return processAttributeNameAndPrefix(name) + + escapeTextForBrowser(value) + '"'; + } else { + return null; + } + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function(node, name, value) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, value); + } else if (DOMProperty.mustUseAttribute[name]) { + if (DOMProperty.hasBooleanValue[name] && !value) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + node.setAttribute(DOMProperty.getAttributeName[name], value); + } + } else { + var propName = DOMProperty.getPropertyName[name]; + if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.setAttribute(name, value); + } + }, + + /** + * Deletes the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + */ + deleteValueForProperty: function(node, name) { + if (DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, undefined); + } else if (DOMProperty.mustUseAttribute[name]) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + var propName = DOMProperty.getPropertyName[name]; + node[propName] = DOMProperty.getDefaultValueForProperty( + node.nodeName, + name + ); + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); + } + } + +}; + +module.exports = DOMPropertyOperations; + +},{"./DOMProperty":7,"./escapeTextForBrowser":67,"./memoizeStringOnly":83}],9:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule Danger + */ + +/*jslint evil: true, sub: true */ + +"use strict"; + +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var throwIf = require("./throwIf"); + +var DOM_UNSUPPORTED; +var NO_MARKUP_PARENT; +var NO_MULTI_MARKUP; +if (true) { + DOM_UNSUPPORTED = + 'You may not insert markup into the document while you are in a worker ' + + 'thread. It\'s not you, it\'s me. This is likely the fault of the ' + + 'framework. Please report this immediately.'; + NO_MARKUP_PARENT = + 'You have attempted to inject markup without a suitable parent. This is ' + + 'likely the fault of the framework - please report immediately.'; + NO_MULTI_MARKUP = + 'The framework has attempted to either insert zero or multiple markup ' + + 'roots into a single location when it should not. This is a serious ' + + 'error - a fault of the framework - please report immediately.'; +} + +var validateMarkupParams; +if (true) { + validateMarkupParams = function(parentNode, markup) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + throwIf(!parentNode || !parentNode.tagName, NO_MARKUP_PARENT); + throwIf(!markup, NO_MULTI_MARKUP); + }; +} + +/** + * Dummy container used to render all markup. + */ +var dummyNode = ExecutionEnvironment.canUseDOM ? + document.createElement('div') : + null; + +/** + * Some browsers cannot use `innerHTML` to render certain elements standalone, + * so we wrap them, render the wrapped nodes, then extract the desired node. + */ +var markupWrap = { + 'option': [1, ''], + 'legend': [1, '
', '
'], + 'area': [1, '', ''], + 'param': [1, '', ''], + 'thead': [1, '', '
'], + 'tr': [2, '', '
'], + 'col': [2, '', '
'], + 'td': [3, '', '
'] +}; +markupWrap['optgroup'] = markupWrap['option']; +markupWrap['tbody'] = markupWrap['thead']; +markupWrap['tfoot'] = markupWrap['thead']; +markupWrap['colgroup'] = markupWrap['thead']; +markupWrap['caption'] = markupWrap['thead']; +markupWrap['th'] = markupWrap['td']; + +/** + * In IE8, certain elements cannot render alone, so wrap all elements. + */ +var defaultWrap = [1, '?
', '
']; + +/** + * Feature detection, remove wraps that are unnecessary for the current browser. + */ +if (dummyNode) { + for (var nodeName in markupWrap) { + if (!markupWrap.hasOwnProperty(nodeName)) { + continue; + } + dummyNode.innerHTML = '<' + nodeName + '>'; + if (dummyNode.firstChild) { + markupWrap[nodeName] = null; + } + } + dummyNode.innerHTML = ''; + if (dummyNode.firstChild) { + defaultWrap = null; + } +} + +/** + * Renders markup into nodes. The returned HTMLCollection is live and should be + * used immediately (or at least before the next invocation to `renderMarkup`). + * + * NOTE: Extracting the `nodeName` does not require a regular expression match + * because we make assumptions about React-generated markup (i.e. there are no + * spaces surrounding the opening tag and there is at least one attribute). + * @see http://jsperf.com/extract-nodename + * + * @param {string} markup + * @return {*} An HTMLCollection. + */ +function renderMarkup(markup) { + var node = dummyNode; + var nodeName = markup.substring(1, markup.indexOf(' ')); + + var wrap = markupWrap[nodeName.toLowerCase()] || defaultWrap; + if (wrap) { + node.innerHTML = wrap[1] + markup + wrap[2]; + + var wrapDepth = wrap[0]; + while (wrapDepth--) { + node = node.lastChild; + } + } else { + node.innerHTML = markup; + } + return node.childNodes; +} + +/** + * Inserts node after 'after'. If 'after' is null, inserts it after nothing, + * which is inserting it at the beginning. + * + * @param {Element} elem Parent element. + * @param {Element} insert Element to insert. + * @param {Element} after Element to insert after. + * @return {Element} Element that was inserted. + */ +function insertNodeAfterNode(elem, insert, after) { + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + if (after) { + if (after.nextSibling) { + return elem.insertBefore(insert, after.nextSibling); + } else { + return elem.appendChild(insert); + } + } else { + return elem.insertBefore(insert, elem.firstChild); + } +} + +/** + * Slow: Should only be used when it is known there are a few (or one) element + * in the node list. + * @param {Element} parentRootDomNode Parent element. + * @param {HTMLCollection} htmlCollection HTMLCollection to insert. + * @param {Element} after Element to insert the node list after. + */ +function inefficientlyInsertHTMLCollectionAfter( + parentRootDomNode, + htmlCollection, + after) { + + if (true) { + throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED); + } + var ret; + var originalLength = htmlCollection.length; + // Access htmlCollection[0] because htmlCollection shrinks as we remove items. + // `insertNodeAfterNode` will remove items from the htmlCollection. + for (var i = 0; i < originalLength; i++) { + ret = + insertNodeAfterNode(parentRootDomNode, htmlCollection[0], ret || after); + } +} + +/** + * Super-dangerously inserts markup into existing DOM structure. Seriously, you + * don't want to use this module unless you are building a framework. This + * requires that the markup that you are inserting represents the root of a + * tree. We do not support the case where there `markup` represents several + * roots. + * + * @param {Element} parentNode Parent DOM element. + * @param {string} markup Markup to dangerously insert. + * @param {number} index Position to insert markup at. + */ +function dangerouslyInsertMarkupAt(parentNode, markup, index) { + if (true) { + validateMarkupParams(parentNode, markup); + } + var htmlCollection = renderMarkup(markup); + var afterNode = index ? parentNode.childNodes[index - 1] : null; + inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode); +} + +/** + * Replaces a node with a string of markup at its current position within its + * parent. `childNode` must be in the document (or at least within a parent + * node). The string of markup must represent a tree of markup with a single + * root. + * + * @param {Element} childNode Child node to replace. + * @param {string} markup Markup to dangerously replace child with. + */ +function dangerouslyReplaceNodeWithMarkup(childNode, markup) { + var parentNode = childNode.parentNode; + if (true) { + validateMarkupParams(parentNode, markup); + } + var htmlCollection = renderMarkup(markup); + if (true) { + throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP); + } + parentNode.replaceChild(htmlCollection[0], childNode); +} + +var Danger = { + dangerouslyInsertMarkupAt: dangerouslyInsertMarkupAt, + dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup +}; + +module.exports = Danger; + +},{"./ExecutionEnvironment":19,"./throwIf":89}],10:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DefaultDOMPropertyConfig + */ + +"use strict"; + +var DOMProperty = require("./DOMProperty"); + +var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE; +var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; +var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE; +var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS; + +var DefaultDOMPropertyConfig = { + isCustomAttribute: RegExp.prototype.test.bind( + /^(data|aria)-[a-z_][a-z\d_.\-]*$/ + ), + Properties: { + /** + * Standard Properties + */ + accessKey: null, + accept: null, + action: null, + ajaxify: MUST_USE_ATTRIBUTE, + allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + allowTransparency: MUST_USE_ATTRIBUTE, + alt: null, + autoComplete: null, + autoFocus: HAS_BOOLEAN_VALUE, + autoPlay: HAS_BOOLEAN_VALUE, + cellPadding: null, + cellSpacing: null, + checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + className: MUST_USE_PROPERTY, + colSpan: null, + contentEditable: null, + contextMenu: MUST_USE_ATTRIBUTE, + controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + data: null, // For `` acts as `src`. + dateTime: MUST_USE_ATTRIBUTE, + dir: null, + disabled: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + draggable: null, + encType: null, + frameBorder: MUST_USE_ATTRIBUTE, + height: MUST_USE_ATTRIBUTE, + hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, + href: null, + htmlFor: null, + icon: null, + id: MUST_USE_PROPERTY, + label: null, + lang: null, + list: null, + max: null, + maxLength: MUST_USE_ATTRIBUTE, + method: null, + min: null, + multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + name: null, + pattern: null, + poster: null, + preload: null, + placeholder: null, + radioGroup: null, + rel: null, + readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + required: HAS_BOOLEAN_VALUE, + role: MUST_USE_ATTRIBUTE, + scrollLeft: MUST_USE_PROPERTY, + scrollTop: MUST_USE_PROPERTY, + selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, + size: null, + spellCheck: null, + src: null, + step: null, + style: null, + tabIndex: null, + target: null, + title: null, + type: null, + value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS, + width: MUST_USE_ATTRIBUTE, + wmode: MUST_USE_ATTRIBUTE, + /** + * SVG Properties + */ + cx: MUST_USE_PROPERTY, + cy: MUST_USE_PROPERTY, + d: MUST_USE_PROPERTY, + fill: MUST_USE_PROPERTY, + fx: MUST_USE_PROPERTY, + fy: MUST_USE_PROPERTY, + points: MUST_USE_PROPERTY, + r: MUST_USE_PROPERTY, + stroke: MUST_USE_PROPERTY, + strokeLinecap: MUST_USE_PROPERTY, + strokeWidth: MUST_USE_PROPERTY, + transform: MUST_USE_PROPERTY, + x: MUST_USE_PROPERTY, + x1: MUST_USE_PROPERTY, + x2: MUST_USE_PROPERTY, + version: MUST_USE_PROPERTY, + viewBox: MUST_USE_PROPERTY, + y: MUST_USE_PROPERTY, + y1: MUST_USE_PROPERTY, + y2: MUST_USE_PROPERTY, + spreadMethod: MUST_USE_PROPERTY, + offset: MUST_USE_PROPERTY, + stopColor: MUST_USE_PROPERTY, + stopOpacity: MUST_USE_PROPERTY, + gradientUnits: MUST_USE_PROPERTY, + gradientTransform: MUST_USE_PROPERTY + }, + DOMAttributeNames: { + className: 'class', + htmlFor: 'for', + strokeLinecap: 'stroke-linecap', + strokeWidth: 'stroke-width', + stopColor: 'stop-color', + stopOpacity: 'stop-opacity' + }, + DOMPropertyNames: { + autoComplete: 'autocomplete', + autoFocus: 'autofocus', + autoPlay: 'autoplay', + encType: 'enctype', + radioGroup: 'radiogroup', + spellCheck: 'spellcheck' + }, + DOMMutationMethods: { + /** + * Setting `className` to null may cause it to be set to the string "null". + * + * @param {DOMElement} node + * @param {*} value + */ + className: function(node, value) { + node.className = value || ''; + } + } +}; + +module.exports = DefaultDOMPropertyConfig; + +},{"./DOMProperty":7}],11:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule DefaultEventPluginOrder + */ + +"use strict"; + + var keyOf = require("./keyOf"); + +/** + * Module that is injectable into `EventPluginHub`, that specifies a + * deterministic ordering of `EventPlugin`s. A convenient way to reason about + * plugins, without having to package every one of them. This is better than + * having plugins be ordered in the same order that they are injected because + * that ordering would be influenced by the packaging order. + * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that + * preventing default on events is convenient in `SimpleEventPlugin` handlers. + */ +var DefaultEventPluginOrder = [ + keyOf({ResponderEventPlugin: null}), + keyOf({SimpleEventPlugin: null}), + keyOf({TapEventPlugin: null}), + keyOf({EnterLeaveEventPlugin: null}), + keyOf({ChangeEventPlugin: null}), + keyOf({AnalyticsEventPlugin: null}), + keyOf({MobileSafariClickEventPlugin: null}) +]; + +module.exports = DefaultEventPluginOrder; + +},{"./keyOf":82}],12:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EnterLeaveEventPlugin + * @typechecks static-only + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); +var SyntheticMouseEvent = require("./SyntheticMouseEvent"); + +var ReactMount = require("./ReactMount"); +var keyOf = require("./keyOf"); + +var topLevelTypes = EventConstants.topLevelTypes; +var getFirstReactDOM = ReactMount.getFirstReactDOM; + +var eventTypes = { + mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, + mouseLeave: {registrationName: keyOf({onMouseLeave: null})} +}; + +var EnterLeaveEventPlugin = { + + eventTypes: eventTypes, + + /** + * For almost every interaction we care about, there will be both a top-level + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that + * we do not extract duplicate events. However, moving the mouse into the + * browser from outside will not fire a `mouseout` event. In this case, we use + * the `mouseover` top-level event. + * + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + if (topLevelType === topLevelTypes.topMouseOver && + (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return null; + } + if (topLevelType !== topLevelTypes.topMouseOut && + topLevelType !== topLevelTypes.topMouseOver) { + // Must not be a mouse in or mouse out - ignoring. + return null; + } + + var from, to; + if (topLevelType === topLevelTypes.topMouseOut) { + from = topLevelTarget; + to = + getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || + ExecutionEnvironment.global; + } else { + from = ExecutionEnvironment.global; + to = topLevelTarget; + } + + if (from === to) { + // Nothing pertains to our managed components. + return null; + } + + var fromID = from ? ReactMount.getID(from) : ''; + var toID = to ? ReactMount.getID(to) : ''; + + var leave = SyntheticMouseEvent.getPooled( + eventTypes.mouseLeave, + fromID, + nativeEvent + ); + var enter = SyntheticMouseEvent.getPooled( + eventTypes.mouseEnter, + toID, + nativeEvent + ); + + EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); + return [leave, enter]; + } + +}; + +module.exports = EnterLeaveEventPlugin; + +})() +},{"./EventConstants":13,"./EventPropagators":18,"./ExecutionEnvironment":19,"./ReactMount":39,"./SyntheticMouseEvent":54,"./keyOf":82}],13:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventConstants + */ + +"use strict"; + +var keyMirror = require("./keyMirror"); + +var PropagationPhases = keyMirror({bubbled: null, captured: null}); + +/** + * Types of raw signals from the browser caught at the top level. + */ +var topLevelTypes = keyMirror({ + topBlur: null, + topChange: null, + topClick: null, + topDOMCharacterDataModified: null, + topDoubleClick: null, + topDrag: null, + topDragEnd: null, + topDragEnter: null, + topDragExit: null, + topDragLeave: null, + topDragOver: null, + topDragStart: null, + topDrop: null, + topFocus: null, + topInput: null, + topKeyDown: null, + topKeyPress: null, + topKeyUp: null, + topMouseDown: null, + topMouseMove: null, + topMouseOut: null, + topMouseOver: null, + topMouseUp: null, + topScroll: null, + topSelectionChange: null, + topSubmit: null, + topTouchCancel: null, + topTouchEnd: null, + topTouchMove: null, + topTouchStart: null, + topWheel: null +}); + +var EventConstants = { + topLevelTypes: topLevelTypes, + PropagationPhases: PropagationPhases +}; + +module.exports = EventConstants; + +},{"./keyMirror":81}],14:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventListener + */ + +/** + * Upstream version of event listener. Does not take into account specific + * nature of platform. + */ +var EventListener = { + /** + * Listens to bubbled events on a DOM node. + * + * @param {Element} el DOM element to register listener on. + * @param {string} handlerBaseName 'click'/'mouseover' + * @param {Function!} cb Callback function + */ + listen: function(el, handlerBaseName, cb) { + if (el.addEventListener) { + el.addEventListener(handlerBaseName, cb, false); + } else if (el.attachEvent) { + el.attachEvent('on' + handlerBaseName, cb); + } + }, + + /** + * Listens to captured events on a DOM node. + * + * @see `EventListener.listen` for params. + * @throws Exception if addEventListener is not supported. + */ + capture: function(el, handlerBaseName, cb) { + if (!el.addEventListener) { + if (true) { + console.error( + 'You are attempting to use addEventlistener ' + + 'in a browser that does not support it support it.' + + 'This likely means that you will not receive events that ' + + 'your application relies on (such as scroll).'); + } + return; + } else { + el.addEventListener(handlerBaseName, cb, true); + } + } +}; + +module.exports = EventListener; + +},{}],15:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPluginHub + */ + +"use strict"; + +var CallbackRegistry = require("./CallbackRegistry"); +var EventPluginRegistry = require("./EventPluginRegistry"); +var EventPluginUtils = require("./EventPluginUtils"); +var EventPropagators = require("./EventPropagators"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var invariant = require("./invariant"); + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + var executeDispatch = EventPluginUtils.executeDispatch; + // Plugins can provide custom behavior when dispatching events. + var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event); + if (PluginModule && PluginModule.executeDispatch) { + executeDispatch = PluginModule.executeDispatch; + } + EventPluginUtils.executeDispatchesInOrder(event, executeDispatch); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ +var EventPluginHub = { + + /** + * Methods for injecting dependencies. + */ + injection: { + + /** + * @param {object} InjectedInstanceHandle + * @public + */ + injectInstanceHandle: EventPropagators.injection.injectInstanceHandle, + + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName + + }, + + registrationNames: EventPluginRegistry.registrationNames, + + putListener: CallbackRegistry.putListener, + + getListener: CallbackRegistry.getListener, + + deleteListener: CallbackRegistry.deleteListener, + + deleteAllListeners: CallbackRegistry.deleteAllListeners, + + /** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @internal + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + var events; + var plugins = EventPluginRegistry.plugins; + for (var i = 0, l = plugins.length; i < l; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent + ); + if (extractedEvents) { + events = accumulate(events, extractedEvents); + } + } + } + return events; + }, + + /** + * Enqueues a synthetic event that should be dispatched when + * `processEventQueue` is invoked. + * + * @param {*} events An accumulation of synthetic events. + * @internal + */ + enqueueEvents: function(events) { + if (events) { + eventQueue = accumulate(eventQueue, events); + } + }, + + /** + * Dispatches all synthetic events on the event queue. + * + * @internal + */ + processEventQueue: function() { + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + forEachAccumulated(processingEventQueue, executeDispatchesAndRelease); + invariant( + !eventQueue, + 'processEventQueue(): Additional events were enqueued while processing ' + + 'an event queue. Support for this has not yet been implemented.' + ); + } + +}; + +if (ExecutionEnvironment.canUseDOM) { + window.EventPluginHub = EventPluginHub; +} + +module.exports = EventPluginHub; + +},{"./CallbackRegistry":4,"./EventPluginRegistry":16,"./EventPluginUtils":17,"./EventPropagators":18,"./ExecutionEnvironment":19,"./accumulate":61,"./forEachAccumulated":70,"./invariant":78}],16:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPluginRegistry + * @typechecks static-only + */ + +"use strict"; + +var invariant = require("./invariant"); + +/** + * Injectable ordering of event plugins. + */ +var EventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!EventPluginOrder) { + // Wait until an `EventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var PluginModule = namesToPlugins[pluginName]; + var pluginIndex = EventPluginOrder.indexOf(pluginName); + invariant( + pluginIndex > -1, + 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + + 'the plugin ordering, `%s`.', + pluginName + ); + if (EventPluginRegistry.plugins[pluginIndex]) { + continue; + } + invariant( + PluginModule.extractEvents, + 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + + 'method, but `%s` does not.', + pluginName + ); + EventPluginRegistry.plugins[pluginIndex] = PluginModule; + var publishedEvents = PluginModule.eventTypes; + for (var eventName in publishedEvents) { + invariant( + publishEventForPlugin(publishedEvents[eventName], PluginModule), + 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', + eventName, + pluginName + ); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, PluginModule) { + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, PluginModule); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, PluginModule); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events and + * can be used with `EventPluginHub.putListener` to register listeners. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, PluginModule) { + invariant( + !EventPluginRegistry.registrationNames[registrationName], + 'EventPluginHub: More than one plugin attempted to publish the same ' + + 'registration name, `%s`.', + registrationName + ); + EventPluginRegistry.registrationNames[registrationName] = PluginModule; + EventPluginRegistry.registrationNamesKeys.push(registrationName); +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ +var EventPluginRegistry = { + + /** + * Ordered list of injected plugins. + */ + plugins: [], + + /** + * Mapping from registration names to plugin modules. + */ + registrationNames: {}, + + /** + * The keys of `registrationNames`. + */ + registrationNamesKeys: [], + + /** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ + injectEventPluginOrder: function(InjectedEventPluginOrder) { + invariant( + !EventPluginOrder, + 'EventPluginRegistry: Cannot inject event plugin ordering more than once.' + ); + // Clone the ordering so it cannot be dynamically mutated. + EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); + recomputePluginOrdering(); + }, + + /** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var PluginModule = injectedNamesToPlugins[pluginName]; + if (namesToPlugins[pluginName] !== PluginModule) { + invariant( + !namesToPlugins[pluginName], + 'EventPluginRegistry: Cannot inject two different event plugins ' + + 'using the same name, `%s`.', + pluginName + ); + namesToPlugins[pluginName] = PluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } + }, + + /** + * Looks up the plugin for the supplied event. + * + * @param {object} event A synthetic event. + * @return {?object} The plugin that created the supplied event. + * @internal + */ + getPluginModuleForEvent: function(event) { + var dispatchConfig = event.dispatchConfig; + if (dispatchConfig.registrationName) { + return EventPluginRegistry.registrationNames[ + dispatchConfig.registrationName + ] || null; + } + for (var phase in dispatchConfig.phasedRegistrationNames) { + if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { + continue; + } + var PluginModule = EventPluginRegistry.registrationNames[ + dispatchConfig.phasedRegistrationNames[phase] + ]; + if (PluginModule) { + return PluginModule; + } + } + return null; + }, + + /** + * Exposed for unit testing. + * @private + */ + _resetEventPlugins: function() { + EventPluginOrder = null; + for (var pluginName in namesToPlugins) { + if (namesToPlugins.hasOwnProperty(pluginName)) { + delete namesToPlugins[pluginName]; + } + } + EventPluginRegistry.plugins.length = 0; + var registrationNames = EventPluginRegistry.registrationNames; + for (var registrationName in registrationNames) { + if (registrationNames.hasOwnProperty(registrationName)) { + delete registrationNames[registrationName]; + } + } + EventPluginRegistry.registrationNamesKeys.length = 0; + } + +}; + +module.exports = EventPluginRegistry; + +},{"./invariant":78}],17:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPluginUtils + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); + +var invariant = require("./invariant"); + +var topLevelTypes = EventConstants.topLevelTypes; + +function isEndish(topLevelType) { + return topLevelType === topLevelTypes.topMouseUp || + topLevelType === topLevelTypes.topTouchEnd || + topLevelType === topLevelTypes.topTouchCancel; +} + +function isMoveish(topLevelType) { + return topLevelType === topLevelTypes.topMouseMove || + topLevelType === topLevelTypes.topTouchMove; +} +function isStartish(topLevelType) { + return topLevelType === topLevelTypes.topMouseDown || + topLevelType === topLevelTypes.topTouchStart; +} + +var validateEventDispatches; +if (true) { + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + + var listenersIsArr = Array.isArray(dispatchListeners); + var idsIsArr = Array.isArray(dispatchIDs); + var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; + var listenersLen = listenersIsArr ? + dispatchListeners.length : + dispatchListeners ? 1 : 0; + + invariant( + idsIsArr === listenersIsArr && IDsLen === listenersLen, + 'EventPluginUtils: Invalid `event`.' + ); + }; +} + +/** + * Invokes `cb(event, listener, id)`. Avoids using call if no scope is + * provided. The `(listener,id)` pair effectively forms the "dispatch" but are + * kept separate to conserve memory. + */ +function forEachEventDispatch(event, cb) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if (true) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + cb(event, dispatchListeners[i], dispatchIDs[i]); + } + } else if (dispatchListeners) { + cb(event, dispatchListeners, dispatchIDs); + } +} + +/** + * Default implementation of PluginModule.executeDispatch(). + * @param {SyntheticEvent} SyntheticEvent to handle + * @param {function} Application-level callback + * @param {string} domID DOM id to pass to the callback. + */ +function executeDispatch(event, listener, domID) { + listener(event, domID); +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event, executeDispatch) { + forEachEventDispatch(event, executeDispatch); + event._dispatchListeners = null; + event._dispatchIDs = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return id of the first dispatch execution who's listener returns true, or + * null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrue(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if (true) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchIDs[i])) { + return dispatchIDs[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchIDs)) { + return dispatchIDs; + } + } + return null; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + if (true) { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchID = event._dispatchIDs; + invariant( + !Array.isArray(dispatchListener), + 'executeDirectDispatch(...): Invalid `event`.' + ); + var res = dispatchListener ? + dispatchListener(event, dispatchID) : + null; + event._dispatchListeners = null; + event._dispatchIDs = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {bool} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * General utilities that are useful in creating custom Event Plugins. + */ +var EventPluginUtils = { + isEndish: isEndish, + isMoveish: isMoveish, + isStartish: isStartish, + executeDispatchesInOrder: executeDispatchesInOrder, + executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, + executeDirectDispatch: executeDirectDispatch, + hasDispatches: hasDispatches, + executeDispatch: executeDispatch +}; + +module.exports = EventPluginUtils; + +},{"./EventConstants":13,"./invariant":78}],18:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule EventPropagators + */ + +"use strict"; + +var CallbackRegistry = require("./CallbackRegistry"); +var EventConstants = require("./EventConstants"); + +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var getListener = CallbackRegistry.getListener; +var PropagationPhases = EventConstants.PropagationPhases; + +/** + * Injected dependencies: + */ + +/** + * - `InstanceHandle`: [required] Module that performs logical traversals of DOM + * hierarchy given ids of the logical DOM elements involved. + */ +var injection = { + InstanceHandle: null, + injectInstanceHandle: function(InjectedInstanceHandle) { + injection.InstanceHandle = InjectedInstanceHandle; + if (true) { + injection.validate(); + } + }, + validate: function() { + var invalid = !injection.InstanceHandle|| + !injection.InstanceHandle.traverseTwoPhase || + !injection.InstanceHandle.traverseEnterLeave; + if (invalid) { + throw new Error('InstanceHandle not injected before use!'); + } + } +}; + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(id, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(id, registrationName); +} + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(domID, upwards, event) { + if (true) { + if (!domID) { + throw new Error('Dispatching id must not be null'); + } + injection.validate(); + } + var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; + var listener = listenerAtPhase(domID, event, phase); + if (listener) { + event._dispatchListeners = accumulate(event._dispatchListeners, listener); + event._dispatchIDs = accumulate(event._dispatchIDs, domID); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We can not perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + injection.InstanceHandle.traverseTwoPhase( + event.dispatchMarker, + accumulateDirectionalDispatches, + event + ); + } +} + + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(id, ignoredDirection, event) { + if (event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(id, registrationName); + if (listener) { + event._dispatchListeners = accumulate(event._dispatchListeners, listener); + event._dispatchIDs = accumulate(event._dispatchIDs, id); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event.dispatchMarker, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + if (true) { + injection.validate(); + } + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { + if (true) { + injection.validate(); + } + injection.InstanceHandle.traverseEnterLeave( + fromID, + toID, + accumulateDispatches, + leave, + enter + ); +} + + +function accumulateDirectDispatches(events) { + if (true) { + injection.validate(); + } + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + + + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing event a + * single one. + * + * @constructor EventPropagators + */ +var EventPropagators = { + accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, + accumulateDirectDispatches: accumulateDirectDispatches, + accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, + injection: injection +}; + +module.exports = EventPropagators; + +},{"./CallbackRegistry":4,"./EventConstants":13,"./accumulate":61,"./forEachAccumulated":70}],19:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ExecutionEnvironment + */ + +/*jslint evil: true */ + +"use strict"; + +var canUseDOM = typeof window !== 'undefined'; + +/** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ +var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + isInWorker: !canUseDOM, // For now, this is true - might change in the future. + + global: new Function('return this;')() + +}; + +module.exports = ExecutionEnvironment; + +})() +},{}],20:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule MobileSafariClickEventPlugin + * @typechecks static-only + */ + +"use strict"; + +var EventConstants = require("./EventConstants"); + +var emptyFunction = require("./emptyFunction"); + +var topLevelTypes = EventConstants.topLevelTypes; + +/** + * Mobile Safari does not fire properly bubble click events on non-interactive + * elements, which means delegated click listeners do not fire. The workaround + * for this bug involves attaching an empty click listener on the target node. + * + * This particular plugin works around the bug by attaching an empty click + * listener on `touchstart` (which does fire on every element). + */ +var MobileSafariClickEventPlugin = { + + eventTypes: null, + + /** + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + if (topLevelType === topLevelTypes.topTouchStart) { + var target = nativeEvent.target; + if (target && !target.onclick) { + target.onclick = emptyFunction; + } + } + } + +}; + +module.exports = MobileSafariClickEventPlugin; + +},{"./EventConstants":13,"./emptyFunction":66}],21:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule PooledClass + */ + +"use strict"; + +/** + * Static poolers. Several custom versions for each potential number of + * arguments. A completely generic pooler is easy to implement, but would + * require accessing the `arguments` object. In each of these, `this` refers to + * the Class itself, not an instance. If any others are needed, simply add them + * here, or in their own files. + */ +var oneArgumentPooler = function(copyFieldsFrom) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, copyFieldsFrom); + return instance; + } else { + return new Klass(copyFieldsFrom); + } +}; + +var twoArgumentPooler = function(a1, a2) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2); + return instance; + } else { + return new Klass(a1, a2); + } +}; + +var threeArgumentPooler = function(a1, a2, a3) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3); + return instance; + } else { + return new Klass(a1, a2, a3); + } +}; + +var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4, a5); + return instance; + } else { + return new Klass(a1, a2, a3, a4, a5); + } +}; + +var standardReleaser = function(instance) { + var Klass = this; + if (instance.destructor) { + instance.destructor(); + } + if (Klass.instancePool.length < Klass.poolSize) { + Klass.instancePool.push(instance); + } +}; + +var DEFAULT_POOL_SIZE = 10; +var DEFAULT_POOLER = oneArgumentPooler; + +/** + * Augments `CopyConstructor` to be a poolable class, augmenting only the class + * itself (statically) not adding any prototypical fields. Any CopyConstructor + * you give this may have a `poolSize` property, and will look for a + * prototypical `destructor` on instances (optional). + * + * @param {Function} CopyConstructor Constructor that can be used to reset. + * @param {Function} pooler Customizable pooler. + */ +var addPoolingTo = function(CopyConstructor, pooler) { + var NewKlass = CopyConstructor; + NewKlass.instancePool = []; + NewKlass.getPooled = pooler || DEFAULT_POOLER; + if (!NewKlass.poolSize) { + NewKlass.poolSize = DEFAULT_POOL_SIZE; + } + NewKlass.release = standardReleaser; + return NewKlass; +}; + +var PooledClass = { + addPoolingTo: addPoolingTo, + oneArgumentPooler: oneArgumentPooler, + twoArgumentPooler: twoArgumentPooler, + threeArgumentPooler: threeArgumentPooler, + fiveArgumentPooler: fiveArgumentPooler +}; + +module.exports = PooledClass; + +},{}],22:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule React + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactComponent = require("./ReactComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactMount = require("./ReactMount"); +var ReactPropTypes = require("./ReactPropTypes"); +var ReactServerRendering = require("./ReactServerRendering"); + +var ReactDefaultInjection = require("./ReactDefaultInjection"); + +ReactDefaultInjection.inject(); + +var React = { + DOM: ReactDOM, + PropTypes: ReactPropTypes, + initializeTouchEvents: function(shouldUseTouch) { + ReactMount.useTouchEvents = shouldUseTouch; + }, + autoBind: ReactCompositeComponent.autoBind, + createClass: ReactCompositeComponent.createClass, + constructAndRenderComponent: ReactMount.constructAndRenderComponent, + constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID, + renderComponent: ReactMount.renderComponent, + renderComponentToString: ReactServerRendering.renderComponentToString, + unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, + isValidComponent: ReactComponent.isValidComponent +}; + +module.exports = React; + +},{"./ReactComponent":23,"./ReactCompositeComponent":24,"./ReactDOM":26,"./ReactDefaultInjection":33,"./ReactMount":39,"./ReactPropTypes":45,"./ReactServerRendering":47}],23:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactComponent + */ + +/*jslint evil: true */ + +"use strict"; + +var getReactRootElementInContainer = require("./getReactRootElementInContainer"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactDOMIDOperations = require("./ReactDOMIDOperations"); +var ReactMarkupChecksum = require("./ReactMarkupChecksum"); +var ReactMount = require("./ReactMount"); +var ReactOwner = require("./ReactOwner"); +var ReactReconcileTransaction = require("./ReactReconcileTransaction"); +var ReactUpdates = require("./ReactUpdates"); + +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); + +/** + * Prop key that references a component's owner. + * @private + */ +var OWNER = '{owner}'; + +/** + * Props key that determines if a component's key was already validated. + * @private + */ +var IS_KEY_VALIDATED = '{is.key.validated}'; + +/** + * Every React component is in one of these life cycles. + */ +var ComponentLifeCycle = keyMirror({ + /** + * Mounted components have a DOM node representation and are capable of + * receiving new props. + */ + MOUNTED: null, + /** + * Unmounted components are inactive and cannot receive new props. + */ + UNMOUNTED: null +}); + +/** + * Warn if there's no key explicitly set on dynamic arrays of children. + * This allows us to keep track of children between updates. + */ + +var ownerHasWarned = {}; + +/** + * 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 + * have a "key" property assigned to it. + * + * @internal + * @param {ReactComponent} component Component that requires a key. + */ +function validateExplicitKey(component) { + if (component[IS_KEY_VALIDATED] || component.props.key != null) { + return; + } + component[IS_KEY_VALIDATED] = true; + + // We can't provide friendly warnings for top level components. + if (!ReactCurrentOwner.current) { + return; + } + + // Name of the component whose render method tried to pass children. + var currentName = ReactCurrentOwner.current.constructor.displayName; + if (ownerHasWarned.hasOwnProperty(currentName)) { + return; + } + ownerHasWarned[currentName] = true; + + var message = 'Each child in an array should have a unique "key" prop. ' + + 'Check the render method of ' + currentName + '.'; + if (!component.isOwnedBy(ReactCurrentOwner.current)) { + // Name of the component that originally created this child. + var childOwnerName = + component.props[OWNER] && component.props[OWNER].constructor.displayName; + + // Usually the current owner is the offender, but if it accepts + // children as a property, it may be the creator of the child that's + // responsible for assigning it a key. + message += ' It was passed a child from ' + childOwnerName + '.'; + } + + console.warn(message); +} + +/** + * 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. + * + * @internal + * @param {*} component Statically passed child of any type. + * @return {boolean} + */ +function validateChildKeys(component) { + if (Array.isArray(component)) { + for (var i = 0; i < component.length; i++) { + var child = component[i]; + if (ReactComponent.isValidComponent(child)) { + validateExplicitKey(child); + } + } + } else if (ReactComponent.isValidComponent(component)) { + // This component was passed in a valid location. + component[IS_KEY_VALIDATED] = true; + } +} + +/** + * Components are the basic units of composition in React. + * + * Every component accepts a set of keyed input parameters known as "props" that + * are initialized by the constructor. Once a component is mounted, the props + * can be mutated using `setProps` or `replaceProps`. + * + * Every component is capable of the following operations: + * + * `mountComponent` + * Initializes the component, renders markup, and registers event listeners. + * + * `receiveProps` + * Updates the rendered DOM nodes given a new set of props. + * + * `unmountComponent` + * Releases any resources allocated by this component. + * + * Components can also be "owned" by other components. Being owned by another + * component means being constructed by that component. This is different from + * being the child of a component, which means having a DOM representation that + * is a child of the DOM representation of that component. + * + * @class ReactComponent + */ +var ReactComponent = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid component. + * @final + */ + isValidComponent: function(object) { + return !!( + object && + typeof object.mountComponentIntoNode === 'function' && + typeof object.receiveProps === 'function' + ); + }, + + /** + * 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, + + /** + * React references `ReactDOMIDOperations` using this property in order to + * allow dependency injection. + * + * @internal + */ + DOMIDOperations: ReactDOMIDOperations, + + /** + * React references `ReactReconcileTransaction` using this property in order + * to allow dependency injection. + * + * @internal + */ + ReactReconcileTransaction: ReactReconcileTransaction, + + /** + * @param {object} DOMIDOperations + * @final + */ + setDOMOperations: function(DOMIDOperations) { + ReactComponent.DOMIDOperations = DOMIDOperations; + }, + + /** + * @param {Transaction} ReactReconcileTransaction + * @final + */ + setReactReconcileTransaction: function(ReactReconcileTransaction) { + ReactComponent.ReactReconcileTransaction = ReactReconcileTransaction; + }, + + /** + * Base functionality for every ReactComponent constructor. + * + * @lends {ReactComponent.prototype} + */ + Mixin: { + + /** + * Checks whether or not this component is mounted. + * + * @return {boolean} True if mounted, false otherwise. + * @final + * @protected + */ + isMounted: function() { + return this._lifeCycleState === ComponentLifeCycle.MOUNTED; + }, + + /** + * Returns the DOM node rendered by this component. + * + * @return {DOMElement} The root node of this component. + * @final + * @protected + */ + getDOMNode: function() { + invariant( + this.isMounted(), + 'getDOMNode(): A component must be mounted to have a DOM node.' + ); + return ReactMount.getNode(this._rootNodeID); + }, + + /** + * Sets a subset of the props. + * + * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @public + */ + setProps: function(partialProps, callback) { + // Merge with `_pendingProps` if it exists, otherwise with existing props. + this.replaceProps( + merge(this._pendingProps || this.props, partialProps), + callback + ); + }, + + /** + * Replaces all of the props. + * + * @param {object} props New props. + * @param {?function} callback Called after props are updated. + * @final + * @public + */ + replaceProps: function(props, callback) { + invariant( + !this.props[OWNER], + 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + + 'component with an owner. This is an anti-pattern since props will ' + + 'get reactively updated when rendered. Instead, change the owner\'s ' + + '`render` method to pass the correct value as props to the component ' + + 'where it is created.' + ); + this._pendingProps = props; + ReactUpdates.enqueueUpdate(this, callback); + }, + + /** + * Base constructor for all React component. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.construct.call(this, ...)`. + * + * @param {?object} initialProps + * @param {*} children + * @internal + */ + construct: function(initialProps, children) { + this.props = initialProps || {}; + // Record the component responsible for creating this component. + this.props[OWNER] = ReactCurrentOwner.current; + // All components start unmounted. + this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; + + this._pendingProps = null; + this._pendingCallbacks = null; + + // Children can be more than one argument + var childrenLength = arguments.length - 1; + if (childrenLength === 1) { + if (true) { + validateChildKeys(children); + } + this.props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + if (true) { + validateChildKeys(arguments[i + 1]); + } + childArray[i] = arguments[i + 1]; + } + this.props.children = childArray; + } + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * NOTE: This does not insert any nodes into the DOM. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.mountComponent.call(this, ...)`. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @internal + */ + mountComponent: function(rootID, transaction) { + invariant( + !this.isMounted(), + 'mountComponent(%s, ...): Can only mount an unmounted component.', + rootID + ); + var props = this.props; + if (props.ref != null) { + ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]); + } + this._rootNodeID = rootID; + this._lifeCycleState = ComponentLifeCycle.MOUNTED; + // Effectively: return ''; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * NOTE: This does not remove any nodes from the DOM. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.unmountComponent.call(this)`. + * + * @internal + */ + unmountComponent: function() { + invariant( + this.isMounted(), + 'unmountComponent(): Can only unmount a mounted component.' + ); + var props = this.props; + if (props.ref != null) { + ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]); + } + ReactMount.purgeID(this._rootNodeID); + this._rootNodeID = null; + this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; + }, + + /** + * Updates the rendered DOM nodes given a new set of props. + * + * Subclasses that override this method should make sure to invoke + * `ReactComponent.Mixin.receiveProps.call(this, ...)`. + * + * @param {object} nextProps Next set of properties. + * @param {ReactReconcileTransaction} transaction + * @internal + */ + receiveProps: function(nextProps, transaction) { + invariant( + this.isMounted(), + 'receiveProps(...): Can only update a mounted component.' + ); + this._pendingProps = nextProps; + this._performUpdateIfNecessary(transaction); + }, + + /** + * Call `_performUpdateIfNecessary` within a new transaction. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function() { + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform(this._performUpdateIfNecessary, this, transaction); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * If `_pendingProps` is set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _performUpdateIfNecessary: function(transaction) { + if (this._pendingProps == null) { + return; + } + var prevProps = this.props; + this.props = this._pendingProps; + this._pendingProps = null; + this.updateComponent(transaction, prevProps); + }, + + /** + * Updates the component's currently mounted representation. + * + * @param {ReactReconcileTransaction} transaction + * @param {object} prevProps + * @internal + */ + updateComponent: function(transaction, prevProps) { + var props = this.props; + // If either the owner or a `ref` has changed, make sure the newest owner + // has stored a reference to `this`, and the previous owner (if different) + // has forgotten the reference to `this`. + if (props[OWNER] !== prevProps[OWNER] || props.ref !== prevProps.ref) { + if (prevProps.ref != null) { + ReactOwner.removeComponentAsRefFrom( + this, prevProps.ref, prevProps[OWNER] + ); + } + // Correct, even if the owner is the same, and only the ref has changed. + if (props.ref != null) { + ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]); + } + } + }, + + /** + * Mounts this component and inserts it into the DOM. + * + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {boolean} shouldReuseMarkup If true, do not insert markup + * @final + * @internal + * @see {ReactMount.renderComponent} + */ + mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) { + var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); + transaction.perform( + this._mountComponentIntoNode, + this, + rootID, + container, + transaction, + shouldReuseMarkup + ); + ReactComponent.ReactReconcileTransaction.release(transaction); + }, + + /** + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {ReactReconcileTransaction} transaction + * @param {boolean} shouldReuseMarkup If true, do not insert markup + * @final + * @private + */ + _mountComponentIntoNode: function( + rootID, + container, + transaction, + shouldReuseMarkup) { + invariant( + container && container.nodeType === 1, + 'mountComponentIntoNode(...): Target container is not a DOM element.' + ); + var markup = this.mountComponent(rootID, transaction); + + if (shouldReuseMarkup) { + if (ReactMarkupChecksum.canReuseMarkup( + markup, + getReactRootElementInContainer(container))) { + return; + } else { + if (true) { + 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.' + ); + } + } + } + + // Asynchronously inject markup by ensuring that the container is not in + // the document when settings its `innerHTML`. + var parent = container.parentNode; + if (parent) { + var next = container.nextSibling; + parent.removeChild(container); + container.innerHTML = markup; + if (next) { + parent.insertBefore(container, next); + } else { + parent.appendChild(container); + } + } else { + container.innerHTML = markup; + } + }, + + /** + * Unmounts this component and removes it from the DOM. + * + * @param {DOMElement} container DOM element to unmount from. + * @final + * @internal + * @see {ReactMount.unmountAndReleaseReactRootNode} + */ + unmountComponentFromNode: function(container) { + this.unmountComponent(); + // http://jsperf.com/emptying-a-node + while (container.lastChild) { + container.removeChild(container.lastChild); + } + }, + + /** + * Checks if this component is owned by the supplied `owner` component. + * + * @param {ReactComponent} owner Component to check. + * @return {boolean} True if `owners` owns this component. + * @final + * @internal + */ + isOwnedBy: function(owner) { + return this.props[OWNER] === owner; + }, + + /** + * Gets another component, that shares the same owner as this one, by ref. + * + * @param {string} ref of a sibling Component. + * @return {?ReactComponent} the actual sibling Component. + * @final + * @internal + */ + getSiblingByRef: function(ref) { + var owner = this.props[OWNER]; + if (!owner || !owner.refs) { + return null; + } + return owner.refs[ref]; + } + + } + +}; + +module.exports = ReactComponent; + +},{"./ReactCurrentOwner":25,"./ReactDOMIDOperations":28,"./ReactMarkupChecksum":38,"./ReactMount":39,"./ReactOwner":43,"./ReactReconcileTransaction":46,"./ReactUpdates":49,"./getReactRootElementInContainer":73,"./invariant":78,"./keyMirror":81,"./merge":84}],24:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactCompositeComponent + */ + +"use strict"; + +var ReactComponent = require("./ReactComponent"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactOwner = require("./ReactOwner"); +var ReactPropTransferer = require("./ReactPropTransferer"); +var ReactUpdates = require("./ReactUpdates"); + +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); +var mixInto = require("./mixInto"); + +/** + * Policies that describe methods in `ReactCompositeComponentInterface`. + */ +var SpecPolicy = keyMirror({ + /** + * These methods may be defined only once by the class specification or mixin. + */ + DEFINE_ONCE: null, + /** + * These methods may be defined by both the class specification and mixins. + * Subsequent definitions will be chained. These methods must return void. + */ + DEFINE_MANY: null, + /** + * These methods are overriding the base ReactCompositeComponent class. + */ + OVERRIDE_BASE: null +}); + +/** + * Composite components are higher-level components that compose other composite + * or native components. + * + * To create a new type of `ReactCompositeComponent`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. + * + * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will available on the prototype. + * + * @interface ReactCompositeComponentInterface + * @internal + */ +var ReactCompositeComponentInterface = { + + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: SpecPolicy.DEFINE_MANY, + + /** + * Definition of prop types for this component. + * + * @type {object} + * @optional + */ + propTypes: SpecPolicy.DEFINE_ONCE, + + + + // ==== Definition methods ==== + + /** + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). + * + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. + * + * @return {object} + * @optional + */ + getDefaultProps: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: SpecPolicy.DEFINE_ONCE, + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required + */ + render: SpecPolicy.DEFINE_ONCE, + + + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props and state. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props and state will not require a component update. + * + * shouldComponentUpdate: function(nextProps, nextState) { + * return !equal(nextProps, this.props) || !equal(nextState, this.state); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked when the component is about to update due to a transition from + * `this.props` and `this.state` to `nextProps` and `nextState`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, + + + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: SpecPolicy.OVERRIDE_BASE + +}; + +/** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared in the specification when defining classes + * using `React.createClass`, they will not be on the component's prototype. + */ +var RESERVED_SPEC_KEYS = { + displayName: function(Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function(Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + propTypes: function(Constructor, propTypes) { + Constructor.propTypes = propTypes; + } +}; + +function validateMethodOverride(proto, name) { + var specPolicy = ReactCompositeComponentInterface[name]; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactCompositeComponentMixin.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.OVERRIDE_BASE, + 'ReactCompositeComponentInterface: You are attempting to override ' + + '`%s` from your class specification. Ensure that your method names ' + + 'do not overlap with React methods.', + name + ); + } + + // Disallow defining methods more than once unless explicitly allowed. + if (proto.hasOwnProperty(name)) { + invariant( + specPolicy === SpecPolicy.DEFINE_MANY, + 'ReactCompositeComponentInterface: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be due ' + + 'to a mixin.', + name + ); + } +} + + +function validateLifeCycleOnReplaceState(instance) { + var compositeLifeCycleState = instance._compositeLifeCycleState; + invariant( + instance.isMounted() || + compositeLifeCycleState === CompositeLifeCycle.MOUNTING, + 'replaceState(...): Can only update a mounted or mounting component.' + ); + invariant( + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && + compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + 'replaceState(...): Cannot update while unmounting component or during ' + + 'an existing state transition (such as within `render`).' + ); +} + +/** + * Custom version of `mixInto` which handles policy validation and reserved + * specification keys when building `ReactCompositeComponent` classses. + */ +function mixSpecIntoComponent(Constructor, spec) { + var proto = Constructor.prototype; + for (var name in spec) { + var property = spec[name]; + if (!spec.hasOwnProperty(name) || !property) { + continue; + } + validateMethodOverride(proto, name); + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactCompositeComponent methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isCompositeComponentMethod = name in ReactCompositeComponentInterface; + var isInherited = name in proto; + var markedDontBind = property.__reactDontBind; + var isFunction = typeof property === 'function'; + var shouldAutoBind = + isFunction && + !isCompositeComponentMethod && + !isInherited && + !markedDontBind; + + if (shouldAutoBind) { + if (!proto.__reactAutoBindMap) { + proto.__reactAutoBindMap = {}; + } + proto.__reactAutoBindMap[name] = property; + proto[name] = property; + } else { + if (isInherited) { + // For methods which are defined more than once, call the existing + // methods before calling the new property. + proto[name] = createChainedFunction(proto[name], property); + } else { + proto[name] = property; + } + } + } + } +} + +/** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ +function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; +} + +/** + * `ReactCompositeComponent` maintains an auxiliary life cycle state in + * `this._compositeLifeCycleState` (which can be null). + * + * This is different from the life cycle state maintained by `ReactComponent` in + * `this._lifeCycleState`. The following diagram shows how the states overlap in + * time. There are times when the CompositeLifeCycle is null - at those times it + * is only meaningful to look at ComponentLifeCycle alone. + * + * Top Row: ReactComponent.ComponentLifeCycle + * Low Row: ReactComponent.CompositeLifeCycle + * + * +-------+------------------------------------------------------+--------+ + * | UN | MOUNTED | UN | + * |MOUNTED| | MOUNTED| + * +-------+------------------------------------------------------+--------+ + * | ^--------+ +------+ +------+ +------+ +--------^ | + * | | | | | | | | | | | | + * | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 | + * | | | |PROPS | | PROPS| | STATE| |MOUNTING| | + * | | | | | | | | | | | | + * | | | | | | | | | | | | + * | +--------+ +------+ +------+ +------+ +--------+ | + * | | | | + * +-------+------------------------------------------------------+--------+ + */ +var CompositeLifeCycle = keyMirror({ + /** + * Components in the process of being mounted respond to state changes + * differently. + */ + MOUNTING: null, + /** + * Components in the process of being unmounted are guarded against state + * changes. + */ + UNMOUNTING: null, + /** + * Components that are mounted and receiving new props respond to state + * changes differently. + */ + RECEIVING_PROPS: null, + /** + * Components that are mounted and receiving new state are guarded against + * additional state changes. + */ + RECEIVING_STATE: null +}); + +/** + * @lends {ReactCompositeComponent.prototype} + */ +var ReactCompositeComponentMixin = { + + /** + * Base constructor for all composite component. + * + * @param {?object} initialProps + * @param {*} children + * @final + * @internal + */ + construct: function(initialProps, children) { + // Children can be either an array or more than one argument + ReactComponent.Mixin.construct.apply(this, arguments); + this.state = null; + this._pendingState = null; + this._compositeLifeCycleState = null; + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function() { + return ReactComponent.Mixin.isMounted.call(this) && + this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function(rootID, transaction) { + ReactComponent.Mixin.mountComponent.call(this, rootID, transaction); + this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; + + this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null; + this._processProps(this.props); + + if (this.__reactAutoBindMap) { + this._bindAutoBindMethods(); + } + + this.state = this.getInitialState ? this.getInitialState() : null; + this._pendingState = null; + this._pendingForceUpdate = false; + + if (this.componentWillMount) { + this.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingState` without triggering a re-render. + if (this._pendingState) { + this.state = this._pendingState; + this._pendingState = null; + } + } + + this._renderedComponent = this._renderValidatedComponent(); + + // Done with mounting, `setState` will now trigger UI changes. + this._compositeLifeCycleState = null; + var markup = this._renderedComponent.mountComponent(rootID, transaction); + if (this.componentDidMount) { + transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount); + } + return markup; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function() { + this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; + if (this.componentWillUnmount) { + this.componentWillUnmount(); + } + this._compositeLifeCycleState = null; + + this._defaultProps = null; + + ReactComponent.Mixin.unmountComponent.call(this); + this._renderedComponent.unmountComponent(); + this._renderedComponent = null; + + if (this.refs) { + this.refs = null; + } + + // Some existing components rely on this.props even after they've been + // destroyed (in event handlers). + // TODO: this.props = null; + // TODO: this.state = null; + }, + + /** + * Sets a subset of the state. Always use this or `replaceState` to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * @param {object} partialState Next partial state to be merged with state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + setState: function(partialState, callback) { + // Merge with `_pendingState` if it exists, otherwise with existing state. + this.replaceState( + merge(this._pendingState || this.state, partialState), + callback + ); + }, + + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {object} completeState Next state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + replaceState: function(completeState, callback) { + validateLifeCycleOnReplaceState(this); + this._pendingState = completeState; + ReactUpdates.enqueueUpdate(this, callback); + }, + + /** + * Processes props by setting default values for unspecified props and + * asserting that the props are valid. + * + * @param {object} props + * @private + */ + _processProps: function(props) { + var propName; + var defaultProps = this._defaultProps; + for (propName in defaultProps) { + if (!(propName in props)) { + 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); + } + } + } + }, + + performUpdateIfNecessary: function() { + var compositeLifeCycleState = this._compositeLifeCycleState; + // Do not trigger a state transition if we are in the middle of mounting or + // receiving props because both of those will already be doing this. + if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING || + compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) { + return; + } + ReactComponent.Mixin.performUpdateIfNecessary.call(this); + }, + + /** + * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is + * set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _performUpdateIfNecessary: function(transaction) { + if (this._pendingProps == null && + this._pendingState == null && + !this._pendingForceUpdate) { + return; + } + + var nextProps = this.props; + if (this._pendingProps != null) { + nextProps = this._pendingProps; + this._processProps(nextProps); + this._pendingProps = null; + + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; + if (this.componentWillReceiveProps) { + this.componentWillReceiveProps(nextProps, transaction); + } + } + + this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; + + 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; + } + + this._compositeLifeCycleState = null; + }, + + /** + * Merges new props and state, notifies delegate methods of update and + * performs update. + * + * @param {object} nextProps Next object to set as properties. + * @param {?object} nextState Next object to set as state. + * @param {ReactReconcileTransaction} transaction + * @private + */ + _performComponentUpdate: function(nextProps, nextState, transaction) { + var prevProps = this.props; + var prevState = this.state; + + if (this.componentWillUpdate) { + this.componentWillUpdate(nextProps, nextState, transaction); + } + + this.props = nextProps; + this.state = nextState; + + this.updateComponent(transaction, prevProps, prevState); + + if (this.componentDidUpdate) { + transaction.getReactOnDOMReady().enqueue( + this, + this.componentDidUpdate.bind(this, prevProps, prevState) + ); + } + }, + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @param {object} prevProps + * @param {?object} prevState + * @internal + * @overridable + */ + updateComponent: function(transaction, prevProps, prevState) { + ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); + var currentComponent = this._renderedComponent; + var nextComponent = this._renderValidatedComponent(); + if (currentComponent.constructor === nextComponent.constructor) { + currentComponent.receiveProps(nextComponent.props, transaction); + } else { + // These two IDs are actually the same! But nothing should rely on that. + var thisID = this._rootNodeID; + var currentComponentID = currentComponent._rootNodeID; + currentComponent.unmountComponent(); + var nextMarkup = nextComponent.mountComponent(thisID, transaction); + ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( + currentComponentID, + nextMarkup + ); + this._renderedComponent = nextComponent; + } + }, + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldUpdateComponent`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. + * @final + * @protected + */ + forceUpdate: function(callback) { + var compositeLifeCycleState = this._compositeLifeCycleState; + invariant( + this.isMounted() || + compositeLifeCycleState === CompositeLifeCycle.MOUNTING, + 'forceUpdate(...): Can only force an update on mounted or mounting ' + + 'components.' + ); + invariant( + compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && + compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + 'forceUpdate(...): Cannot force an update while unmounting component ' + + 'or during an existing state transition (such as within `render`).' + ); + this._pendingForceUpdate = true; + ReactUpdates.enqueueUpdate(this, callback); + }, + + /** + * @private + */ + _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; + } + invariant( + ReactComponent.isValidComponent(renderedComponent), + '%s.render(): A valid ReactComponent must be returned.', + this.constructor.displayName || 'ReactCompositeComponent' + ); + return renderedComponent; + }, + + /** + * @private + */ + _bindAutoBindMethods: function() { + for (var autoBindKey in this.__reactAutoBindMap) { + if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + continue; + } + var method = this.__reactAutoBindMap[autoBindKey]; + this[autoBindKey] = this._bindAutoBindMethod(method); + } + }, + + /** + * Binds a method to the component. + * + * @param {function} method Method to be bound. + * @private + */ + _bindAutoBindMethod: function(method) { + var component = this; + var boundMethod = function() { + return method.apply(component, arguments); + }; + if (true) { + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + boundMethod.bind = function(newThis) { + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component) { + console.warn( + 'bind(): React component methods may only be bound to the ' + + 'component instance. See ' + componentName + ); + } else if (arguments.length === 1) { + console.warn( + 'bind(): You are binding a component method to the component. ' + + 'React does this for you automatically in a high-performance ' + + 'way, so you can safely remove this call. See ' + componentName + ); + return boundMethod; + } + return _bind.apply(boundMethod, arguments); + }; + } + return boundMethod; + } +}; + +var ReactCompositeComponentBase = function() {}; +mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); +mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); +mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); +mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); + +/** + * Module for creating composite components. + * + * @class ReactCompositeComponent + * @extends ReactComponent + * @extends ReactOwner + * @extends ReactPropTransferer + */ +var ReactCompositeComponent = { + + LifeCycle: CompositeLifeCycle, + + Base: ReactCompositeComponentBase, + + /** + * Creates a composite component class given a class specification. + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function(spec) { + var Constructor = function() {}; + Constructor.prototype = new ReactCompositeComponentBase(); + Constructor.prototype.constructor = Constructor; + mixSpecIntoComponent(Constructor, spec); + invariant( + Constructor.prototype.render, + 'createClass(...): Class specification must implement a `render` method.' + ); + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactCompositeComponentInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } + } + + var ConvenienceConstructor = function(props, children) { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + ConvenienceConstructor.componentConstructor = Constructor; + ConvenienceConstructor.originalSpec = spec; + return ConvenienceConstructor; + }, + + /** + * TODO: Delete this when all callers have been updated to rely on this + * behavior being the default. + * + * Backwards compatible stub for what is now the default behavior. + * @param {function} method Method to be bound. + * @public + */ + autoBind: function(method) { + if (true) { + console.warn( + 'React.autoBind() is now deprecated. All React component methods ' + + 'are auto bound by default, so React.autoBind() is a no-op. It ' + + 'will be removed in the next version of React' + ); + } + return method; + } +}; + +module.exports = ReactCompositeComponent; + +})() +},{"./ReactComponent":23,"./ReactCurrentOwner":25,"./ReactOwner":43,"./ReactPropTransferer":44,"./ReactUpdates":49,"./invariant":78,"./keyMirror":81,"./merge":84,"./mixInto":87}],25:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactCurrentOwner + */ + +"use strict"; + +/** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + * + * The depth indicate how many composite components are above this render level. + */ +var ReactCurrentOwner = { + + /** + * @internal + * @type {ReactComponent} + */ + current: null + +}; + +module.exports = ReactCurrentOwner; + +},{}],26:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOM + * @typechecks static-only + */ + +"use strict"; + +var ReactNativeComponent = require("./ReactNativeComponent"); + +var mergeInto = require("./mergeInto"); +var objMapKeyVal = require("./objMapKeyVal"); + +/** + * Creates a new React class that is idempotent and capable of containing other + * React components. It accepts event listeners and DOM properties that are + * valid according to `DOMProperty`. + * + * - Event listeners: `onClick`, `onMouseDown`, etc. + * - DOM properties: `className`, `name`, `title`, etc. + * + * The `style` property functions differently from the DOM API. It accepts an + * object mapping of style properties to values. + * + * @param {string} tag Tag name (e.g. `div`). + * @param {boolean} omitClose True if the close tag should be omitted. + * @private + */ +function createDOMComponentClass(tag, omitClose) { + var Constructor = function() {}; + Constructor.prototype = new ReactNativeComponent(tag, omitClose); + Constructor.prototype.constructor = Constructor; + + var ConvenienceConstructor = function(props, children) { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + ConvenienceConstructor.componentConstructor = Constructor; + return ConvenienceConstructor; +} + +/** + * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes. + * This is also accessible via `React.DOM`. + * + * @public + */ +var ReactDOM = objMapKeyVal({ + a: false, + abbr: false, + address: false, + area: false, + article: false, + aside: false, + audio: false, + b: false, + base: false, + bdi: false, + bdo: false, + big: false, + blockquote: false, + body: false, + br: true, + button: false, + canvas: false, + caption: false, + cite: false, + code: false, + col: true, + colgroup: false, + data: false, + datalist: false, + dd: false, + del: false, + details: false, + dfn: false, + div: false, + dl: false, + dt: false, + em: false, + embed: true, + fieldset: false, + figcaption: false, + figure: false, + footer: false, + form: false, // NOTE: Injected, see `ReactDOMForm`. + h1: false, + h2: false, + h3: false, + h4: false, + h5: false, + h6: false, + head: false, + header: false, + hr: true, + html: false, + i: false, + iframe: false, + img: true, + input: true, + ins: false, + kbd: false, + keygen: true, + label: false, + legend: false, + li: false, + link: false, + main: false, + map: false, + mark: false, + menu: false, + menuitem: false, // NOTE: Close tag should be omitted, but causes problems. + meta: true, + meter: false, + nav: false, + noscript: false, + object: false, + ol: false, + optgroup: false, + option: false, + output: false, + p: false, + param: true, + pre: false, + progress: false, + q: false, + rp: false, + rt: false, + ruby: false, + s: false, + samp: false, + script: false, + section: false, + select: false, + small: false, + source: false, + span: false, + strong: false, + style: false, + sub: false, + summary: false, + sup: false, + table: false, + tbody: false, + td: false, + textarea: false, // NOTE: Injected, see `ReactDOMTextarea`. + tfoot: false, + th: false, + thead: false, + time: false, + title: false, + tr: false, + track: true, + u: false, + ul: false, + 'var': false, + video: false, + wbr: false, + + // SVG + circle: false, + g: false, + line: false, + path: false, + polyline: false, + rect: false, + svg: false, + text: false +}, createDOMComponentClass); + +var injection = { + injectComponentClasses: function(componentClasses) { + mergeInto(ReactDOM, componentClasses); + } +}; + +ReactDOM.injection = injection; + +module.exports = ReactDOM; + +},{"./ReactNativeComponent":41,"./mergeInto":86,"./objMapKeyVal":88}],27:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMForm + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); +var ReactEventEmitter = require("./ReactEventEmitter"); +var EventConstants = require("./EventConstants"); + +// Store a reference to the
`ReactNativeComponent`. +var form = ReactDOM.form; + +/** + * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need + * to capture it on the element itself. There are lots of hacks we could + * do to accomplish this, but the most reliable is to make a + * composite component and use `componentDidMount` to attach the event handlers. + */ +var ReactDOMForm = ReactCompositeComponent.createClass({ + render: function() { + // TODO: Instead of using `ReactDOM` directly, we should use JSX. However, + // `jshint` fails to parse JSX so in order for linting to work in the open + // source repo, we need to just use `ReactDOM.form`. + return this.transferPropsTo(form(null, this.props.children)); + }, + + componentDidMount: function(node) { + ReactEventEmitter.trapBubbledEvent( + EventConstants.topLevelTypes.topSubmit, + 'submit', + node + ); + } +}); + +module.exports = ReactDOMForm; + +},{"./EventConstants":13,"./ReactCompositeComponent":24,"./ReactDOM":26,"./ReactEventEmitter":34}],28:[function(require,module,exports){ +(function(){/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMIDOperations + * @typechecks static-only + */ + +/*jslint evil: true */ + +"use strict"; + +var CSSPropertyOperations = require("./CSSPropertyOperations"); +var DOMChildrenOperations = require("./DOMChildrenOperations"); +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var ReactMount = require("./ReactMount"); + +var getTextContentAccessor = require("./getTextContentAccessor"); +var invariant = require("./invariant"); + +/** + * Errors for properties that should not be updated with `updatePropertyById()`. + * + * @type {object} + * @private + */ +var INVALID_PROPERTY_ERRORS = { + dangerouslySetInnerHTML: + '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', + style: '`style` must be set using `updateStylesByID()`.' +}; + +/** + * The DOM property to use when setting text content. + * + * @type {string} + * @private + */ +var textContentAccessor = getTextContentAccessor() || 'NA'; + +/** + * Operations used to process updates to DOM nodes. This is made injectable via + * `ReactComponent.DOMIDOperations`. + */ +var ReactDOMIDOperations = { + + /** + * Updates a DOM node with new property values. This should only be used to + * update DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A valid property name, see `DOMProperty`. + * @param {*} value New value of the property. + * @internal + */ + updatePropertyByID: function(id, name, value) { + var node = ReactMount.getNode(id); + invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[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); + } + }, + + /** + * Updates a DOM node to remove a property. This should only be used to remove + * DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A property name to remove, see `DOMProperty`. + * @internal + */ + deletePropertyByID: function(id, name, value) { + var node = ReactMount.getNode(id); + invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ); + DOMPropertyOperations.deleteValueForProperty(node, name, value); + }, + + /** + * This should almost never be used instead of `updatePropertyByID()` due to + * the extra object allocation required by the API. That said, this is useful + * for batching up several operations across worker thread boundaries. + * + * @param {string} id ID of the node to update. + * @param {object} properties A mapping of valid property names. + * @internal + * @see {ReactDOMIDOperations.updatePropertyByID} + */ + updatePropertiesByID: function(id, properties) { + for (var name in properties) { + if (!properties.hasOwnProperty(name)) { + continue; + } + ReactDOMIDOperations.updatePropertiesByID(id, name, properties[name]); + } + }, + + /** + * Updates a DOM node with new style values. If a value is specified as '', + * the corresponding style property will be unset. + * + * @param {string} id ID of the node to update. + * @param {object} styles Mapping from styles to values. + * @internal + */ + updateStylesByID: function(id, styles) { + var node = ReactMount.getNode(id); + CSSPropertyOperations.setValueForStyles(node, styles); + }, + + /** + * Updates a DOM node's innerHTML set by `props.dangerouslySetInnerHTML`. + * + * @param {string} id ID of the node to update. + * @param {object} html An HTML object with the `__html` property. + * @internal + */ + updateInnerHTMLByID: function(id, html) { + var node = 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 && html.__html || '').replace(/^ /g, ' '); + }, + + /** + * Updates a DOM node's text content set by `props.content`. + * + * @param {string} id ID of the node to update. + * @param {string} content Text content. + * @internal + */ + updateTextContentByID: function(id, content) { + var node = ReactMount.getNode(id); + node[textContentAccessor] = content; + }, + + /** + * Replaces a DOM node that exists in the document with markup. + * + * @param {string} id ID of child to be replaced. + * @param {string} markup Dangerous markup to inject in place of child. + * @internal + * @see {Danger.dangerouslyReplaceNodeWithMarkup} + */ + dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); + }, + + /** + * TODO: We only actually *need* to purge the cache when we remove elements. + * Detect if any elements were removed instead of blindly purging. + */ + manageChildrenByParentID: function(parentID, domOperations) { + var parent = ReactMount.getNode(parentID); + DOMChildrenOperations.manageChildren(parent, domOperations); + } + +}; + +module.exports = ReactDOMIDOperations; + +})() +},{"./CSSPropertyOperations":3,"./DOMChildrenOperations":6,"./DOMPropertyOperations":8,"./ReactMount":39,"./getTextContentAccessor":74,"./invariant":78}],29:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMInput + */ + +"use strict"; + +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); + +var merge = require("./merge"); + +// Store a reference to the `ReactNativeComponent`. +var input = ReactDOM.input; + +/** + * Implements an native component that allows setting these optional + * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. + * + * If `checked` or `value` are not supplied (or null/undefined), user actions + * that affect the checked state or value will trigger updates to the element. + * + * If they are supplied (and not null/undefined), the rendered element will not + * trigger updates to the element. Instead, the props must change in order for + * the rendered element to be updated. + * + * The rendered element will be initialized as unchecked (or `defaultChecked`) + * with an empty value (or `defaultValue`). + * + * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html + */ +var ReactDOMInput = ReactCompositeComponent.createClass({ + + getInitialState: function() { + return { + checked: this.props.defaultChecked || false, + value: this.props.defaultValue || '' + }; + }, + + shouldComponentUpdate: function() { + // Defer any updates to this component during the `onChange` handler. + return !this._isChanging; + }, + + getChecked: function() { + return this.props.checked != null ? this.props.checked : this.state.checked; + }, + + getValue: function() { + // Cast `this.props.value` to a string so equality checks pass. + return this.props.value != null ? '' + this.props.value : this.state.value; + }, + + render: function() { + // Clone `this.props` so we don't mutate the input. + var props = merge(this.props); + + props.checked = this.getChecked(); + props.value = this.getValue(); + props.onChange = this.handleChange; + + return input(props, this.props.children); + }, + + componentDidUpdate: function(prevProps, prevState, rootNode) { + if (this.props.checked != null) { + DOMPropertyOperations.setValueForProperty( + rootNode, + 'checked', + this.props.checked || false + ); + } + if (this.props.value != null) { + // Cast `this.props.value` to a string so falsey values that cast to + // truthy strings are not ignored. + DOMPropertyOperations.setValueForProperty( + rootNode, + 'value', + '' + this.props.value || '' + ); + } + }, + + handleChange: function(event) { + var returnValue; + if (this.props.onChange) { + this._isChanging = true; + returnValue = this.props.onChange(event); + this._isChanging = false; + } + this.setState({ + checked: event.target.checked, + value: event.target.value + }); + return returnValue; + } + +}); + +module.exports = ReactDOMInput; + +},{"./DOMPropertyOperations":8,"./ReactCompositeComponent":24,"./ReactDOM":26,"./merge":84}],30:[function(require,module,exports){ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule ReactDOMOption + */ + +"use strict"; + +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); + +// Store a reference to the