github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/react/react.js (about) 1 /** 2 * React v0.8.0 3 */ 4 !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.React=e():"undefined"!=typeof global?global.React=e():"undefined"!=typeof self&&(self.React=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 5 /** 6 * Copyright 2013 Facebook, Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 * @providesModule $ 21 * @typechecks 22 */ 23 24 var ge = require("./ge"); 25 var ex = require("./ex"); 26 27 /** 28 * Find a node by ID. 29 * 30 * If your application code depends on the existence of the element, use $, 31 * which will throw if the element doesn't exist. 32 * 33 * If you're not sure whether or not the element exists, use ge instead, and 34 * manually check for the element's existence in your application code. 35 * 36 * @param {string|DOMDocument|DOMElement|DOMTextNode|Comment} id 37 * @return {DOMDocument|DOMElement|DOMTextNode|Comment} 38 */ 39 function $(id) { 40 var element = ge(id); 41 if (!element) { 42 throw new Error(ex( 43 'Tried to get element with id of "%s" but it is not present on the page.', 44 id 45 )); 46 } 47 return element; 48 } 49 50 module.exports = $; 51 52 },{"./ex":85,"./ge":89}],2:[function(require,module,exports){ 53 /** 54 * Copyright 2013 Facebook, Inc. 55 * 56 * Licensed under the Apache License, Version 2.0 (the "License"); 57 * you may not use this file except in compliance with the License. 58 * You may obtain a copy of the License at 59 * 60 * http://www.apache.org/licenses/LICENSE-2.0 61 * 62 * Unless required by applicable law or agreed to in writing, software 63 * distributed under the License is distributed on an "AS IS" BASIS, 64 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 * See the License for the specific language governing permissions and 66 * limitations under the License. 67 * 68 * @providesModule CSSProperty 69 */ 70 71 "use strict"; 72 73 /** 74 * CSS properties which accept numbers but are not in units of "px". 75 */ 76 var isUnitlessNumber = { 77 fillOpacity: true, 78 fontWeight: true, 79 lineHeight: true, 80 opacity: true, 81 orphans: true, 82 zIndex: true, 83 zoom: true 84 }; 85 86 /** 87 * Most style properties can be unset by doing .style[prop] = '' but IE8 88 * doesn't like doing that with shorthand properties so for the properties that 89 * IE8 breaks on, which are listed here, we instead unset each of the 90 * individual properties. See http://bugs.jquery.com/ticket/12385. 91 * The 4-value 'clock' properties like margin, padding, border-width seem to 92 * behave without any problems. Curiously, list-style works too without any 93 * special prodding. 94 */ 95 var shorthandPropertyExpansions = { 96 background: { 97 backgroundImage: true, 98 backgroundPosition: true, 99 backgroundRepeat: true, 100 backgroundColor: true 101 }, 102 border: { 103 borderWidth: true, 104 borderStyle: true, 105 borderColor: true 106 }, 107 borderBottom: { 108 borderBottomWidth: true, 109 borderBottomStyle: true, 110 borderBottomColor: true 111 }, 112 borderLeft: { 113 borderLeftWidth: true, 114 borderLeftStyle: true, 115 borderLeftColor: true 116 }, 117 borderRight: { 118 borderRightWidth: true, 119 borderRightStyle: true, 120 borderRightColor: true 121 }, 122 borderTop: { 123 borderTopWidth: true, 124 borderTopStyle: true, 125 borderTopColor: true 126 }, 127 font: { 128 fontStyle: true, 129 fontVariant: true, 130 fontWeight: true, 131 fontSize: true, 132 lineHeight: true, 133 fontFamily: true 134 } 135 }; 136 137 var CSSProperty = { 138 isUnitlessNumber: isUnitlessNumber, 139 shorthandPropertyExpansions: shorthandPropertyExpansions 140 }; 141 142 module.exports = CSSProperty; 143 144 },{}],3:[function(require,module,exports){ 145 /** 146 * Copyright 2013 Facebook, Inc. 147 * 148 * Licensed under the Apache License, Version 2.0 (the "License"); 149 * you may not use this file except in compliance with the License. 150 * You may obtain a copy of the License at 151 * 152 * http://www.apache.org/licenses/LICENSE-2.0 153 * 154 * Unless required by applicable law or agreed to in writing, software 155 * distributed under the License is distributed on an "AS IS" BASIS, 156 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 157 * See the License for the specific language governing permissions and 158 * limitations under the License. 159 * 160 * @providesModule CSSPropertyOperations 161 * @typechecks static-only 162 */ 163 164 "use strict"; 165 166 var CSSProperty = require("./CSSProperty"); 167 168 var dangerousStyleValue = require("./dangerousStyleValue"); 169 var escapeTextForBrowser = require("./escapeTextForBrowser"); 170 var hyphenate = require("./hyphenate"); 171 var memoizeStringOnly = require("./memoizeStringOnly"); 172 173 var processStyleName = memoizeStringOnly(function(styleName) { 174 return escapeTextForBrowser(hyphenate(styleName)); 175 }); 176 177 /** 178 * Operations for dealing with CSS properties. 179 */ 180 var CSSPropertyOperations = { 181 182 /** 183 * Serializes a mapping of style properties for use as inline styles: 184 * 185 * > createMarkupForStyles({width: '200px', height: 0}) 186 * "width:200px;height:0;" 187 * 188 * Undefined values are ignored so that declarative programming is easier. 189 * 190 * @param {object} styles 191 * @return {?string} 192 */ 193 createMarkupForStyles: function(styles) { 194 var serialized = ''; 195 for (var styleName in styles) { 196 if (!styles.hasOwnProperty(styleName)) { 197 continue; 198 } 199 var styleValue = styles[styleName]; 200 if (styleValue != null) { 201 serialized += processStyleName(styleName) + ':'; 202 serialized += dangerousStyleValue(styleName, styleValue) + ';'; 203 } 204 } 205 return serialized || null; 206 }, 207 208 /** 209 * Sets the value for multiple styles on a node. If a value is specified as 210 * '' (empty string), the corresponding style property will be unset. 211 * 212 * @param {DOMElement} node 213 * @param {object} styles 214 */ 215 setValueForStyles: function(node, styles) { 216 var style = node.style; 217 for (var styleName in styles) { 218 if (!styles.hasOwnProperty(styleName)) { 219 continue; 220 } 221 var styleValue = dangerousStyleValue(styleName, styles[styleName]); 222 if (styleValue) { 223 style[styleName] = styleValue; 224 } else { 225 var expansion = CSSProperty.shorthandPropertyExpansions[styleName]; 226 if (expansion) { 227 // Shorthand property that IE8 won't like unsetting, so unset each 228 // component to placate it 229 for (var individualStyleName in expansion) { 230 style[individualStyleName] = ''; 231 } 232 } else { 233 style[styleName] = ''; 234 } 235 } 236 } 237 } 238 239 }; 240 241 module.exports = CSSPropertyOperations; 242 243 },{"./CSSProperty":2,"./dangerousStyleValue":82,"./escapeTextForBrowser":84,"./hyphenate":97,"./memoizeStringOnly":106}],4:[function(require,module,exports){ 244 /** 245 * Copyright 2013 Facebook, Inc. 246 * 247 * Licensed under the Apache License, Version 2.0 (the "License"); 248 * you may not use this file except in compliance with the License. 249 * You may obtain a copy of the License at 250 * 251 * http://www.apache.org/licenses/LICENSE-2.0 252 * 253 * Unless required by applicable law or agreed to in writing, software 254 * distributed under the License is distributed on an "AS IS" BASIS, 255 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 256 * See the License for the specific language governing permissions and 257 * limitations under the License. 258 * 259 * @providesModule CallbackRegistry 260 * @typechecks static-only 261 */ 262 263 "use strict"; 264 265 var listenerBank = {}; 266 267 /** 268 * Stores "listeners" by `registrationName`/`id`. There should be at most one 269 * "listener" per `registrationName`/`id` in the `listenerBank`. 270 * 271 * Access listeners via `listenerBank[registrationName][id]`. 272 * 273 * @class CallbackRegistry 274 * @internal 275 */ 276 var CallbackRegistry = { 277 278 /** 279 * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. 280 * 281 * @param {string} id ID of the DOM element. 282 * @param {string} registrationName Name of listener (e.g. `onClick`). 283 * @param {?function} listener The callback to store. 284 */ 285 putListener: function(id, registrationName, listener) { 286 var bankForRegistrationName = 287 listenerBank[registrationName] || (listenerBank[registrationName] = {}); 288 bankForRegistrationName[id] = listener; 289 }, 290 291 /** 292 * @param {string} id ID of the DOM element. 293 * @param {string} registrationName Name of listener (e.g. `onClick`). 294 * @return {?function} The stored callback. 295 */ 296 getListener: function(id, registrationName) { 297 var bankForRegistrationName = listenerBank[registrationName]; 298 return bankForRegistrationName && bankForRegistrationName[id]; 299 }, 300 301 /** 302 * Deletes a listener from the registration bank. 303 * 304 * @param {string} id ID of the DOM element. 305 * @param {string} registrationName Name of listener (e.g. `onClick`). 306 */ 307 deleteListener: function(id, registrationName) { 308 var bankForRegistrationName = listenerBank[registrationName]; 309 if (bankForRegistrationName) { 310 delete bankForRegistrationName[id]; 311 } 312 }, 313 314 /** 315 * Deletes all listeners for the DOM element with the supplied ID. 316 * 317 * @param {string} id ID of the DOM element. 318 */ 319 deleteAllListeners: function(id) { 320 for (var registrationName in listenerBank) { 321 delete listenerBank[registrationName][id]; 322 } 323 }, 324 325 /** 326 * This is needed for tests only. Do not use! 327 */ 328 __purge: function() { 329 listenerBank = {}; 330 } 331 332 }; 333 334 module.exports = CallbackRegistry; 335 336 },{}],5:[function(require,module,exports){ 337 /** 338 * Copyright 2013 Facebook, Inc. 339 * 340 * Licensed under the Apache License, Version 2.0 (the "License"); 341 * you may not use this file except in compliance with the License. 342 * You may obtain a copy of the License at 343 * 344 * http://www.apache.org/licenses/LICENSE-2.0 345 * 346 * Unless required by applicable law or agreed to in writing, software 347 * distributed under the License is distributed on an "AS IS" BASIS, 348 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 349 * See the License for the specific language governing permissions and 350 * limitations under the License. 351 * 352 * @providesModule ChangeEventPlugin 353 */ 354 355 "use strict"; 356 357 var EventConstants = require("./EventConstants"); 358 var EventPluginHub = require("./EventPluginHub"); 359 var EventPropagators = require("./EventPropagators"); 360 var ExecutionEnvironment = require("./ExecutionEnvironment"); 361 var SyntheticEvent = require("./SyntheticEvent"); 362 363 var isEventSupported = require("./isEventSupported"); 364 var isTextInputElement = require("./isTextInputElement"); 365 var keyOf = require("./keyOf"); 366 367 var topLevelTypes = EventConstants.topLevelTypes; 368 369 var eventTypes = { 370 change: { 371 phasedRegistrationNames: { 372 bubbled: keyOf({onChange: null}), 373 captured: keyOf({onChangeCapture: null}) 374 } 375 } 376 }; 377 378 /** 379 * For IE shims 380 */ 381 var activeElement = null; 382 var activeElementID = null; 383 var activeElementValue = null; 384 var activeElementValueProp = null; 385 386 /** 387 * SECTION: handle `change` event 388 */ 389 function shouldUseChangeEvent(elem) { 390 return ( 391 elem.nodeName === 'SELECT' || 392 (elem.nodeName === 'INPUT' && elem.type === 'file') 393 ); 394 } 395 396 var doesChangeEventBubble = false; 397 if (ExecutionEnvironment.canUseDOM) { 398 // See `handleChange` comment below 399 doesChangeEventBubble = isEventSupported('change') && ( 400 !('documentMode' in document) || document.documentMode > 8 401 ); 402 } 403 404 function manualDispatchChangeEvent(nativeEvent) { 405 var event = SyntheticEvent.getPooled( 406 eventTypes.change, 407 activeElementID, 408 nativeEvent 409 ); 410 EventPropagators.accumulateTwoPhaseDispatches(event); 411 412 // If change bubbled, we'd just bind to it like all the other events 413 // and have it go through ReactEventTopLevelCallback. Since it doesn't, we 414 // manually listen for the change event and so we have to enqueue and 415 // process the abstract event manually. 416 EventPluginHub.enqueueEvents(event); 417 EventPluginHub.processEventQueue(); 418 } 419 420 function startWatchingForChangeEventIE8(target, targetID) { 421 activeElement = target; 422 activeElementID = targetID; 423 activeElement.attachEvent('onchange', manualDispatchChangeEvent); 424 } 425 426 function stopWatchingForChangeEventIE8() { 427 if (!activeElement) { 428 return; 429 } 430 activeElement.detachEvent('onchange', manualDispatchChangeEvent); 431 activeElement = null; 432 activeElementID = null; 433 } 434 435 function getTargetIDForChangeEvent( 436 topLevelType, 437 topLevelTarget, 438 topLevelTargetID) { 439 if (topLevelType === topLevelTypes.topChange) { 440 return topLevelTargetID; 441 } 442 } 443 function handleEventsForChangeEventIE8( 444 topLevelType, 445 topLevelTarget, 446 topLevelTargetID) { 447 if (topLevelType === topLevelTypes.topFocus) { 448 // stopWatching() should be a noop here but we call it just in case we 449 // missed a blur event somehow. 450 stopWatchingForChangeEventIE8(); 451 startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID); 452 } else if (topLevelType === topLevelTypes.topBlur) { 453 stopWatchingForChangeEventIE8(); 454 } 455 } 456 457 458 /** 459 * SECTION: handle `input` event 460 */ 461 var isInputEventSupported = false; 462 if (ExecutionEnvironment.canUseDOM) { 463 // IE9 claims to support the input event but fails to trigger it when 464 // deleting text, so we ignore its input events 465 isInputEventSupported = isEventSupported('input') && ( 466 !('documentMode' in document) || document.documentMode > 9 467 ); 468 } 469 470 /** 471 * (For old IE.) Replacement getter/setter for the `value` property that gets 472 * set on the active element. 473 */ 474 var newValueProp = { 475 get: function() { 476 return activeElementValueProp.get.call(this); 477 }, 478 set: function(val) { 479 // Cast to a string so we can do equality checks. 480 activeElementValue = '' + val; 481 activeElementValueProp.set.call(this, val); 482 } 483 }; 484 485 /** 486 * (For old IE.) Starts tracking propertychange events on the passed-in element 487 * and override the value property so that we can distinguish user events from 488 * value changes in JS. 489 */ 490 function startWatchingForValueChange(target, targetID) { 491 activeElement = target; 492 activeElementID = targetID; 493 activeElementValue = target.value; 494 activeElementValueProp = Object.getOwnPropertyDescriptor( 495 target.constructor.prototype, 496 'value' 497 ); 498 499 Object.defineProperty(activeElement, 'value', newValueProp); 500 activeElement.attachEvent('onpropertychange', handlePropertyChange); 501 } 502 503 /** 504 * (For old IE.) Removes the event listeners from the currently-tracked element, 505 * if any exists. 506 */ 507 function stopWatchingForValueChange() { 508 if (!activeElement) { 509 return; 510 } 511 512 // delete restores the original property definition 513 delete activeElement.value; 514 activeElement.detachEvent('onpropertychange', handlePropertyChange); 515 516 activeElement = null; 517 activeElementID = null; 518 activeElementValue = null; 519 activeElementValueProp = null; 520 } 521 522 /** 523 * (For old IE.) Handles a propertychange event, sending a `change` event if 524 * the value of the active element has changed. 525 */ 526 function handlePropertyChange(nativeEvent) { 527 if (nativeEvent.propertyName !== 'value') { 528 return; 529 } 530 var value = nativeEvent.srcElement.value; 531 if (value === activeElementValue) { 532 return; 533 } 534 activeElementValue = value; 535 536 manualDispatchChangeEvent(nativeEvent); 537 } 538 539 /** 540 * If a `change` event should be fired, returns the target's ID. 541 */ 542 function getTargetIDForInputEvent( 543 topLevelType, 544 topLevelTarget, 545 topLevelTargetID) { 546 if (topLevelType === topLevelTypes.topInput) { 547 // In modern browsers (i.e., not IE8 or IE9), the input event is exactly 548 // what we want so fall through here and trigger an abstract event 549 return topLevelTargetID; 550 } 551 } 552 553 // For IE8 and IE9. 554 function handleEventsForInputEventIE( 555 topLevelType, 556 topLevelTarget, 557 topLevelTargetID) { 558 if (topLevelType === topLevelTypes.topFocus) { 559 // In IE8, we can capture almost all .value changes by adding a 560 // propertychange handler and looking for events with propertyName 561 // equal to 'value' 562 // In IE9, propertychange fires for most input events but is buggy and 563 // doesn't fire when text is deleted, but conveniently, selectionchange 564 // appears to fire in all of the remaining cases so we catch those and 565 // forward the event if the value has changed 566 // In either case, we don't want to call the event handler if the value 567 // is changed from JS so we redefine a setter for `.value` that updates 568 // our activeElementValue variable, allowing us to ignore those changes 569 // 570 // stopWatching() should be a noop here but we call it just in case we 571 // missed a blur event somehow. 572 stopWatchingForValueChange(); 573 startWatchingForValueChange(topLevelTarget, topLevelTargetID); 574 } else if (topLevelType === topLevelTypes.topBlur) { 575 stopWatchingForValueChange(); 576 } 577 } 578 579 // For IE8 and IE9. 580 function getTargetIDForInputEventIE( 581 topLevelType, 582 topLevelTarget, 583 topLevelTargetID) { 584 if (topLevelType === topLevelTypes.topSelectionChange || 585 topLevelType === topLevelTypes.topKeyUp || 586 topLevelType === topLevelTypes.topKeyDown) { 587 // On the selectionchange event, the target is just document which isn't 588 // helpful for us so just check activeElement instead. 589 // 590 // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire 591 // propertychange on the first input event after setting `value` from a 592 // script and fires only keydown, keypress, keyup. Catching keyup usually 593 // gets it and catching keydown lets us fire an event for the first 594 // keystroke if user does a key repeat (it'll be a little delayed: right 595 // before the second keystroke). Other input methods (e.g., paste) seem to 596 // fire selectionchange normally. 597 if (activeElement && activeElement.value !== activeElementValue) { 598 activeElementValue = activeElement.value; 599 return activeElementID; 600 } 601 } 602 } 603 604 605 /** 606 * SECTION: handle `click` event 607 */ 608 function shouldUseClickEvent(elem) { 609 // Use the `click` event to detect changes to checkbox and radio inputs. 610 // This approach works across all browsers, whereas `change` does not fire 611 // until `blur` in IE8. 612 return ( 613 elem.nodeName === 'INPUT' && 614 (elem.type === 'checkbox' || elem.type === 'radio') 615 ); 616 } 617 618 function getTargetIDForClickEvent( 619 topLevelType, 620 topLevelTarget, 621 topLevelTargetID) { 622 if (topLevelType === topLevelTypes.topClick) { 623 return topLevelTargetID; 624 } 625 } 626 627 /** 628 * This plugin creates an `onChange` event that normalizes change events 629 * across form elements. This event fires at a time when it's possible to 630 * change the element's value without seeing a flicker. 631 * 632 * Supported elements are: 633 * - input (see `isTextInputElement`) 634 * - textarea 635 * - select 636 */ 637 var ChangeEventPlugin = { 638 639 eventTypes: eventTypes, 640 641 /** 642 * @param {string} topLevelType Record from `EventConstants`. 643 * @param {DOMEventTarget} topLevelTarget The listening component root node. 644 * @param {string} topLevelTargetID ID of `topLevelTarget`. 645 * @param {object} nativeEvent Native browser event. 646 * @return {*} An accumulation of synthetic events. 647 * @see {EventPluginHub.extractEvents} 648 */ 649 extractEvents: function( 650 topLevelType, 651 topLevelTarget, 652 topLevelTargetID, 653 nativeEvent) { 654 655 var getTargetIDFunc, handleEventFunc; 656 if (shouldUseChangeEvent(topLevelTarget)) { 657 if (doesChangeEventBubble) { 658 getTargetIDFunc = getTargetIDForChangeEvent; 659 } else { 660 handleEventFunc = handleEventsForChangeEventIE8; 661 } 662 } else if (isTextInputElement(topLevelTarget)) { 663 if (isInputEventSupported) { 664 getTargetIDFunc = getTargetIDForInputEvent; 665 } else { 666 getTargetIDFunc = getTargetIDForInputEventIE; 667 handleEventFunc = handleEventsForInputEventIE; 668 } 669 } else if (shouldUseClickEvent(topLevelTarget)) { 670 getTargetIDFunc = getTargetIDForClickEvent; 671 } 672 673 if (getTargetIDFunc) { 674 var targetID = getTargetIDFunc( 675 topLevelType, 676 topLevelTarget, 677 topLevelTargetID 678 ); 679 if (targetID) { 680 var event = SyntheticEvent.getPooled( 681 eventTypes.change, 682 targetID, 683 nativeEvent 684 ); 685 EventPropagators.accumulateTwoPhaseDispatches(event); 686 return event; 687 } 688 } 689 690 if (handleEventFunc) { 691 handleEventFunc( 692 topLevelType, 693 topLevelTarget, 694 topLevelTargetID 695 ); 696 } 697 } 698 699 }; 700 701 module.exports = ChangeEventPlugin; 702 703 },{"./EventConstants":14,"./EventPluginHub":16,"./EventPropagators":19,"./ExecutionEnvironment":20,"./SyntheticEvent":66,"./isEventSupported":99,"./isTextInputElement":101,"./keyOf":105}],6:[function(require,module,exports){ 704 /** 705 * Copyright 2013 Facebook, Inc. 706 * 707 * Licensed under the Apache License, Version 2.0 (the "License"); 708 * you may not use this file except in compliance with the License. 709 * You may obtain a copy of the License at 710 * 711 * http://www.apache.org/licenses/LICENSE-2.0 712 * 713 * Unless required by applicable law or agreed to in writing, software 714 * distributed under the License is distributed on an "AS IS" BASIS, 715 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 716 * See the License for the specific language governing permissions and 717 * limitations under the License. 718 * 719 * @providesModule CompositionEventPlugin 720 * @typechecks static-only 721 */ 722 723 "use strict"; 724 725 var EventConstants = require("./EventConstants"); 726 var EventPropagators = require("./EventPropagators"); 727 var ExecutionEnvironment = require("./ExecutionEnvironment"); 728 var ReactInputSelection = require("./ReactInputSelection"); 729 var SyntheticCompositionEvent = require("./SyntheticCompositionEvent"); 730 731 var getTextContentAccessor = require("./getTextContentAccessor"); 732 var keyOf = require("./keyOf"); 733 734 var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space 735 var START_KEYCODE = 229; 736 737 var useCompositionEvent = ExecutionEnvironment.canUseDOM && 738 'CompositionEvent' in window; 739 var topLevelTypes = EventConstants.topLevelTypes; 740 var currentComposition = null; 741 742 // Events and their corresponding property names. 743 var eventTypes = { 744 compositionEnd: { 745 phasedRegistrationNames: { 746 bubbled: keyOf({onCompositionEnd: null}), 747 captured: keyOf({onCompositionEndCapture: null}) 748 } 749 }, 750 compositionStart: { 751 phasedRegistrationNames: { 752 bubbled: keyOf({onCompositionStart: null}), 753 captured: keyOf({onCompositionStartCapture: null}) 754 } 755 }, 756 compositionUpdate: { 757 phasedRegistrationNames: { 758 bubbled: keyOf({onCompositionUpdate: null}), 759 captured: keyOf({onCompositionUpdateCapture: null}) 760 } 761 } 762 }; 763 764 /** 765 * Translate native top level events into event types. 766 * 767 * @param {string} topLevelType 768 * @return {object} 769 */ 770 function getCompositionEventType(topLevelType) { 771 switch (topLevelType) { 772 case topLevelTypes.topCompositionStart: 773 return eventTypes.compositionStart; 774 case topLevelTypes.topCompositionEnd: 775 return eventTypes.compositionEnd; 776 case topLevelTypes.topCompositionUpdate: 777 return eventTypes.compositionUpdate; 778 } 779 } 780 781 /** 782 * Does our fallback best-guess model think this event signifies that 783 * composition has begun? 784 * 785 * @param {string} topLevelType 786 * @param {object} nativeEvent 787 * @return {boolean} 788 */ 789 function isFallbackStart(topLevelType, nativeEvent) { 790 return ( 791 topLevelType === topLevelTypes.topKeyDown && 792 nativeEvent.keyCode === START_KEYCODE 793 ); 794 } 795 796 /** 797 * Does our fallback mode think that this event is the end of composition? 798 * 799 * @param {string} topLevelType 800 * @param {object} nativeEvent 801 * @return {boolean} 802 */ 803 function isFallbackEnd(topLevelType, nativeEvent) { 804 switch (topLevelType) { 805 case topLevelTypes.topKeyUp: 806 // Command keys insert or clear IME input. 807 return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1); 808 case topLevelTypes.topKeyDown: 809 // Expect IME keyCode on each keydown. If we get any other 810 // code we must have exited earlier. 811 return (nativeEvent.keyCode !== START_KEYCODE); 812 case topLevelTypes.topKeyPress: 813 case topLevelTypes.topMouseDown: 814 case topLevelTypes.topBlur: 815 // Events are not possible without cancelling IME. 816 return true; 817 default: 818 return false; 819 } 820 } 821 822 /** 823 * Helper class stores information about selection and document state 824 * so we can figure out what changed at a later date. 825 * 826 * @param {DOMEventTarget} root 827 */ 828 function FallbackCompositionState(root) { 829 this.root = root; 830 this.startSelection = ReactInputSelection.getSelection(root); 831 this.startValue = this.getText(); 832 } 833 834 /** 835 * Get current text of input. 836 * 837 * @return {string} 838 */ 839 FallbackCompositionState.prototype.getText = function() { 840 return this.root.value || this.root[getTextContentAccessor()]; 841 }; 842 843 /** 844 * Text that has changed since the start of composition. 845 * 846 * @return {string} 847 */ 848 FallbackCompositionState.prototype.getData = function() { 849 var endValue = this.getText(); 850 var prefixLength = this.startSelection.start; 851 var suffixLength = this.startValue.length - this.startSelection.end; 852 853 return endValue.substr( 854 prefixLength, 855 endValue.length - suffixLength - prefixLength 856 ); 857 }; 858 859 /** 860 * This plugin creates `onCompositionStart`, `onCompositionUpdate` and 861 * `onCompositionEnd` events on inputs, textareas and contentEditable 862 * nodes. 863 */ 864 var CompositionEventPlugin = { 865 866 eventTypes: eventTypes, 867 868 /** 869 * @param {string} topLevelType Record from `EventConstants`. 870 * @param {DOMEventTarget} topLevelTarget The listening component root node. 871 * @param {string} topLevelTargetID ID of `topLevelTarget`. 872 * @param {object} nativeEvent Native browser event. 873 * @return {*} An accumulation of synthetic events. 874 * @see {EventPluginHub.extractEvents} 875 */ 876 extractEvents: function( 877 topLevelType, 878 topLevelTarget, 879 topLevelTargetID, 880 nativeEvent) { 881 882 var eventType; 883 var data; 884 885 if (useCompositionEvent) { 886 eventType = getCompositionEventType(topLevelType); 887 } else if (!currentComposition) { 888 if (isFallbackStart(topLevelType, nativeEvent)) { 889 eventType = eventTypes.start; 890 currentComposition = new FallbackCompositionState(topLevelTarget); 891 } 892 } else if (isFallbackEnd(topLevelType, nativeEvent)) { 893 eventType = eventTypes.compositionEnd; 894 data = currentComposition.getData(); 895 currentComposition = null; 896 } 897 898 if (eventType) { 899 var event = SyntheticCompositionEvent.getPooled( 900 eventType, 901 topLevelTargetID, 902 nativeEvent 903 ); 904 if (data) { 905 // Inject data generated from fallback path into the synthetic event. 906 // This matches the property of native CompositionEventInterface. 907 event.data = data; 908 } 909 EventPropagators.accumulateTwoPhaseDispatches(event); 910 return event; 911 } 912 } 913 }; 914 915 module.exports = CompositionEventPlugin; 916 917 },{"./EventConstants":14,"./EventPropagators":19,"./ExecutionEnvironment":20,"./ReactInputSelection":47,"./SyntheticCompositionEvent":65,"./getTextContentAccessor":95,"./keyOf":105}],7:[function(require,module,exports){ 918 /** 919 * Copyright 2013 Facebook, Inc. 920 * 921 * Licensed under the Apache License, Version 2.0 (the "License"); 922 * you may not use this file except in compliance with the License. 923 * You may obtain a copy of the License at 924 * 925 * http://www.apache.org/licenses/LICENSE-2.0 926 * 927 * Unless required by applicable law or agreed to in writing, software 928 * distributed under the License is distributed on an "AS IS" BASIS, 929 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 930 * See the License for the specific language governing permissions and 931 * limitations under the License. 932 * 933 * @providesModule DOMChildrenOperations 934 * @typechecks static-only 935 */ 936 937 "use strict"; 938 939 var Danger = require("./Danger"); 940 var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); 941 942 var getTextContentAccessor = require("./getTextContentAccessor"); 943 944 /** 945 * The DOM property to use when setting text content. 946 * 947 * @type {string} 948 * @private 949 */ 950 var textContentAccessor = getTextContentAccessor() || 'NA'; 951 952 /** 953 * Inserts `childNode` as a child of `parentNode` at the `index`. 954 * 955 * @param {DOMElement} parentNode Parent node in which to insert. 956 * @param {DOMElement} childNode Child node to insert. 957 * @param {number} index Index at which to insert the child. 958 * @internal 959 */ 960 function insertChildAt(parentNode, childNode, index) { 961 var childNodes = parentNode.childNodes; 962 if (childNodes[index] === childNode) { 963 return; 964 } 965 // If `childNode` is already a child of `parentNode`, remove it so that 966 // computing `childNodes[index]` takes into account the removal. 967 if (childNode.parentNode === parentNode) { 968 parentNode.removeChild(childNode); 969 } 970 if (index >= childNodes.length) { 971 parentNode.appendChild(childNode); 972 } else { 973 parentNode.insertBefore(childNode, childNodes[index]); 974 } 975 } 976 977 /** 978 * Operations for updating with DOM children. 979 */ 980 var DOMChildrenOperations = { 981 982 dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, 983 984 /** 985 * Updates a component's children by processing a series of updates. The 986 * update configurations are each expected to have a `parentNode` property. 987 * 988 * @param {array<object>} updates List of update configurations. 989 * @param {array<string>} markupList List of markup strings. 990 * @internal 991 */ 992 processUpdates: function(updates, markupList) { 993 var update; 994 // Mapping from parent IDs to initial child orderings. 995 var initialChildren = null; 996 // List of children that will be moved or removed. 997 var updatedChildren = null; 998 999 for (var i = 0; update = updates[i]; i++) { 1000 if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || 1001 update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { 1002 var updatedIndex = update.fromIndex; 1003 var updatedChild = update.parentNode.childNodes[updatedIndex]; 1004 var parentID = update.parentID; 1005 1006 initialChildren = initialChildren || {}; 1007 initialChildren[parentID] = initialChildren[parentID] || []; 1008 initialChildren[parentID][updatedIndex] = updatedChild; 1009 1010 updatedChildren = updatedChildren || []; 1011 updatedChildren.push(updatedChild); 1012 } 1013 } 1014 1015 var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); 1016 1017 // Remove updated children first so that `toIndex` is consistent. 1018 if (updatedChildren) { 1019 for (var j = 0; j < updatedChildren.length; j++) { 1020 updatedChildren[j].parentNode.removeChild(updatedChildren[j]); 1021 } 1022 } 1023 1024 for (var k = 0; update = updates[k]; k++) { 1025 switch (update.type) { 1026 case ReactMultiChildUpdateTypes.INSERT_MARKUP: 1027 insertChildAt( 1028 update.parentNode, 1029 renderedMarkup[update.markupIndex], 1030 update.toIndex 1031 ); 1032 break; 1033 case ReactMultiChildUpdateTypes.MOVE_EXISTING: 1034 insertChildAt( 1035 update.parentNode, 1036 initialChildren[update.parentID][update.fromIndex], 1037 update.toIndex 1038 ); 1039 break; 1040 case ReactMultiChildUpdateTypes.TEXT_CONTENT: 1041 update.parentNode[textContentAccessor] = update.textContent; 1042 break; 1043 case ReactMultiChildUpdateTypes.REMOVE_NODE: 1044 // Already removed by the for-loop above. 1045 break; 1046 } 1047 } 1048 } 1049 1050 }; 1051 1052 module.exports = DOMChildrenOperations; 1053 1054 },{"./Danger":10,"./ReactMultiChildUpdateTypes":53,"./getTextContentAccessor":95}],8:[function(require,module,exports){ 1055 /** 1056 * Copyright 2013 Facebook, Inc. 1057 * 1058 * Licensed under the Apache License, Version 2.0 (the "License"); 1059 * you may not use this file except in compliance with the License. 1060 * You may obtain a copy of the License at 1061 * 1062 * http://www.apache.org/licenses/LICENSE-2.0 1063 * 1064 * Unless required by applicable law or agreed to in writing, software 1065 * distributed under the License is distributed on an "AS IS" BASIS, 1066 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1067 * See the License for the specific language governing permissions and 1068 * limitations under the License. 1069 * 1070 * @providesModule DOMProperty 1071 * @typechecks static-only 1072 */ 1073 1074 /*jslint bitwise: true */ 1075 1076 "use strict"; 1077 1078 var invariant = require("./invariant"); 1079 1080 var DOMPropertyInjection = { 1081 /** 1082 * Mapping from normalized, camelcased property names to a configuration that 1083 * specifies how the associated DOM property should be accessed or rendered. 1084 */ 1085 MUST_USE_ATTRIBUTE: 0x1, 1086 MUST_USE_PROPERTY: 0x2, 1087 HAS_SIDE_EFFECTS: 0x4, 1088 HAS_BOOLEAN_VALUE: 0x8, 1089 HAS_POSITIVE_NUMERIC_VALUE: 0x10, 1090 1091 /** 1092 * Inject some specialized knowledge about the DOM. This takes a config object 1093 * with the following properties: 1094 * 1095 * isCustomAttribute: function that given an attribute name will return true 1096 * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* 1097 * attributes where it's impossible to enumerate all of the possible 1098 * attribute names, 1099 * 1100 * Properties: object mapping DOM property name to one of the 1101 * DOMPropertyInjection constants or null. If your attribute isn't in here, 1102 * it won't get written to the DOM. 1103 * 1104 * DOMAttributeNames: object mapping React attribute name to the DOM 1105 * attribute name. Attribute names not specified use the **lowercase** 1106 * normalized name. 1107 * 1108 * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. 1109 * Property names not specified use the normalized name. 1110 * 1111 * DOMMutationMethods: Properties that require special mutation methods. If 1112 * `value` is undefined, the mutation method should unset the property. 1113 * 1114 * @param {object} domPropertyConfig the config as described above. 1115 */ 1116 injectDOMPropertyConfig: function(domPropertyConfig) { 1117 var Properties = domPropertyConfig.Properties || {}; 1118 var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; 1119 var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; 1120 var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; 1121 1122 if (domPropertyConfig.isCustomAttribute) { 1123 DOMProperty._isCustomAttributeFunctions.push( 1124 domPropertyConfig.isCustomAttribute 1125 ); 1126 } 1127 1128 for (var propName in Properties) { 1129 ("production" !== "development" ? invariant( 1130 !DOMProperty.isStandardName[propName], 1131 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + 1132 '\'%s\' which has already been injected. You may be accidentally ' + 1133 'injecting the same DOM property config twice, or you may be ' + 1134 'injecting two configs that have conflicting property names.', 1135 propName 1136 ) : invariant(!DOMProperty.isStandardName[propName])); 1137 1138 DOMProperty.isStandardName[propName] = true; 1139 1140 var lowerCased = propName.toLowerCase(); 1141 DOMProperty.getPossibleStandardName[lowerCased] = propName; 1142 1143 var attributeName = DOMAttributeNames[propName]; 1144 if (attributeName) { 1145 DOMProperty.getPossibleStandardName[attributeName] = propName; 1146 } 1147 1148 DOMProperty.getAttributeName[propName] = attributeName || lowerCased; 1149 1150 DOMProperty.getPropertyName[propName] = 1151 DOMPropertyNames[propName] || propName; 1152 1153 var mutationMethod = DOMMutationMethods[propName]; 1154 if (mutationMethod) { 1155 DOMProperty.getMutationMethod[propName] = mutationMethod; 1156 } 1157 1158 var propConfig = Properties[propName]; 1159 DOMProperty.mustUseAttribute[propName] = 1160 propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE; 1161 DOMProperty.mustUseProperty[propName] = 1162 propConfig & DOMPropertyInjection.MUST_USE_PROPERTY; 1163 DOMProperty.hasSideEffects[propName] = 1164 propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS; 1165 DOMProperty.hasBooleanValue[propName] = 1166 propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE; 1167 DOMProperty.hasPositiveNumericValue[propName] = 1168 propConfig & DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE; 1169 1170 ("production" !== "development" ? invariant( 1171 !DOMProperty.mustUseAttribute[propName] || 1172 !DOMProperty.mustUseProperty[propName], 1173 'DOMProperty: Cannot require using both attribute and property: %s', 1174 propName 1175 ) : invariant(!DOMProperty.mustUseAttribute[propName] || 1176 !DOMProperty.mustUseProperty[propName])); 1177 ("production" !== "development" ? invariant( 1178 DOMProperty.mustUseProperty[propName] || 1179 !DOMProperty.hasSideEffects[propName], 1180 'DOMProperty: Properties that have side effects must use property: %s', 1181 propName 1182 ) : invariant(DOMProperty.mustUseProperty[propName] || 1183 !DOMProperty.hasSideEffects[propName])); 1184 ("production" !== "development" ? invariant( 1185 !DOMProperty.hasBooleanValue[propName] || 1186 !DOMProperty.hasPositiveNumericValue[propName], 1187 'DOMProperty: Cannot have both boolean and positive numeric value: %s', 1188 propName 1189 ) : invariant(!DOMProperty.hasBooleanValue[propName] || 1190 !DOMProperty.hasPositiveNumericValue[propName])); 1191 } 1192 } 1193 }; 1194 var defaultValueCache = {}; 1195 1196 /** 1197 * DOMProperty exports lookup objects that can be used like functions: 1198 * 1199 * > DOMProperty.isValid['id'] 1200 * true 1201 * > DOMProperty.isValid['foobar'] 1202 * undefined 1203 * 1204 * Although this may be confusing, it performs better in general. 1205 * 1206 * @see http://jsperf.com/key-exists 1207 * @see http://jsperf.com/key-missing 1208 */ 1209 var DOMProperty = { 1210 1211 /** 1212 * Checks whether a property name is a standard property. 1213 * @type {Object} 1214 */ 1215 isStandardName: {}, 1216 1217 /** 1218 * Mapping from lowercase property names to the properly cased version, used 1219 * to warn in the case of missing properties. 1220 * @type {Object} 1221 */ 1222 getPossibleStandardName: {}, 1223 1224 /** 1225 * Mapping from normalized names to attribute names that differ. Attribute 1226 * names are used when rendering markup or with `*Attribute()`. 1227 * @type {Object} 1228 */ 1229 getAttributeName: {}, 1230 1231 /** 1232 * Mapping from normalized names to properties on DOM node instances. 1233 * (This includes properties that mutate due to external factors.) 1234 * @type {Object} 1235 */ 1236 getPropertyName: {}, 1237 1238 /** 1239 * Mapping from normalized names to mutation methods. This will only exist if 1240 * mutation cannot be set simply by the property or `setAttribute()`. 1241 * @type {Object} 1242 */ 1243 getMutationMethod: {}, 1244 1245 /** 1246 * Whether the property must be accessed and mutated as an object property. 1247 * @type {Object} 1248 */ 1249 mustUseAttribute: {}, 1250 1251 /** 1252 * Whether the property must be accessed and mutated using `*Attribute()`. 1253 * (This includes anything that fails `<propName> in <element>`.) 1254 * @type {Object} 1255 */ 1256 mustUseProperty: {}, 1257 1258 /** 1259 * Whether or not setting a value causes side effects such as triggering 1260 * resources to be loaded or text selection changes. We must ensure that 1261 * the value is only set if it has changed. 1262 * @type {Object} 1263 */ 1264 hasSideEffects: {}, 1265 1266 /** 1267 * Whether the property should be removed when set to a falsey value. 1268 * @type {Object} 1269 */ 1270 hasBooleanValue: {}, 1271 1272 /** 1273 * Whether the property must be positive numeric or parse as a positive 1274 * numeric and should be removed when set to a falsey value. 1275 * @type {Object} 1276 */ 1277 hasPositiveNumericValue: {}, 1278 1279 /** 1280 * All of the isCustomAttribute() functions that have been injected. 1281 */ 1282 _isCustomAttributeFunctions: [], 1283 1284 /** 1285 * Checks whether a property name is a custom attribute. 1286 * @method 1287 */ 1288 isCustomAttribute: function(attributeName) { 1289 return DOMProperty._isCustomAttributeFunctions.some( 1290 function(isCustomAttributeFn) { 1291 return isCustomAttributeFn.call(null, attributeName); 1292 } 1293 ); 1294 }, 1295 1296 /** 1297 * Returns the default property value for a DOM property (i.e., not an 1298 * attribute). Most default values are '' or false, but not all. Worse yet, 1299 * some (in particular, `type`) vary depending on the type of element. 1300 * 1301 * TODO: Is it better to grab all the possible properties when creating an 1302 * element to avoid having to create the same element twice? 1303 */ 1304 getDefaultValueForProperty: function(nodeName, prop) { 1305 var nodeDefaults = defaultValueCache[nodeName]; 1306 var testElement; 1307 if (!nodeDefaults) { 1308 defaultValueCache[nodeName] = nodeDefaults = {}; 1309 } 1310 if (!(prop in nodeDefaults)) { 1311 testElement = document.createElement(nodeName); 1312 nodeDefaults[prop] = testElement[prop]; 1313 } 1314 return nodeDefaults[prop]; 1315 }, 1316 1317 injection: DOMPropertyInjection 1318 }; 1319 1320 module.exports = DOMProperty; 1321 1322 },{"./invariant":98}],9:[function(require,module,exports){ 1323 /** 1324 * Copyright 2013 Facebook, Inc. 1325 * 1326 * Licensed under the Apache License, Version 2.0 (the "License"); 1327 * you may not use this file except in compliance with the License. 1328 * You may obtain a copy of the License at 1329 * 1330 * http://www.apache.org/licenses/LICENSE-2.0 1331 * 1332 * Unless required by applicable law or agreed to in writing, software 1333 * distributed under the License is distributed on an "AS IS" BASIS, 1334 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1335 * See the License for the specific language governing permissions and 1336 * limitations under the License. 1337 * 1338 * @providesModule DOMPropertyOperations 1339 * @typechecks static-only 1340 */ 1341 1342 "use strict"; 1343 1344 var DOMProperty = require("./DOMProperty"); 1345 1346 var escapeTextForBrowser = require("./escapeTextForBrowser"); 1347 var memoizeStringOnly = require("./memoizeStringOnly"); 1348 1349 function shouldIgnoreValue(name, value) { 1350 return value == null || 1351 DOMProperty.hasBooleanValue[name] && !value || 1352 DOMProperty.hasPositiveNumericValue[name] && (isNaN(value) || value < 1); 1353 } 1354 1355 var processAttributeNameAndPrefix = memoizeStringOnly(function(name) { 1356 return escapeTextForBrowser(name) + '="'; 1357 }); 1358 1359 if ("production" !== "development") { 1360 var reactProps = { 1361 __owner__: true, 1362 children: true, 1363 dangerouslySetInnerHTML: true, 1364 key: true, 1365 ref: true 1366 }; 1367 var warnedProperties = {}; 1368 1369 var warnUnknownProperty = function(name) { 1370 if (reactProps[name] || warnedProperties[name]) { 1371 return; 1372 } 1373 1374 warnedProperties[name] = true; 1375 var lowerCasedName = name.toLowerCase(); 1376 1377 // data-* attributes should be lowercase; suggest the lowercase version 1378 var standardName = DOMProperty.isCustomAttribute(lowerCasedName) ? 1379 lowerCasedName : DOMProperty.getPossibleStandardName[lowerCasedName]; 1380 1381 // For now, only warn when we have a suggested correction. This prevents 1382 // logging too much when using transferPropsTo. 1383 if (standardName != null) { 1384 console.warn( 1385 'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?' 1386 ); 1387 } 1388 1389 }; 1390 } 1391 1392 /** 1393 * Operations for dealing with DOM properties. 1394 */ 1395 var DOMPropertyOperations = { 1396 1397 /** 1398 * Creates markup for a property. 1399 * 1400 * @param {string} name 1401 * @param {*} value 1402 * @return {?string} Markup string, or null if the property was invalid. 1403 */ 1404 createMarkupForProperty: function(name, value) { 1405 if (DOMProperty.isStandardName[name]) { 1406 if (shouldIgnoreValue(name, value)) { 1407 return ''; 1408 } 1409 var attributeName = DOMProperty.getAttributeName[name]; 1410 return processAttributeNameAndPrefix(attributeName) + 1411 escapeTextForBrowser(value) + '"'; 1412 } else if (DOMProperty.isCustomAttribute(name)) { 1413 if (value == null) { 1414 return ''; 1415 } 1416 return processAttributeNameAndPrefix(name) + 1417 escapeTextForBrowser(value) + '"'; 1418 } else if ("production" !== "development") { 1419 warnUnknownProperty(name); 1420 } 1421 return null; 1422 }, 1423 1424 /** 1425 * Sets the value for a property on a node. 1426 * 1427 * @param {DOMElement} node 1428 * @param {string} name 1429 * @param {*} value 1430 */ 1431 setValueForProperty: function(node, name, value) { 1432 if (DOMProperty.isStandardName[name]) { 1433 var mutationMethod = DOMProperty.getMutationMethod[name]; 1434 if (mutationMethod) { 1435 mutationMethod(node, value); 1436 } else if (shouldIgnoreValue(name, value)) { 1437 this.deleteValueForProperty(node, name); 1438 } else if (DOMProperty.mustUseAttribute[name]) { 1439 node.setAttribute(DOMProperty.getAttributeName[name], '' + value); 1440 } else { 1441 var propName = DOMProperty.getPropertyName[name]; 1442 if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) { 1443 node[propName] = value; 1444 } 1445 } 1446 } else if (DOMProperty.isCustomAttribute(name)) { 1447 if (value == null) { 1448 node.removeAttribute(DOMProperty.getAttributeName[name]); 1449 } else { 1450 node.setAttribute(name, '' + value); 1451 } 1452 } else if ("production" !== "development") { 1453 warnUnknownProperty(name); 1454 } 1455 }, 1456 1457 /** 1458 * Deletes the value for a property on a node. 1459 * 1460 * @param {DOMElement} node 1461 * @param {string} name 1462 */ 1463 deleteValueForProperty: function(node, name) { 1464 if (DOMProperty.isStandardName[name]) { 1465 var mutationMethod = DOMProperty.getMutationMethod[name]; 1466 if (mutationMethod) { 1467 mutationMethod(node, undefined); 1468 } else if (DOMProperty.mustUseAttribute[name]) { 1469 node.removeAttribute(DOMProperty.getAttributeName[name]); 1470 } else { 1471 var propName = DOMProperty.getPropertyName[name]; 1472 var defaultValue = DOMProperty.getDefaultValueForProperty( 1473 node.nodeName, 1474 name 1475 ); 1476 if (!DOMProperty.hasSideEffects[name] || 1477 node[propName] !== defaultValue) { 1478 node[propName] = defaultValue; 1479 } 1480 } 1481 } else if (DOMProperty.isCustomAttribute(name)) { 1482 node.removeAttribute(name); 1483 } else if ("production" !== "development") { 1484 warnUnknownProperty(name); 1485 } 1486 } 1487 1488 }; 1489 1490 module.exports = DOMPropertyOperations; 1491 1492 },{"./DOMProperty":8,"./escapeTextForBrowser":84,"./memoizeStringOnly":106}],10:[function(require,module,exports){ 1493 /** 1494 * Copyright 2013 Facebook, Inc. 1495 * 1496 * Licensed under the Apache License, Version 2.0 (the "License"); 1497 * you may not use this file except in compliance with the License. 1498 * You may obtain a copy of the License at 1499 * 1500 * http://www.apache.org/licenses/LICENSE-2.0 1501 * 1502 * Unless required by applicable law or agreed to in writing, software 1503 * distributed under the License is distributed on an "AS IS" BASIS, 1504 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1505 * See the License for the specific language governing permissions and 1506 * limitations under the License. 1507 * 1508 * @providesModule Danger 1509 * @typechecks static-only 1510 */ 1511 1512 /*jslint evil: true, sub: true */ 1513 1514 "use strict"; 1515 1516 var ExecutionEnvironment = require("./ExecutionEnvironment"); 1517 1518 var createNodesFromMarkup = require("./createNodesFromMarkup"); 1519 var emptyFunction = require("./emptyFunction"); 1520 var getMarkupWrap = require("./getMarkupWrap"); 1521 var invariant = require("./invariant"); 1522 var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); 1523 1524 var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; 1525 var RESULT_INDEX_ATTR = 'data-danger-index'; 1526 1527 /** 1528 * Extracts the `nodeName` from a string of markup. 1529 * 1530 * NOTE: Extracting the `nodeName` does not require a regular expression match 1531 * because we make assumptions about React-generated markup (i.e. there are no 1532 * spaces surrounding the opening tag and there is at least one attribute). 1533 * 1534 * @param {string} markup String of markup. 1535 * @return {string} Node name of the supplied markup. 1536 * @see http://jsperf.com/extract-nodename 1537 */ 1538 function getNodeName(markup) { 1539 return markup.substring(1, markup.indexOf(' ')); 1540 } 1541 1542 var Danger = { 1543 1544 /** 1545 * Renders markup into an array of nodes. The markup is expected to render 1546 * into a list of root nodes. Also, the length of `resultList` and 1547 * `markupList` should be the same. 1548 * 1549 * @param {array<string>} markupList List of markup strings to render. 1550 * @return {array<DOMElement>} List of rendered nodes. 1551 * @internal 1552 */ 1553 dangerouslyRenderMarkup: function(markupList) { 1554 ("production" !== "development" ? invariant( 1555 ExecutionEnvironment.canUseDOM, 1556 'dangerouslyRenderMarkup(...): Cannot render markup in a Worker ' + 1557 'thread. This is likely a bug in the framework. Please report ' + 1558 'immediately.' 1559 ) : invariant(ExecutionEnvironment.canUseDOM)); 1560 var nodeName; 1561 var markupByNodeName = {}; 1562 // Group markup by `nodeName` if a wrap is necessary, else by '*'. 1563 for (var i = 0; i < markupList.length; i++) { 1564 ("production" !== "development" ? invariant( 1565 markupList[i], 1566 'dangerouslyRenderMarkup(...): Missing markup.' 1567 ) : invariant(markupList[i])); 1568 nodeName = getNodeName(markupList[i]); 1569 nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; 1570 markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; 1571 markupByNodeName[nodeName][i] = markupList[i]; 1572 } 1573 var resultList = []; 1574 var resultListAssignmentCount = 0; 1575 for (nodeName in markupByNodeName) { 1576 if (!markupByNodeName.hasOwnProperty(nodeName)) { 1577 continue; 1578 } 1579 var markupListByNodeName = markupByNodeName[nodeName]; 1580 1581 // This for-in loop skips the holes of the sparse array. The order of 1582 // iteration should follow the order of assignment, which happens to match 1583 // numerical index order, but we don't rely on that. 1584 for (var resultIndex in markupListByNodeName) { 1585 if (markupListByNodeName.hasOwnProperty(resultIndex)) { 1586 var markup = markupListByNodeName[resultIndex]; 1587 1588 // Push the requested markup with an additional RESULT_INDEX_ATTR 1589 // attribute. If the markup does not start with a < character, it 1590 // will be discarded below (with an appropriate console.error). 1591 markupListByNodeName[resultIndex] = markup.replace( 1592 OPEN_TAG_NAME_EXP, 1593 // This index will be parsed back out below. 1594 '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" ' 1595 ); 1596 } 1597 } 1598 1599 // Render each group of markup with similar wrapping `nodeName`. 1600 var renderNodes = createNodesFromMarkup( 1601 markupListByNodeName.join(''), 1602 emptyFunction // Do nothing special with <script> tags. 1603 ); 1604 1605 for (i = 0; i < renderNodes.length; ++i) { 1606 var renderNode = renderNodes[i]; 1607 if (renderNode.hasAttribute && 1608 renderNode.hasAttribute(RESULT_INDEX_ATTR)) { 1609 1610 resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR); 1611 renderNode.removeAttribute(RESULT_INDEX_ATTR); 1612 1613 ("production" !== "development" ? invariant( 1614 !resultList.hasOwnProperty(resultIndex), 1615 'Danger: Assigning to an already-occupied result index.' 1616 ) : invariant(!resultList.hasOwnProperty(resultIndex))); 1617 1618 resultList[resultIndex] = renderNode; 1619 1620 // This should match resultList.length and markupList.length when 1621 // we're done. 1622 resultListAssignmentCount += 1; 1623 1624 } else if ("production" !== "development") { 1625 console.error( 1626 "Danger: Discarding unexpected node:", 1627 renderNode 1628 ); 1629 } 1630 } 1631 } 1632 1633 // Although resultList was populated out of order, it should now be a dense 1634 // array. 1635 ("production" !== "development" ? invariant( 1636 resultListAssignmentCount === resultList.length, 1637 'Danger: Did not assign to every index of resultList.' 1638 ) : invariant(resultListAssignmentCount === resultList.length)); 1639 1640 ("production" !== "development" ? invariant( 1641 resultList.length === markupList.length, 1642 'Danger: Expected markup to render %s nodes, but rendered %s.', 1643 markupList.length, 1644 resultList.length 1645 ) : invariant(resultList.length === markupList.length)); 1646 1647 return resultList; 1648 }, 1649 1650 /** 1651 * Replaces a node with a string of markup at its current position within its 1652 * parent. The markup must render into a single root node. 1653 * 1654 * @param {DOMElement} oldChild Child node to replace. 1655 * @param {string} markup Markup to render in place of the child node. 1656 * @internal 1657 */ 1658 dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) { 1659 ("production" !== "development" ? invariant( 1660 ExecutionEnvironment.canUseDOM, 1661 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' + 1662 'worker thread. This is likely a bug in the framework. Please report ' + 1663 'immediately.' 1664 ) : invariant(ExecutionEnvironment.canUseDOM)); 1665 ("production" !== "development" ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup)); 1666 // createNodesFromMarkup() won't work if the markup is rooted by <html> 1667 // since it has special semantic meaning. So we use an alternatie strategy. 1668 if (oldChild.tagName.toLowerCase() === 'html') { 1669 mutateHTMLNodeWithMarkup(oldChild, markup); 1670 return; 1671 } 1672 var newChild = createNodesFromMarkup(markup, emptyFunction)[0]; 1673 oldChild.parentNode.replaceChild(newChild, oldChild); 1674 } 1675 1676 }; 1677 1678 module.exports = Danger; 1679 1680 },{"./ExecutionEnvironment":20,"./createNodesFromMarkup":80,"./emptyFunction":83,"./getMarkupWrap":92,"./invariant":98,"./mutateHTMLNodeWithMarkup":111}],11:[function(require,module,exports){ 1681 /** 1682 * Copyright 2013 Facebook, Inc. 1683 * 1684 * Licensed under the Apache License, Version 2.0 (the "License"); 1685 * you may not use this file except in compliance with the License. 1686 * You may obtain a copy of the License at 1687 * 1688 * http://www.apache.org/licenses/LICENSE-2.0 1689 * 1690 * Unless required by applicable law or agreed to in writing, software 1691 * distributed under the License is distributed on an "AS IS" BASIS, 1692 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1693 * See the License for the specific language governing permissions and 1694 * limitations under the License. 1695 * 1696 * @providesModule DefaultDOMPropertyConfig 1697 */ 1698 1699 /*jslint bitwise: true*/ 1700 1701 "use strict"; 1702 1703 var DOMProperty = require("./DOMProperty"); 1704 1705 var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE; 1706 var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; 1707 var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE; 1708 var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS; 1709 var HAS_POSITIVE_NUMERIC_VALUE = 1710 DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE; 1711 1712 var DefaultDOMPropertyConfig = { 1713 isCustomAttribute: RegExp.prototype.test.bind( 1714 /^(data|aria)-[a-z_][a-z\d_.\-]*$/ 1715 ), 1716 Properties: { 1717 /** 1718 * Standard Properties 1719 */ 1720 accept: null, 1721 accessKey: null, 1722 action: null, 1723 allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, 1724 allowTransparency: MUST_USE_ATTRIBUTE, 1725 alt: null, 1726 async: HAS_BOOLEAN_VALUE, 1727 autoComplete: null, 1728 autoFocus: HAS_BOOLEAN_VALUE, 1729 autoPlay: HAS_BOOLEAN_VALUE, 1730 cellPadding: null, 1731 cellSpacing: null, 1732 charSet: MUST_USE_ATTRIBUTE, 1733 checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1734 className: MUST_USE_PROPERTY, 1735 cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, 1736 colSpan: null, 1737 content: null, 1738 contentEditable: null, 1739 contextMenu: MUST_USE_ATTRIBUTE, 1740 controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1741 data: null, // For `<object />` acts as `src`. 1742 dateTime: MUST_USE_ATTRIBUTE, 1743 defer: HAS_BOOLEAN_VALUE, 1744 dir: null, 1745 disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, 1746 draggable: null, 1747 encType: null, 1748 form: MUST_USE_ATTRIBUTE, 1749 frameBorder: MUST_USE_ATTRIBUTE, 1750 height: MUST_USE_ATTRIBUTE, 1751 hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, 1752 href: null, 1753 htmlFor: null, 1754 httpEquiv: null, 1755 icon: null, 1756 id: MUST_USE_PROPERTY, 1757 label: null, 1758 lang: null, 1759 list: null, 1760 loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1761 max: null, 1762 maxLength: MUST_USE_ATTRIBUTE, 1763 method: null, 1764 min: null, 1765 multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1766 name: null, 1767 pattern: null, 1768 placeholder: null, 1769 poster: null, 1770 preload: null, 1771 radioGroup: null, 1772 readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1773 rel: null, 1774 required: HAS_BOOLEAN_VALUE, 1775 role: MUST_USE_ATTRIBUTE, 1776 rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, 1777 rowSpan: null, 1778 scrollLeft: MUST_USE_PROPERTY, 1779 scrollTop: MUST_USE_PROPERTY, 1780 selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, 1781 size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE, 1782 spellCheck: null, 1783 src: null, 1784 step: null, 1785 style: null, 1786 tabIndex: null, 1787 target: null, 1788 title: null, 1789 type: null, 1790 value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS, 1791 width: MUST_USE_ATTRIBUTE, 1792 wmode: MUST_USE_ATTRIBUTE, 1793 1794 /** 1795 * Non-standard Properties 1796 */ 1797 autoCapitalize: null, // Supported in Mobile Safari for keyboard hints 1798 autoCorrect: null, // Supported in Mobile Safari for keyboard hints 1799 1800 /** 1801 * SVG Properties 1802 */ 1803 cx: MUST_USE_ATTRIBUTE, 1804 cy: MUST_USE_ATTRIBUTE, 1805 d: MUST_USE_ATTRIBUTE, 1806 fill: MUST_USE_ATTRIBUTE, 1807 fx: MUST_USE_ATTRIBUTE, 1808 fy: MUST_USE_ATTRIBUTE, 1809 gradientTransform: MUST_USE_ATTRIBUTE, 1810 gradientUnits: MUST_USE_ATTRIBUTE, 1811 offset: MUST_USE_ATTRIBUTE, 1812 points: MUST_USE_ATTRIBUTE, 1813 r: MUST_USE_ATTRIBUTE, 1814 rx: MUST_USE_ATTRIBUTE, 1815 ry: MUST_USE_ATTRIBUTE, 1816 spreadMethod: MUST_USE_ATTRIBUTE, 1817 stopColor: MUST_USE_ATTRIBUTE, 1818 stopOpacity: MUST_USE_ATTRIBUTE, 1819 stroke: MUST_USE_ATTRIBUTE, 1820 strokeLinecap: MUST_USE_ATTRIBUTE, 1821 strokeWidth: MUST_USE_ATTRIBUTE, 1822 transform: MUST_USE_ATTRIBUTE, 1823 version: MUST_USE_ATTRIBUTE, 1824 viewBox: MUST_USE_ATTRIBUTE, 1825 x1: MUST_USE_ATTRIBUTE, 1826 x2: MUST_USE_ATTRIBUTE, 1827 x: MUST_USE_ATTRIBUTE, 1828 y1: MUST_USE_ATTRIBUTE, 1829 y2: MUST_USE_ATTRIBUTE, 1830 y: MUST_USE_ATTRIBUTE 1831 }, 1832 DOMAttributeNames: { 1833 className: 'class', 1834 gradientTransform: 'gradientTransform', 1835 gradientUnits: 'gradientUnits', 1836 htmlFor: 'for', 1837 spreadMethod: 'spreadMethod', 1838 stopColor: 'stop-color', 1839 stopOpacity: 'stop-opacity', 1840 strokeLinecap: 'stroke-linecap', 1841 strokeWidth: 'stroke-width', 1842 viewBox: 'viewBox' 1843 }, 1844 DOMPropertyNames: { 1845 autoCapitalize: 'autocapitalize', 1846 autoComplete: 'autocomplete', 1847 autoCorrect: 'autocorrect', 1848 autoFocus: 'autofocus', 1849 autoPlay: 'autoplay', 1850 encType: 'enctype', 1851 radioGroup: 'radiogroup', 1852 spellCheck: 'spellcheck' 1853 }, 1854 DOMMutationMethods: { 1855 /** 1856 * Setting `className` to null may cause it to be set to the string "null". 1857 * 1858 * @param {DOMElement} node 1859 * @param {*} value 1860 */ 1861 className: function(node, value) { 1862 node.className = value || ''; 1863 } 1864 } 1865 }; 1866 1867 module.exports = DefaultDOMPropertyConfig; 1868 1869 },{"./DOMProperty":8}],12:[function(require,module,exports){ 1870 /** 1871 * Copyright 2013 Facebook, Inc. 1872 * 1873 * Licensed under the Apache License, Version 2.0 (the "License"); 1874 * you may not use this file except in compliance with the License. 1875 * You may obtain a copy of the License at 1876 * 1877 * http://www.apache.org/licenses/LICENSE-2.0 1878 * 1879 * Unless required by applicable law or agreed to in writing, software 1880 * distributed under the License is distributed on an "AS IS" BASIS, 1881 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1882 * See the License for the specific language governing permissions and 1883 * limitations under the License. 1884 * 1885 * @providesModule DefaultEventPluginOrder 1886 */ 1887 1888 "use strict"; 1889 1890 var keyOf = require("./keyOf"); 1891 1892 /** 1893 * Module that is injectable into `EventPluginHub`, that specifies a 1894 * deterministic ordering of `EventPlugin`s. A convenient way to reason about 1895 * plugins, without having to package every one of them. This is better than 1896 * having plugins be ordered in the same order that they are injected because 1897 * that ordering would be influenced by the packaging order. 1898 * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that 1899 * preventing default on events is convenient in `SimpleEventPlugin` handlers. 1900 */ 1901 var DefaultEventPluginOrder = [ 1902 keyOf({ResponderEventPlugin: null}), 1903 keyOf({SimpleEventPlugin: null}), 1904 keyOf({TapEventPlugin: null}), 1905 keyOf({EnterLeaveEventPlugin: null}), 1906 keyOf({ChangeEventPlugin: null}), 1907 keyOf({SelectEventPlugin: null}), 1908 keyOf({CompositionEventPlugin: null}), 1909 keyOf({AnalyticsEventPlugin: null}), 1910 keyOf({MobileSafariClickEventPlugin: null}) 1911 ]; 1912 1913 module.exports = DefaultEventPluginOrder; 1914 1915 },{"./keyOf":105}],13:[function(require,module,exports){ 1916 /** 1917 * Copyright 2013 Facebook, Inc. 1918 * 1919 * Licensed under the Apache License, Version 2.0 (the "License"); 1920 * you may not use this file except in compliance with the License. 1921 * You may obtain a copy of the License at 1922 * 1923 * http://www.apache.org/licenses/LICENSE-2.0 1924 * 1925 * Unless required by applicable law or agreed to in writing, software 1926 * distributed under the License is distributed on an "AS IS" BASIS, 1927 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1928 * See the License for the specific language governing permissions and 1929 * limitations under the License. 1930 * 1931 * @providesModule EnterLeaveEventPlugin 1932 * @typechecks static-only 1933 */ 1934 1935 "use strict"; 1936 1937 var EventConstants = require("./EventConstants"); 1938 var EventPropagators = require("./EventPropagators"); 1939 var SyntheticMouseEvent = require("./SyntheticMouseEvent"); 1940 1941 var ReactMount = require("./ReactMount"); 1942 var keyOf = require("./keyOf"); 1943 1944 var topLevelTypes = EventConstants.topLevelTypes; 1945 var getFirstReactDOM = ReactMount.getFirstReactDOM; 1946 1947 var eventTypes = { 1948 mouseEnter: {registrationName: keyOf({onMouseEnter: null})}, 1949 mouseLeave: {registrationName: keyOf({onMouseLeave: null})} 1950 }; 1951 1952 var extractedEvents = [null, null]; 1953 1954 var EnterLeaveEventPlugin = { 1955 1956 eventTypes: eventTypes, 1957 1958 /** 1959 * For almost every interaction we care about, there will be both a top-level 1960 * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that 1961 * we do not extract duplicate events. However, moving the mouse into the 1962 * browser from outside will not fire a `mouseout` event. In this case, we use 1963 * the `mouseover` top-level event. 1964 * 1965 * @param {string} topLevelType Record from `EventConstants`. 1966 * @param {DOMEventTarget} topLevelTarget The listening component root node. 1967 * @param {string} topLevelTargetID ID of `topLevelTarget`. 1968 * @param {object} nativeEvent Native browser event. 1969 * @return {*} An accumulation of synthetic events. 1970 * @see {EventPluginHub.extractEvents} 1971 */ 1972 extractEvents: function( 1973 topLevelType, 1974 topLevelTarget, 1975 topLevelTargetID, 1976 nativeEvent) { 1977 if (topLevelType === topLevelTypes.topMouseOver && 1978 (nativeEvent.relatedTarget || nativeEvent.fromElement)) { 1979 return null; 1980 } 1981 if (topLevelType !== topLevelTypes.topMouseOut && 1982 topLevelType !== topLevelTypes.topMouseOver) { 1983 // Must not be a mouse in or mouse out - ignoring. 1984 return null; 1985 } 1986 1987 var from, to; 1988 if (topLevelType === topLevelTypes.topMouseOut) { 1989 from = topLevelTarget; 1990 to = 1991 getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || 1992 window; 1993 } else { 1994 from = window; 1995 to = topLevelTarget; 1996 } 1997 1998 if (from === to) { 1999 // Nothing pertains to our managed components. 2000 return null; 2001 } 2002 2003 var fromID = from ? ReactMount.getID(from) : ''; 2004 var toID = to ? ReactMount.getID(to) : ''; 2005 2006 var leave = SyntheticMouseEvent.getPooled( 2007 eventTypes.mouseLeave, 2008 fromID, 2009 nativeEvent 2010 ); 2011 var enter = SyntheticMouseEvent.getPooled( 2012 eventTypes.mouseEnter, 2013 toID, 2014 nativeEvent 2015 ); 2016 2017 EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID); 2018 2019 extractedEvents[0] = leave; 2020 extractedEvents[1] = enter; 2021 2022 return extractedEvents; 2023 } 2024 2025 }; 2026 2027 module.exports = EnterLeaveEventPlugin; 2028 2029 },{"./EventConstants":14,"./EventPropagators":19,"./ReactMount":50,"./SyntheticMouseEvent":69,"./keyOf":105}],14:[function(require,module,exports){ 2030 /** 2031 * Copyright 2013 Facebook, Inc. 2032 * 2033 * Licensed under the Apache License, Version 2.0 (the "License"); 2034 * you may not use this file except in compliance with the License. 2035 * You may obtain a copy of the License at 2036 * 2037 * http://www.apache.org/licenses/LICENSE-2.0 2038 * 2039 * Unless required by applicable law or agreed to in writing, software 2040 * distributed under the License is distributed on an "AS IS" BASIS, 2041 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2042 * See the License for the specific language governing permissions and 2043 * limitations under the License. 2044 * 2045 * @providesModule EventConstants 2046 */ 2047 2048 "use strict"; 2049 2050 var keyMirror = require("./keyMirror"); 2051 2052 var PropagationPhases = keyMirror({bubbled: null, captured: null}); 2053 2054 /** 2055 * Types of raw signals from the browser caught at the top level. 2056 */ 2057 var topLevelTypes = keyMirror({ 2058 topBlur: null, 2059 topChange: null, 2060 topClick: null, 2061 topCompositionEnd: null, 2062 topCompositionStart: null, 2063 topCompositionUpdate: null, 2064 topContextMenu: null, 2065 topCopy: null, 2066 topCut: null, 2067 topDoubleClick: null, 2068 topDrag: null, 2069 topDragEnd: null, 2070 topDragEnter: null, 2071 topDragExit: null, 2072 topDragLeave: null, 2073 topDragOver: null, 2074 topDragStart: null, 2075 topDrop: null, 2076 topFocus: null, 2077 topInput: null, 2078 topKeyDown: null, 2079 topKeyPress: null, 2080 topKeyUp: null, 2081 topMouseDown: null, 2082 topMouseMove: null, 2083 topMouseOut: null, 2084 topMouseOver: null, 2085 topMouseUp: null, 2086 topPaste: null, 2087 topScroll: null, 2088 topSelectionChange: null, 2089 topSubmit: null, 2090 topTouchCancel: null, 2091 topTouchEnd: null, 2092 topTouchMove: null, 2093 topTouchStart: null, 2094 topWheel: null 2095 }); 2096 2097 var EventConstants = { 2098 topLevelTypes: topLevelTypes, 2099 PropagationPhases: PropagationPhases 2100 }; 2101 2102 module.exports = EventConstants; 2103 2104 },{"./keyMirror":104}],15:[function(require,module,exports){ 2105 /** 2106 * Copyright 2013 Facebook, Inc. 2107 * 2108 * Licensed under the Apache License, Version 2.0 (the "License"); 2109 * you may not use this file except in compliance with the License. 2110 * You may obtain a copy of the License at 2111 * 2112 * http://www.apache.org/licenses/LICENSE-2.0 2113 * 2114 * Unless required by applicable law or agreed to in writing, software 2115 * distributed under the License is distributed on an "AS IS" BASIS, 2116 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2117 * See the License for the specific language governing permissions and 2118 * limitations under the License. 2119 * 2120 * @providesModule EventListener 2121 */ 2122 2123 /** 2124 * Upstream version of event listener. Does not take into account specific 2125 * nature of platform. 2126 */ 2127 var EventListener = { 2128 /** 2129 * Listens to bubbled events on a DOM node. 2130 * 2131 * @param {Element} el DOM element to register listener on. 2132 * @param {string} handlerBaseName 'click'/'mouseover' 2133 * @param {Function!} cb Callback function 2134 */ 2135 listen: function(el, handlerBaseName, cb) { 2136 if (el.addEventListener) { 2137 el.addEventListener(handlerBaseName, cb, false); 2138 } else if (el.attachEvent) { 2139 el.attachEvent('on' + handlerBaseName, cb); 2140 } 2141 }, 2142 2143 /** 2144 * Listens to captured events on a DOM node. 2145 * 2146 * @see `EventListener.listen` for params. 2147 * @throws Exception if addEventListener is not supported. 2148 */ 2149 capture: function(el, handlerBaseName, cb) { 2150 if (!el.addEventListener) { 2151 if ("production" !== "development") { 2152 console.error( 2153 'You are attempting to use addEventListener ' + 2154 'in a browser that does not support it.' + 2155 'This likely means that you will not receive events that ' + 2156 'your application relies on (such as scroll).'); 2157 } 2158 return; 2159 } else { 2160 el.addEventListener(handlerBaseName, cb, true); 2161 } 2162 } 2163 }; 2164 2165 module.exports = EventListener; 2166 2167 },{}],16:[function(require,module,exports){ 2168 /** 2169 * Copyright 2013 Facebook, Inc. 2170 * 2171 * Licensed under the Apache License, Version 2.0 (the "License"); 2172 * you may not use this file except in compliance with the License. 2173 * You may obtain a copy of the License at 2174 * 2175 * http://www.apache.org/licenses/LICENSE-2.0 2176 * 2177 * Unless required by applicable law or agreed to in writing, software 2178 * distributed under the License is distributed on an "AS IS" BASIS, 2179 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2180 * See the License for the specific language governing permissions and 2181 * limitations under the License. 2182 * 2183 * @providesModule EventPluginHub 2184 */ 2185 2186 "use strict"; 2187 2188 var CallbackRegistry = require("./CallbackRegistry"); 2189 var EventPluginRegistry = require("./EventPluginRegistry"); 2190 var EventPluginUtils = require("./EventPluginUtils"); 2191 var EventPropagators = require("./EventPropagators"); 2192 var ExecutionEnvironment = require("./ExecutionEnvironment"); 2193 2194 var accumulate = require("./accumulate"); 2195 var forEachAccumulated = require("./forEachAccumulated"); 2196 var invariant = require("./invariant"); 2197 2198 /** 2199 * Internal queue of events that have accumulated their dispatches and are 2200 * waiting to have their dispatches executed. 2201 */ 2202 var eventQueue = null; 2203 2204 /** 2205 * Dispatches an event and releases it back into the pool, unless persistent. 2206 * 2207 * @param {?object} event Synthetic event to be dispatched. 2208 * @private 2209 */ 2210 var executeDispatchesAndRelease = function(event) { 2211 if (event) { 2212 var executeDispatch = EventPluginUtils.executeDispatch; 2213 // Plugins can provide custom behavior when dispatching events. 2214 var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event); 2215 if (PluginModule && PluginModule.executeDispatch) { 2216 executeDispatch = PluginModule.executeDispatch; 2217 } 2218 EventPluginUtils.executeDispatchesInOrder(event, executeDispatch); 2219 2220 if (!event.isPersistent()) { 2221 event.constructor.release(event); 2222 } 2223 } 2224 }; 2225 2226 /** 2227 * This is a unified interface for event plugins to be installed and configured. 2228 * 2229 * Event plugins can implement the following properties: 2230 * 2231 * `extractEvents` {function(string, DOMEventTarget, string, object): *} 2232 * Required. When a top-level event is fired, this method is expected to 2233 * extract synthetic events that will in turn be queued and dispatched. 2234 * 2235 * `eventTypes` {object} 2236 * Optional, plugins that fire events must publish a mapping of registration 2237 * names that are used to register listeners. Values of this mapping must 2238 * be objects that contain `registrationName` or `phasedRegistrationNames`. 2239 * 2240 * `executeDispatch` {function(object, function, string)} 2241 * Optional, allows plugins to override how an event gets dispatched. By 2242 * default, the listener is simply invoked. 2243 * 2244 * Each plugin that is injected into `EventsPluginHub` is immediately operable. 2245 * 2246 * @public 2247 */ 2248 var EventPluginHub = { 2249 2250 /** 2251 * Methods for injecting dependencies. 2252 */ 2253 injection: { 2254 2255 /** 2256 * @param {object} InjectedInstanceHandle 2257 * @public 2258 */ 2259 injectInstanceHandle: EventPropagators.injection.injectInstanceHandle, 2260 2261 /** 2262 * @param {array} InjectedEventPluginOrder 2263 * @public 2264 */ 2265 injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder, 2266 2267 /** 2268 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 2269 */ 2270 injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName 2271 2272 }, 2273 2274 registrationNames: EventPluginRegistry.registrationNames, 2275 2276 putListener: CallbackRegistry.putListener, 2277 2278 getListener: CallbackRegistry.getListener, 2279 2280 deleteListener: CallbackRegistry.deleteListener, 2281 2282 deleteAllListeners: CallbackRegistry.deleteAllListeners, 2283 2284 /** 2285 * Allows registered plugins an opportunity to extract events from top-level 2286 * native browser events. 2287 * 2288 * @param {string} topLevelType Record from `EventConstants`. 2289 * @param {DOMEventTarget} topLevelTarget The listening component root node. 2290 * @param {string} topLevelTargetID ID of `topLevelTarget`. 2291 * @param {object} nativeEvent Native browser event. 2292 * @return {*} An accumulation of synthetic events. 2293 * @internal 2294 */ 2295 extractEvents: function( 2296 topLevelType, 2297 topLevelTarget, 2298 topLevelTargetID, 2299 nativeEvent) { 2300 var events; 2301 var plugins = EventPluginRegistry.plugins; 2302 for (var i = 0, l = plugins.length; i < l; i++) { 2303 // Not every plugin in the ordering may be loaded at runtime. 2304 var possiblePlugin = plugins[i]; 2305 if (possiblePlugin) { 2306 var extractedEvents = possiblePlugin.extractEvents( 2307 topLevelType, 2308 topLevelTarget, 2309 topLevelTargetID, 2310 nativeEvent 2311 ); 2312 if (extractedEvents) { 2313 events = accumulate(events, extractedEvents); 2314 } 2315 } 2316 } 2317 return events; 2318 }, 2319 2320 /** 2321 * Enqueues a synthetic event that should be dispatched when 2322 * `processEventQueue` is invoked. 2323 * 2324 * @param {*} events An accumulation of synthetic events. 2325 * @internal 2326 */ 2327 enqueueEvents: function(events) { 2328 if (events) { 2329 eventQueue = accumulate(eventQueue, events); 2330 } 2331 }, 2332 2333 /** 2334 * Dispatches all synthetic events on the event queue. 2335 * 2336 * @internal 2337 */ 2338 processEventQueue: function() { 2339 // Set `eventQueue` to null before processing it so that we can tell if more 2340 // events get enqueued while processing. 2341 var processingEventQueue = eventQueue; 2342 eventQueue = null; 2343 forEachAccumulated(processingEventQueue, executeDispatchesAndRelease); 2344 ("production" !== "development" ? invariant( 2345 !eventQueue, 2346 'processEventQueue(): Additional events were enqueued while processing ' + 2347 'an event queue. Support for this has not yet been implemented.' 2348 ) : invariant(!eventQueue)); 2349 } 2350 2351 }; 2352 2353 if (ExecutionEnvironment.canUseDOM) { 2354 window.EventPluginHub = EventPluginHub; 2355 } 2356 2357 module.exports = EventPluginHub; 2358 2359 },{"./CallbackRegistry":4,"./EventPluginRegistry":17,"./EventPluginUtils":18,"./EventPropagators":19,"./ExecutionEnvironment":20,"./accumulate":75,"./forEachAccumulated":88,"./invariant":98}],17:[function(require,module,exports){ 2360 /** 2361 * Copyright 2013 Facebook, Inc. 2362 * 2363 * Licensed under the Apache License, Version 2.0 (the "License"); 2364 * you may not use this file except in compliance with the License. 2365 * You may obtain a copy of the License at 2366 * 2367 * http://www.apache.org/licenses/LICENSE-2.0 2368 * 2369 * Unless required by applicable law or agreed to in writing, software 2370 * distributed under the License is distributed on an "AS IS" BASIS, 2371 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2372 * See the License for the specific language governing permissions and 2373 * limitations under the License. 2374 * 2375 * @providesModule EventPluginRegistry 2376 * @typechecks static-only 2377 */ 2378 2379 "use strict"; 2380 2381 var invariant = require("./invariant"); 2382 2383 /** 2384 * Injectable ordering of event plugins. 2385 */ 2386 var EventPluginOrder = null; 2387 2388 /** 2389 * Injectable mapping from names to event plugin modules. 2390 */ 2391 var namesToPlugins = {}; 2392 2393 /** 2394 * Recomputes the plugin list using the injected plugins and plugin ordering. 2395 * 2396 * @private 2397 */ 2398 function recomputePluginOrdering() { 2399 if (!EventPluginOrder) { 2400 // Wait until an `EventPluginOrder` is injected. 2401 return; 2402 } 2403 for (var pluginName in namesToPlugins) { 2404 var PluginModule = namesToPlugins[pluginName]; 2405 var pluginIndex = EventPluginOrder.indexOf(pluginName); 2406 ("production" !== "development" ? invariant( 2407 pluginIndex > -1, 2408 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + 2409 'the plugin ordering, `%s`.', 2410 pluginName 2411 ) : invariant(pluginIndex > -1)); 2412 if (EventPluginRegistry.plugins[pluginIndex]) { 2413 continue; 2414 } 2415 ("production" !== "development" ? invariant( 2416 PluginModule.extractEvents, 2417 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + 2418 'method, but `%s` does not.', 2419 pluginName 2420 ) : invariant(PluginModule.extractEvents)); 2421 EventPluginRegistry.plugins[pluginIndex] = PluginModule; 2422 var publishedEvents = PluginModule.eventTypes; 2423 for (var eventName in publishedEvents) { 2424 ("production" !== "development" ? invariant( 2425 publishEventForPlugin(publishedEvents[eventName], PluginModule), 2426 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', 2427 eventName, 2428 pluginName 2429 ) : invariant(publishEventForPlugin(publishedEvents[eventName], PluginModule))); 2430 } 2431 } 2432 } 2433 2434 /** 2435 * Publishes an event so that it can be dispatched by the supplied plugin. 2436 * 2437 * @param {object} dispatchConfig Dispatch configuration for the event. 2438 * @param {object} PluginModule Plugin publishing the event. 2439 * @return {boolean} True if the event was successfully published. 2440 * @private 2441 */ 2442 function publishEventForPlugin(dispatchConfig, PluginModule) { 2443 var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; 2444 if (phasedRegistrationNames) { 2445 for (var phaseName in phasedRegistrationNames) { 2446 if (phasedRegistrationNames.hasOwnProperty(phaseName)) { 2447 var phasedRegistrationName = phasedRegistrationNames[phaseName]; 2448 publishRegistrationName(phasedRegistrationName, PluginModule); 2449 } 2450 } 2451 return true; 2452 } else if (dispatchConfig.registrationName) { 2453 publishRegistrationName(dispatchConfig.registrationName, PluginModule); 2454 return true; 2455 } 2456 return false; 2457 } 2458 2459 /** 2460 * Publishes a registration name that is used to identify dispatched events and 2461 * can be used with `EventPluginHub.putListener` to register listeners. 2462 * 2463 * @param {string} registrationName Registration name to add. 2464 * @param {object} PluginModule Plugin publishing the event. 2465 * @private 2466 */ 2467 function publishRegistrationName(registrationName, PluginModule) { 2468 ("production" !== "development" ? invariant( 2469 !EventPluginRegistry.registrationNames[registrationName], 2470 'EventPluginHub: More than one plugin attempted to publish the same ' + 2471 'registration name, `%s`.', 2472 registrationName 2473 ) : invariant(!EventPluginRegistry.registrationNames[registrationName])); 2474 EventPluginRegistry.registrationNames[registrationName] = PluginModule; 2475 } 2476 2477 /** 2478 * Registers plugins so that they can extract and dispatch events. 2479 * 2480 * @see {EventPluginHub} 2481 */ 2482 var EventPluginRegistry = { 2483 2484 /** 2485 * Ordered list of injected plugins. 2486 */ 2487 plugins: [], 2488 2489 /** 2490 * Mapping from registration names to plugin modules. 2491 */ 2492 registrationNames: {}, 2493 2494 /** 2495 * Injects an ordering of plugins (by plugin name). This allows the ordering 2496 * to be decoupled from injection of the actual plugins so that ordering is 2497 * always deterministic regardless of packaging, on-the-fly injection, etc. 2498 * 2499 * @param {array} InjectedEventPluginOrder 2500 * @internal 2501 * @see {EventPluginHub.injection.injectEventPluginOrder} 2502 */ 2503 injectEventPluginOrder: function(InjectedEventPluginOrder) { 2504 ("production" !== "development" ? invariant( 2505 !EventPluginOrder, 2506 'EventPluginRegistry: Cannot inject event plugin ordering more than once.' 2507 ) : invariant(!EventPluginOrder)); 2508 // Clone the ordering so it cannot be dynamically mutated. 2509 EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); 2510 recomputePluginOrdering(); 2511 }, 2512 2513 /** 2514 * Injects plugins to be used by `EventPluginHub`. The plugin names must be 2515 * in the ordering injected by `injectEventPluginOrder`. 2516 * 2517 * Plugins can be injected as part of page initialization or on-the-fly. 2518 * 2519 * @param {object} injectedNamesToPlugins Map from names to plugin modules. 2520 * @internal 2521 * @see {EventPluginHub.injection.injectEventPluginsByName} 2522 */ 2523 injectEventPluginsByName: function(injectedNamesToPlugins) { 2524 var isOrderingDirty = false; 2525 for (var pluginName in injectedNamesToPlugins) { 2526 if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { 2527 continue; 2528 } 2529 var PluginModule = injectedNamesToPlugins[pluginName]; 2530 if (namesToPlugins[pluginName] !== PluginModule) { 2531 ("production" !== "development" ? invariant( 2532 !namesToPlugins[pluginName], 2533 'EventPluginRegistry: Cannot inject two different event plugins ' + 2534 'using the same name, `%s`.', 2535 pluginName 2536 ) : invariant(!namesToPlugins[pluginName])); 2537 namesToPlugins[pluginName] = PluginModule; 2538 isOrderingDirty = true; 2539 } 2540 } 2541 if (isOrderingDirty) { 2542 recomputePluginOrdering(); 2543 } 2544 }, 2545 2546 /** 2547 * Looks up the plugin for the supplied event. 2548 * 2549 * @param {object} event A synthetic event. 2550 * @return {?object} The plugin that created the supplied event. 2551 * @internal 2552 */ 2553 getPluginModuleForEvent: function(event) { 2554 var dispatchConfig = event.dispatchConfig; 2555 if (dispatchConfig.registrationName) { 2556 return EventPluginRegistry.registrationNames[ 2557 dispatchConfig.registrationName 2558 ] || null; 2559 } 2560 for (var phase in dispatchConfig.phasedRegistrationNames) { 2561 if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { 2562 continue; 2563 } 2564 var PluginModule = EventPluginRegistry.registrationNames[ 2565 dispatchConfig.phasedRegistrationNames[phase] 2566 ]; 2567 if (PluginModule) { 2568 return PluginModule; 2569 } 2570 } 2571 return null; 2572 }, 2573 2574 /** 2575 * Exposed for unit testing. 2576 * @private 2577 */ 2578 _resetEventPlugins: function() { 2579 EventPluginOrder = null; 2580 for (var pluginName in namesToPlugins) { 2581 if (namesToPlugins.hasOwnProperty(pluginName)) { 2582 delete namesToPlugins[pluginName]; 2583 } 2584 } 2585 EventPluginRegistry.plugins.length = 0; 2586 var registrationNames = EventPluginRegistry.registrationNames; 2587 for (var registrationName in registrationNames) { 2588 if (registrationNames.hasOwnProperty(registrationName)) { 2589 delete registrationNames[registrationName]; 2590 } 2591 } 2592 } 2593 2594 }; 2595 2596 module.exports = EventPluginRegistry; 2597 2598 },{"./invariant":98}],18:[function(require,module,exports){ 2599 /** 2600 * Copyright 2013 Facebook, Inc. 2601 * 2602 * Licensed under the Apache License, Version 2.0 (the "License"); 2603 * you may not use this file except in compliance with the License. 2604 * You may obtain a copy of the License at 2605 * 2606 * http://www.apache.org/licenses/LICENSE-2.0 2607 * 2608 * Unless required by applicable law or agreed to in writing, software 2609 * distributed under the License is distributed on an "AS IS" BASIS, 2610 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2611 * See the License for the specific language governing permissions and 2612 * limitations under the License. 2613 * 2614 * @providesModule EventPluginUtils 2615 */ 2616 2617 "use strict"; 2618 2619 var EventConstants = require("./EventConstants"); 2620 2621 var invariant = require("./invariant"); 2622 2623 var topLevelTypes = EventConstants.topLevelTypes; 2624 2625 function isEndish(topLevelType) { 2626 return topLevelType === topLevelTypes.topMouseUp || 2627 topLevelType === topLevelTypes.topTouchEnd || 2628 topLevelType === topLevelTypes.topTouchCancel; 2629 } 2630 2631 function isMoveish(topLevelType) { 2632 return topLevelType === topLevelTypes.topMouseMove || 2633 topLevelType === topLevelTypes.topTouchMove; 2634 } 2635 function isStartish(topLevelType) { 2636 return topLevelType === topLevelTypes.topMouseDown || 2637 topLevelType === topLevelTypes.topTouchStart; 2638 } 2639 2640 var validateEventDispatches; 2641 if ("production" !== "development") { 2642 validateEventDispatches = function(event) { 2643 var dispatchListeners = event._dispatchListeners; 2644 var dispatchIDs = event._dispatchIDs; 2645 2646 var listenersIsArr = Array.isArray(dispatchListeners); 2647 var idsIsArr = Array.isArray(dispatchIDs); 2648 var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; 2649 var listenersLen = listenersIsArr ? 2650 dispatchListeners.length : 2651 dispatchListeners ? 1 : 0; 2652 2653 ("production" !== "development" ? invariant( 2654 idsIsArr === listenersIsArr && IDsLen === listenersLen, 2655 'EventPluginUtils: Invalid `event`.' 2656 ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen)); 2657 }; 2658 } 2659 2660 /** 2661 * Invokes `cb(event, listener, id)`. Avoids using call if no scope is 2662 * provided. The `(listener,id)` pair effectively forms the "dispatch" but are 2663 * kept separate to conserve memory. 2664 */ 2665 function forEachEventDispatch(event, cb) { 2666 var dispatchListeners = event._dispatchListeners; 2667 var dispatchIDs = event._dispatchIDs; 2668 if ("production" !== "development") { 2669 validateEventDispatches(event); 2670 } 2671 if (Array.isArray(dispatchListeners)) { 2672 for (var i = 0; i < dispatchListeners.length; i++) { 2673 if (event.isPropagationStopped()) { 2674 break; 2675 } 2676 // Listeners and IDs are two parallel arrays that are always in sync. 2677 cb(event, dispatchListeners[i], dispatchIDs[i]); 2678 } 2679 } else if (dispatchListeners) { 2680 cb(event, dispatchListeners, dispatchIDs); 2681 } 2682 } 2683 2684 /** 2685 * Default implementation of PluginModule.executeDispatch(). 2686 * @param {SyntheticEvent} SyntheticEvent to handle 2687 * @param {function} Application-level callback 2688 * @param {string} domID DOM id to pass to the callback. 2689 */ 2690 function executeDispatch(event, listener, domID) { 2691 listener(event, domID); 2692 } 2693 2694 /** 2695 * Standard/simple iteration through an event's collected dispatches. 2696 */ 2697 function executeDispatchesInOrder(event, executeDispatch) { 2698 forEachEventDispatch(event, executeDispatch); 2699 event._dispatchListeners = null; 2700 event._dispatchIDs = null; 2701 } 2702 2703 /** 2704 * Standard/simple iteration through an event's collected dispatches, but stops 2705 * at the first dispatch execution returning true, and returns that id. 2706 * 2707 * @return id of the first dispatch execution who's listener returns true, or 2708 * null if no listener returned true. 2709 */ 2710 function executeDispatchesInOrderStopAtTrue(event) { 2711 var dispatchListeners = event._dispatchListeners; 2712 var dispatchIDs = event._dispatchIDs; 2713 if ("production" !== "development") { 2714 validateEventDispatches(event); 2715 } 2716 if (Array.isArray(dispatchListeners)) { 2717 for (var i = 0; i < dispatchListeners.length; i++) { 2718 if (event.isPropagationStopped()) { 2719 break; 2720 } 2721 // Listeners and IDs are two parallel arrays that are always in sync. 2722 if (dispatchListeners[i](event, dispatchIDs[i])) { 2723 return dispatchIDs[i]; 2724 } 2725 } 2726 } else if (dispatchListeners) { 2727 if (dispatchListeners(event, dispatchIDs)) { 2728 return dispatchIDs; 2729 } 2730 } 2731 return null; 2732 } 2733 2734 /** 2735 * Execution of a "direct" dispatch - there must be at most one dispatch 2736 * accumulated on the event or it is considered an error. It doesn't really make 2737 * sense for an event with multiple dispatches (bubbled) to keep track of the 2738 * return values at each dispatch execution, but it does tend to make sense when 2739 * dealing with "direct" dispatches. 2740 * 2741 * @return The return value of executing the single dispatch. 2742 */ 2743 function executeDirectDispatch(event) { 2744 if ("production" !== "development") { 2745 validateEventDispatches(event); 2746 } 2747 var dispatchListener = event._dispatchListeners; 2748 var dispatchID = event._dispatchIDs; 2749 ("production" !== "development" ? invariant( 2750 !Array.isArray(dispatchListener), 2751 'executeDirectDispatch(...): Invalid `event`.' 2752 ) : invariant(!Array.isArray(dispatchListener))); 2753 var res = dispatchListener ? 2754 dispatchListener(event, dispatchID) : 2755 null; 2756 event._dispatchListeners = null; 2757 event._dispatchIDs = null; 2758 return res; 2759 } 2760 2761 /** 2762 * @param {SyntheticEvent} event 2763 * @return {bool} True iff number of dispatches accumulated is greater than 0. 2764 */ 2765 function hasDispatches(event) { 2766 return !!event._dispatchListeners; 2767 } 2768 2769 /** 2770 * General utilities that are useful in creating custom Event Plugins. 2771 */ 2772 var EventPluginUtils = { 2773 isEndish: isEndish, 2774 isMoveish: isMoveish, 2775 isStartish: isStartish, 2776 executeDispatchesInOrder: executeDispatchesInOrder, 2777 executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, 2778 executeDirectDispatch: executeDirectDispatch, 2779 hasDispatches: hasDispatches, 2780 executeDispatch: executeDispatch 2781 }; 2782 2783 module.exports = EventPluginUtils; 2784 2785 },{"./EventConstants":14,"./invariant":98}],19:[function(require,module,exports){ 2786 /** 2787 * Copyright 2013 Facebook, Inc. 2788 * 2789 * Licensed under the Apache License, Version 2.0 (the "License"); 2790 * you may not use this file except in compliance with the License. 2791 * You may obtain a copy of the License at 2792 * 2793 * http://www.apache.org/licenses/LICENSE-2.0 2794 * 2795 * Unless required by applicable law or agreed to in writing, software 2796 * distributed under the License is distributed on an "AS IS" BASIS, 2797 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2798 * See the License for the specific language governing permissions and 2799 * limitations under the License. 2800 * 2801 * @providesModule EventPropagators 2802 */ 2803 2804 "use strict"; 2805 2806 var CallbackRegistry = require("./CallbackRegistry"); 2807 var EventConstants = require("./EventConstants"); 2808 2809 var accumulate = require("./accumulate"); 2810 var forEachAccumulated = require("./forEachAccumulated"); 2811 var getListener = CallbackRegistry.getListener; 2812 var PropagationPhases = EventConstants.PropagationPhases; 2813 2814 /** 2815 * Injected dependencies: 2816 */ 2817 2818 /** 2819 * - `InstanceHandle`: [required] Module that performs logical traversals of DOM 2820 * hierarchy given ids of the logical DOM elements involved. 2821 */ 2822 var injection = { 2823 InstanceHandle: null, 2824 injectInstanceHandle: function(InjectedInstanceHandle) { 2825 injection.InstanceHandle = InjectedInstanceHandle; 2826 if ("production" !== "development") { 2827 injection.validate(); 2828 } 2829 }, 2830 validate: function() { 2831 var invalid = !injection.InstanceHandle|| 2832 !injection.InstanceHandle.traverseTwoPhase || 2833 !injection.InstanceHandle.traverseEnterLeave; 2834 if (invalid) { 2835 throw new Error('InstanceHandle not injected before use!'); 2836 } 2837 } 2838 }; 2839 2840 /** 2841 * Some event types have a notion of different registration names for different 2842 * "phases" of propagation. This finds listeners by a given phase. 2843 */ 2844 function listenerAtPhase(id, event, propagationPhase) { 2845 var registrationName = 2846 event.dispatchConfig.phasedRegistrationNames[propagationPhase]; 2847 return getListener(id, registrationName); 2848 } 2849 2850 /** 2851 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function 2852 * here, allows us to not have to bind or create functions for each event. 2853 * Mutating the event's members allows us to not have to create a wrapping 2854 * "dispatch" object that pairs the event with the listener. 2855 */ 2856 function accumulateDirectionalDispatches(domID, upwards, event) { 2857 if ("production" !== "development") { 2858 if (!domID) { 2859 throw new Error('Dispatching id must not be null'); 2860 } 2861 injection.validate(); 2862 } 2863 var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; 2864 var listener = listenerAtPhase(domID, event, phase); 2865 if (listener) { 2866 event._dispatchListeners = accumulate(event._dispatchListeners, listener); 2867 event._dispatchIDs = accumulate(event._dispatchIDs, domID); 2868 } 2869 } 2870 2871 /** 2872 * Collect dispatches (must be entirely collected before dispatching - see unit 2873 * tests). Lazily allocate the array to conserve memory. We must loop through 2874 * each event and perform the traversal for each one. We can not perform a 2875 * single traversal for the entire collection of events because each event may 2876 * have a different target. 2877 */ 2878 function accumulateTwoPhaseDispatchesSingle(event) { 2879 if (event && event.dispatchConfig.phasedRegistrationNames) { 2880 injection.InstanceHandle.traverseTwoPhase( 2881 event.dispatchMarker, 2882 accumulateDirectionalDispatches, 2883 event 2884 ); 2885 } 2886 } 2887 2888 2889 /** 2890 * Accumulates without regard to direction, does not look for phased 2891 * registration names. Same as `accumulateDirectDispatchesSingle` but without 2892 * requiring that the `dispatchMarker` be the same as the dispatched ID. 2893 */ 2894 function accumulateDispatches(id, ignoredDirection, event) { 2895 if (event && event.dispatchConfig.registrationName) { 2896 var registrationName = event.dispatchConfig.registrationName; 2897 var listener = getListener(id, registrationName); 2898 if (listener) { 2899 event._dispatchListeners = accumulate(event._dispatchListeners, listener); 2900 event._dispatchIDs = accumulate(event._dispatchIDs, id); 2901 } 2902 } 2903 } 2904 2905 /** 2906 * Accumulates dispatches on an `SyntheticEvent`, but only for the 2907 * `dispatchMarker`. 2908 * @param {SyntheticEvent} event 2909 */ 2910 function accumulateDirectDispatchesSingle(event) { 2911 if (event && event.dispatchConfig.registrationName) { 2912 accumulateDispatches(event.dispatchMarker, null, event); 2913 } 2914 } 2915 2916 function accumulateTwoPhaseDispatches(events) { 2917 if ("production" !== "development") { 2918 injection.validate(); 2919 } 2920 forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); 2921 } 2922 2923 function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { 2924 if ("production" !== "development") { 2925 injection.validate(); 2926 } 2927 injection.InstanceHandle.traverseEnterLeave( 2928 fromID, 2929 toID, 2930 accumulateDispatches, 2931 leave, 2932 enter 2933 ); 2934 } 2935 2936 2937 function accumulateDirectDispatches(events) { 2938 if ("production" !== "development") { 2939 injection.validate(); 2940 } 2941 forEachAccumulated(events, accumulateDirectDispatchesSingle); 2942 } 2943 2944 2945 2946 /** 2947 * A small set of propagation patterns, each of which will accept a small amount 2948 * of information, and generate a set of "dispatch ready event objects" - which 2949 * are sets of events that have already been annotated with a set of dispatched 2950 * listener functions/ids. The API is designed this way to discourage these 2951 * propagation strategies from actually executing the dispatches, since we 2952 * always want to collect the entire set of dispatches before executing event a 2953 * single one. 2954 * 2955 * @constructor EventPropagators 2956 */ 2957 var EventPropagators = { 2958 accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, 2959 accumulateDirectDispatches: accumulateDirectDispatches, 2960 accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches, 2961 injection: injection 2962 }; 2963 2964 module.exports = EventPropagators; 2965 2966 },{"./CallbackRegistry":4,"./EventConstants":14,"./accumulate":75,"./forEachAccumulated":88}],20:[function(require,module,exports){ 2967 /** 2968 * Copyright 2013 Facebook, Inc. 2969 * 2970 * Licensed under the Apache License, Version 2.0 (the "License"); 2971 * you may not use this file except in compliance with the License. 2972 * You may obtain a copy of the License at 2973 * 2974 * http://www.apache.org/licenses/LICENSE-2.0 2975 * 2976 * Unless required by applicable law or agreed to in writing, software 2977 * distributed under the License is distributed on an "AS IS" BASIS, 2978 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2979 * See the License for the specific language governing permissions and 2980 * limitations under the License. 2981 * 2982 * @providesModule ExecutionEnvironment 2983 */ 2984 2985 /*jslint evil: true */ 2986 2987 "use strict"; 2988 2989 var canUseDOM = typeof window !== 'undefined'; 2990 2991 /** 2992 * Simple, lightweight module assisting with the detection and context of 2993 * Worker. Helps avoid circular dependencies and allows code to reason about 2994 * whether or not they are in a Worker, even if they never include the main 2995 * `ReactWorker` dependency. 2996 */ 2997 var ExecutionEnvironment = { 2998 2999 canUseDOM: canUseDOM, 3000 3001 canUseWorkers: typeof Worker !== 'undefined', 3002 3003 isInWorker: !canUseDOM // For now, this is true - might change in the future. 3004 3005 }; 3006 3007 module.exports = ExecutionEnvironment; 3008 3009 },{}],21:[function(require,module,exports){ 3010 /** 3011 * Copyright 2013 Facebook, Inc. 3012 * 3013 * Licensed under the Apache License, Version 2.0 (the "License"); 3014 * you may not use this file except in compliance with the License. 3015 * You may obtain a copy of the License at 3016 * 3017 * http://www.apache.org/licenses/LICENSE-2.0 3018 * 3019 * Unless required by applicable law or agreed to in writing, software 3020 * distributed under the License is distributed on an "AS IS" BASIS, 3021 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3022 * See the License for the specific language governing permissions and 3023 * limitations under the License. 3024 * 3025 * @providesModule LinkedValueMixin 3026 * @typechecks static-only 3027 */ 3028 3029 "use strict"; 3030 3031 var invariant = require("./invariant"); 3032 3033 /** 3034 * Provide a linked `value` attribute for controlled forms. You should not use 3035 * this outside of the ReactDOM controlled form components. 3036 */ 3037 var LinkedValueMixin = { 3038 _assertLink: function() { 3039 ("production" !== "development" ? invariant( 3040 this.props.value == null && this.props.onChange == null, 3041 'Cannot provide a valueLink and a value or onChange event. If you ' + 3042 'want to use value or onChange, you probably don\'t want to use ' + 3043 'valueLink' 3044 ) : invariant(this.props.value == null && this.props.onChange == null)); 3045 }, 3046 3047 /** 3048 * @return {*} current value of the input either from value prop or link. 3049 */ 3050 getValue: function() { 3051 if (this.props.valueLink) { 3052 this._assertLink(); 3053 return this.props.valueLink.value; 3054 } 3055 return this.props.value; 3056 }, 3057 3058 /** 3059 * @return {function} change callback either from onChange prop or link. 3060 */ 3061 getOnChange: function() { 3062 if (this.props.valueLink) { 3063 this._assertLink(); 3064 return this._handleLinkedValueChange; 3065 } 3066 return this.props.onChange; 3067 }, 3068 3069 /** 3070 * @param {SyntheticEvent} e change event to handle 3071 */ 3072 _handleLinkedValueChange: function(e) { 3073 this.props.valueLink.requestChange(e.target.value); 3074 } 3075 }; 3076 3077 module.exports = LinkedValueMixin; 3078 3079 },{"./invariant":98}],22:[function(require,module,exports){ 3080 /** 3081 * Copyright 2013 Facebook, Inc. 3082 * 3083 * Licensed under the Apache License, Version 2.0 (the "License"); 3084 * you may not use this file except in compliance with the License. 3085 * You may obtain a copy of the License at 3086 * 3087 * http://www.apache.org/licenses/LICENSE-2.0 3088 * 3089 * Unless required by applicable law or agreed to in writing, software 3090 * distributed under the License is distributed on an "AS IS" BASIS, 3091 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3092 * See the License for the specific language governing permissions and 3093 * limitations under the License. 3094 * 3095 * @providesModule MobileSafariClickEventPlugin 3096 * @typechecks static-only 3097 */ 3098 3099 "use strict"; 3100 3101 var EventConstants = require("./EventConstants"); 3102 3103 var emptyFunction = require("./emptyFunction"); 3104 3105 var topLevelTypes = EventConstants.topLevelTypes; 3106 3107 /** 3108 * Mobile Safari does not fire properly bubble click events on non-interactive 3109 * elements, which means delegated click listeners do not fire. The workaround 3110 * for this bug involves attaching an empty click listener on the target node. 3111 * 3112 * This particular plugin works around the bug by attaching an empty click 3113 * listener on `touchstart` (which does fire on every element). 3114 */ 3115 var MobileSafariClickEventPlugin = { 3116 3117 eventTypes: null, 3118 3119 /** 3120 * @param {string} topLevelType Record from `EventConstants`. 3121 * @param {DOMEventTarget} topLevelTarget The listening component root node. 3122 * @param {string} topLevelTargetID ID of `topLevelTarget`. 3123 * @param {object} nativeEvent Native browser event. 3124 * @return {*} An accumulation of synthetic events. 3125 * @see {EventPluginHub.extractEvents} 3126 */ 3127 extractEvents: function( 3128 topLevelType, 3129 topLevelTarget, 3130 topLevelTargetID, 3131 nativeEvent) { 3132 if (topLevelType === topLevelTypes.topTouchStart) { 3133 var target = nativeEvent.target; 3134 if (target && !target.onclick) { 3135 target.onclick = emptyFunction; 3136 } 3137 } 3138 } 3139 3140 }; 3141 3142 module.exports = MobileSafariClickEventPlugin; 3143 3144 },{"./EventConstants":14,"./emptyFunction":83}],23:[function(require,module,exports){ 3145 /** 3146 * Copyright 2013 Facebook, Inc. 3147 * 3148 * Licensed under the Apache License, Version 2.0 (the "License"); 3149 * you may not use this file except in compliance with the License. 3150 * You may obtain a copy of the License at 3151 * 3152 * http://www.apache.org/licenses/LICENSE-2.0 3153 * 3154 * Unless required by applicable law or agreed to in writing, software 3155 * distributed under the License is distributed on an "AS IS" BASIS, 3156 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3157 * See the License for the specific language governing permissions and 3158 * limitations under the License. 3159 * 3160 * @providesModule PooledClass 3161 */ 3162 3163 "use strict"; 3164 3165 /** 3166 * Static poolers. Several custom versions for each potential number of 3167 * arguments. A completely generic pooler is easy to implement, but would 3168 * require accessing the `arguments` object. In each of these, `this` refers to 3169 * the Class itself, not an instance. If any others are needed, simply add them 3170 * here, or in their own files. 3171 */ 3172 var oneArgumentPooler = function(copyFieldsFrom) { 3173 var Klass = this; 3174 if (Klass.instancePool.length) { 3175 var instance = Klass.instancePool.pop(); 3176 Klass.call(instance, copyFieldsFrom); 3177 return instance; 3178 } else { 3179 return new Klass(copyFieldsFrom); 3180 } 3181 }; 3182 3183 var twoArgumentPooler = function(a1, a2) { 3184 var Klass = this; 3185 if (Klass.instancePool.length) { 3186 var instance = Klass.instancePool.pop(); 3187 Klass.call(instance, a1, a2); 3188 return instance; 3189 } else { 3190 return new Klass(a1, a2); 3191 } 3192 }; 3193 3194 var threeArgumentPooler = function(a1, a2, a3) { 3195 var Klass = this; 3196 if (Klass.instancePool.length) { 3197 var instance = Klass.instancePool.pop(); 3198 Klass.call(instance, a1, a2, a3); 3199 return instance; 3200 } else { 3201 return new Klass(a1, a2, a3); 3202 } 3203 }; 3204 3205 var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { 3206 var Klass = this; 3207 if (Klass.instancePool.length) { 3208 var instance = Klass.instancePool.pop(); 3209 Klass.call(instance, a1, a2, a3, a4, a5); 3210 return instance; 3211 } else { 3212 return new Klass(a1, a2, a3, a4, a5); 3213 } 3214 }; 3215 3216 var standardReleaser = function(instance) { 3217 var Klass = this; 3218 if (instance.destructor) { 3219 instance.destructor(); 3220 } 3221 if (Klass.instancePool.length < Klass.poolSize) { 3222 Klass.instancePool.push(instance); 3223 } 3224 }; 3225 3226 var DEFAULT_POOL_SIZE = 10; 3227 var DEFAULT_POOLER = oneArgumentPooler; 3228 3229 /** 3230 * Augments `CopyConstructor` to be a poolable class, augmenting only the class 3231 * itself (statically) not adding any prototypical fields. Any CopyConstructor 3232 * you give this may have a `poolSize` property, and will look for a 3233 * prototypical `destructor` on instances (optional). 3234 * 3235 * @param {Function} CopyConstructor Constructor that can be used to reset. 3236 * @param {Function} pooler Customizable pooler. 3237 */ 3238 var addPoolingTo = function(CopyConstructor, pooler) { 3239 var NewKlass = CopyConstructor; 3240 NewKlass.instancePool = []; 3241 NewKlass.getPooled = pooler || DEFAULT_POOLER; 3242 if (!NewKlass.poolSize) { 3243 NewKlass.poolSize = DEFAULT_POOL_SIZE; 3244 } 3245 NewKlass.release = standardReleaser; 3246 return NewKlass; 3247 }; 3248 3249 var PooledClass = { 3250 addPoolingTo: addPoolingTo, 3251 oneArgumentPooler: oneArgumentPooler, 3252 twoArgumentPooler: twoArgumentPooler, 3253 threeArgumentPooler: threeArgumentPooler, 3254 fiveArgumentPooler: fiveArgumentPooler 3255 }; 3256 3257 module.exports = PooledClass; 3258 3259 },{}],24:[function(require,module,exports){ 3260 /** 3261 * Copyright 2013 Facebook, Inc. 3262 * 3263 * Licensed under the Apache License, Version 2.0 (the "License"); 3264 * you may not use this file except in compliance with the License. 3265 * You may obtain a copy of the License at 3266 * 3267 * http://www.apache.org/licenses/LICENSE-2.0 3268 * 3269 * Unless required by applicable law or agreed to in writing, software 3270 * distributed under the License is distributed on an "AS IS" BASIS, 3271 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3272 * See the License for the specific language governing permissions and 3273 * limitations under the License. 3274 * 3275 * @providesModule React 3276 */ 3277 3278 "use strict"; 3279 3280 var ReactComponent = require("./ReactComponent"); 3281 var ReactCompositeComponent = require("./ReactCompositeComponent"); 3282 var ReactCurrentOwner = require("./ReactCurrentOwner"); 3283 var ReactDOM = require("./ReactDOM"); 3284 var ReactDOMComponent = require("./ReactDOMComponent"); 3285 var ReactDefaultInjection = require("./ReactDefaultInjection"); 3286 var ReactInstanceHandles = require("./ReactInstanceHandles"); 3287 var ReactMount = require("./ReactMount"); 3288 var ReactMultiChild = require("./ReactMultiChild"); 3289 var ReactPerf = require("./ReactPerf"); 3290 var ReactPropTypes = require("./ReactPropTypes"); 3291 var ReactServerRendering = require("./ReactServerRendering"); 3292 var ReactTextComponent = require("./ReactTextComponent"); 3293 3294 ReactDefaultInjection.inject(); 3295 3296 var React = { 3297 DOM: ReactDOM, 3298 PropTypes: ReactPropTypes, 3299 initializeTouchEvents: function(shouldUseTouch) { 3300 ReactMount.useTouchEvents = shouldUseTouch; 3301 }, 3302 createClass: ReactCompositeComponent.createClass, 3303 constructAndRenderComponent: ReactMount.constructAndRenderComponent, 3304 constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID, 3305 renderComponent: ReactPerf.measure( 3306 'React', 3307 'renderComponent', 3308 ReactMount.renderComponent 3309 ), 3310 renderComponentToString: ReactServerRendering.renderComponentToString, 3311 unmountComponentAtNode: ReactMount.unmountComponentAtNode, 3312 unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, 3313 isValidClass: ReactCompositeComponent.isValidClass, 3314 isValidComponent: ReactComponent.isValidComponent, 3315 __internals: { 3316 Component: ReactComponent, 3317 CurrentOwner: ReactCurrentOwner, 3318 DOMComponent: ReactDOMComponent, 3319 InstanceHandles: ReactInstanceHandles, 3320 Mount: ReactMount, 3321 MultiChild: ReactMultiChild, 3322 TextComponent: ReactTextComponent 3323 } 3324 }; 3325 3326 // Version exists only in the open-source version of React, not in Facebook's 3327 // internal version. 3328 React.version = '0.8.0'; 3329 3330 module.exports = React; 3331 3332 },{"./ReactComponent":25,"./ReactCompositeComponent":28,"./ReactCurrentOwner":29,"./ReactDOM":30,"./ReactDOMComponent":32,"./ReactDefaultInjection":41,"./ReactInstanceHandles":48,"./ReactMount":50,"./ReactMultiChild":52,"./ReactPerf":55,"./ReactPropTypes":57,"./ReactServerRendering":59,"./ReactTextComponent":60}],25:[function(require,module,exports){ 3333 /** 3334 * Copyright 2013 Facebook, Inc. 3335 * 3336 * Licensed under the Apache License, Version 2.0 (the "License"); 3337 * you may not use this file except in compliance with the License. 3338 * You may obtain a copy of the License at 3339 * 3340 * http://www.apache.org/licenses/LICENSE-2.0 3341 * 3342 * Unless required by applicable law or agreed to in writing, software 3343 * distributed under the License is distributed on an "AS IS" BASIS, 3344 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3345 * See the License for the specific language governing permissions and 3346 * limitations under the License. 3347 * 3348 * @providesModule ReactComponent 3349 */ 3350 3351 "use strict"; 3352 3353 var ReactComponentEnvironment = require("./ReactComponentEnvironment"); 3354 var ReactCurrentOwner = require("./ReactCurrentOwner"); 3355 var ReactOwner = require("./ReactOwner"); 3356 var ReactUpdates = require("./ReactUpdates"); 3357 3358 var invariant = require("./invariant"); 3359 var keyMirror = require("./keyMirror"); 3360 var merge = require("./merge"); 3361 3362 /** 3363 * Every React component is in one of these life cycles. 3364 */ 3365 var ComponentLifeCycle = keyMirror({ 3366 /** 3367 * Mounted components have a DOM node representation and are capable of 3368 * receiving new props. 3369 */ 3370 MOUNTED: null, 3371 /** 3372 * Unmounted components are inactive and cannot receive new props. 3373 */ 3374 UNMOUNTED: null 3375 }); 3376 3377 /** 3378 * Warn if there's no key explicitly set on dynamic arrays of children. 3379 * This allows us to keep track of children between updates. 3380 */ 3381 3382 var ownerHasWarned = {}; 3383 3384 /** 3385 * Warn if the component doesn't have an explicit key assigned to it. 3386 * This component is in an array. The array could grow and shrink or be 3387 * reordered. All children, that hasn't already been validated, are required to 3388 * have a "key" property assigned to it. 3389 * 3390 * @internal 3391 * @param {ReactComponent} component Component that requires a key. 3392 */ 3393 function validateExplicitKey(component) { 3394 if (component.__keyValidated__ || component.props.key != null) { 3395 return; 3396 } 3397 component.__keyValidated__ = true; 3398 3399 // We can't provide friendly warnings for top level components. 3400 if (!ReactCurrentOwner.current) { 3401 return; 3402 } 3403 3404 // Name of the component whose render method tried to pass children. 3405 var currentName = ReactCurrentOwner.current.constructor.displayName; 3406 if (ownerHasWarned.hasOwnProperty(currentName)) { 3407 return; 3408 } 3409 ownerHasWarned[currentName] = true; 3410 3411 var message = 'Each child in an array should have a unique "key" prop. ' + 3412 'Check the render method of ' + currentName + '.'; 3413 if (!component.isOwnedBy(ReactCurrentOwner.current)) { 3414 // Name of the component that originally created this child. 3415 var childOwnerName = 3416 component.props.__owner__ && 3417 component.props.__owner__.constructor.displayName; 3418 3419 // Usually the current owner is the offender, but if it accepts 3420 // children as a property, it may be the creator of the child that's 3421 // responsible for assigning it a key. 3422 message += ' It was passed a child from ' + childOwnerName + '.'; 3423 } 3424 3425 console.warn(message); 3426 } 3427 3428 /** 3429 * Ensure that every component either is passed in a static location or, if 3430 * if it's passed in an array, has an explicit key property defined. 3431 * 3432 * @internal 3433 * @param {*} component Statically passed child of any type. 3434 * @return {boolean} 3435 */ 3436 function validateChildKeys(component) { 3437 if (Array.isArray(component)) { 3438 for (var i = 0; i < component.length; i++) { 3439 var child = component[i]; 3440 if (ReactComponent.isValidComponent(child)) { 3441 validateExplicitKey(child); 3442 } 3443 } 3444 } else if (ReactComponent.isValidComponent(component)) { 3445 // This component was passed in a valid location. 3446 component.__keyValidated__ = true; 3447 } 3448 } 3449 3450 /** 3451 * Components are the basic units of composition in React. 3452 * 3453 * Every component accepts a set of keyed input parameters known as "props" that 3454 * are initialized by the constructor. Once a component is mounted, the props 3455 * can be mutated using `setProps` or `replaceProps`. 3456 * 3457 * Every component is capable of the following operations: 3458 * 3459 * `mountComponent` 3460 * Initializes the component, renders markup, and registers event listeners. 3461 * 3462 * `receiveComponent` 3463 * Updates the rendered DOM nodes to match the given component. 3464 * 3465 * `unmountComponent` 3466 * Releases any resources allocated by this component. 3467 * 3468 * Components can also be "owned" by other components. Being owned by another 3469 * component means being constructed by that component. This is different from 3470 * being the child of a component, which means having a DOM representation that 3471 * is a child of the DOM representation of that component. 3472 * 3473 * @class ReactComponent 3474 */ 3475 var ReactComponent = { 3476 3477 /** 3478 * @param {?object} object 3479 * @return {boolean} True if `object` is a valid component. 3480 * @final 3481 */ 3482 isValidComponent: function(object) { 3483 return !!( 3484 object && 3485 typeof object.mountComponentIntoNode === 'function' && 3486 typeof object.receiveComponent === 'function' 3487 ); 3488 }, 3489 3490 /** 3491 * Generate a key string that identifies a component within a set. 3492 * 3493 * @param {*} component A component that could contain a manual key. 3494 * @param {number} index Index that is used if a manual key is not provided. 3495 * @return {string} 3496 * @internal 3497 */ 3498 getKey: function(component, index) { 3499 if (component && component.props && component.props.key != null) { 3500 // Explicit key 3501 return '{' + component.props.key + '}'; 3502 } 3503 // Implicit key determined by the index in the set 3504 return '[' + index + ']'; 3505 }, 3506 3507 /** 3508 * @internal 3509 */ 3510 LifeCycle: ComponentLifeCycle, 3511 3512 /** 3513 * Injected module that provides ability to mutate individual properties. 3514 * Injected into the base class because many different subclasses need access 3515 * to this. 3516 * 3517 * @internal 3518 */ 3519 DOMIDOperations: ReactComponentEnvironment.DOMIDOperations, 3520 3521 /** 3522 * Optionally injectable environment dependent cleanup hook. (server vs. 3523 * browser etc). Example: A browser system caches DOM nodes based on component 3524 * ID and must remove that cache entry when this instance is unmounted. 3525 * 3526 * @private 3527 */ 3528 unmountIDFromEnvironment: ReactComponentEnvironment.unmountIDFromEnvironment, 3529 3530 /** 3531 * The "image" of a component tree, is the platform specific (typically 3532 * serialized) data that represents a tree of lower level UI building blocks. 3533 * On the web, this "image" is HTML markup which describes a construction of 3534 * low level `div` and `span` nodes. Other platforms may have different 3535 * encoding of this "image". This must be injected. 3536 * 3537 * @private 3538 */ 3539 mountImageIntoNode: ReactComponentEnvironment.mountImageIntoNode, 3540 3541 /** 3542 * React references `ReactReconcileTransaction` using this property in order 3543 * to allow dependency injection. 3544 * 3545 * @internal 3546 */ 3547 ReactReconcileTransaction: 3548 ReactComponentEnvironment.ReactReconcileTransaction, 3549 3550 /** 3551 * Base functionality for every ReactComponent constructor. Mixed into the 3552 * `ReactComponent` prototype, but exposed statically for easy access. 3553 * 3554 * @lends {ReactComponent.prototype} 3555 */ 3556 Mixin: merge(ReactComponentEnvironment.Mixin, { 3557 3558 /** 3559 * Checks whether or not this component is mounted. 3560 * 3561 * @return {boolean} True if mounted, false otherwise. 3562 * @final 3563 * @protected 3564 */ 3565 isMounted: function() { 3566 return this._lifeCycleState === ComponentLifeCycle.MOUNTED; 3567 }, 3568 3569 /** 3570 * Sets a subset of the props. 3571 * 3572 * @param {object} partialProps Subset of the next props. 3573 * @param {?function} callback Called after props are updated. 3574 * @final 3575 * @public 3576 */ 3577 setProps: function(partialProps, callback) { 3578 // Merge with `_pendingProps` if it exists, otherwise with existing props. 3579 this.replaceProps( 3580 merge(this._pendingProps || this.props, partialProps), 3581 callback 3582 ); 3583 }, 3584 3585 /** 3586 * Replaces all of the props. 3587 * 3588 * @param {object} props New props. 3589 * @param {?function} callback Called after props are updated. 3590 * @final 3591 * @public 3592 */ 3593 replaceProps: function(props, callback) { 3594 ("production" !== "development" ? invariant( 3595 !this.props.__owner__, 3596 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + 3597 'component with an owner. This is an anti-pattern since props will ' + 3598 'get reactively updated when rendered. Instead, change the owner\'s ' + 3599 '`render` method to pass the correct value as props to the component ' + 3600 'where it is created.' 3601 ) : invariant(!this.props.__owner__)); 3602 ("production" !== "development" ? invariant( 3603 this.isMounted(), 3604 'replaceProps(...): Can only update a mounted component.' 3605 ) : invariant(this.isMounted())); 3606 this._pendingProps = props; 3607 ReactUpdates.enqueueUpdate(this, callback); 3608 }, 3609 3610 /** 3611 * Base constructor for all React component. 3612 * 3613 * Subclasses that override this method should make sure to invoke 3614 * `ReactComponent.Mixin.construct.call(this, ...)`. 3615 * 3616 * @param {?object} initialProps 3617 * @param {*} children 3618 * @internal 3619 */ 3620 construct: function(initialProps, children) { 3621 this.props = initialProps || {}; 3622 // Record the component responsible for creating this component. 3623 this.props.__owner__ = ReactCurrentOwner.current; 3624 // All components start unmounted. 3625 this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; 3626 3627 this._pendingProps = null; 3628 this._pendingCallbacks = null; 3629 3630 // Children can be more than one argument 3631 var childrenLength = arguments.length - 1; 3632 if (childrenLength === 1) { 3633 if ("production" !== "development") { 3634 validateChildKeys(children); 3635 } 3636 this.props.children = children; 3637 } else if (childrenLength > 1) { 3638 var childArray = Array(childrenLength); 3639 for (var i = 0; i < childrenLength; i++) { 3640 if ("production" !== "development") { 3641 validateChildKeys(arguments[i + 1]); 3642 } 3643 childArray[i] = arguments[i + 1]; 3644 } 3645 this.props.children = childArray; 3646 } 3647 }, 3648 3649 /** 3650 * Initializes the component, renders markup, and registers event listeners. 3651 * 3652 * NOTE: This does not insert any nodes into the DOM. 3653 * 3654 * Subclasses that override this method should make sure to invoke 3655 * `ReactComponent.Mixin.mountComponent.call(this, ...)`. 3656 * 3657 * @param {string} rootID DOM ID of the root node. 3658 * @param {ReactReconcileTransaction} transaction 3659 * @param {number} mountDepth number of components in the owner hierarchy. 3660 * @return {?string} Rendered markup to be inserted into the DOM. 3661 * @internal 3662 */ 3663 mountComponent: function(rootID, transaction, mountDepth) { 3664 ("production" !== "development" ? invariant( 3665 !this.isMounted(), 3666 'mountComponent(%s, ...): Can only mount an unmounted component.', 3667 rootID 3668 ) : invariant(!this.isMounted())); 3669 var props = this.props; 3670 if (props.ref != null) { 3671 ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__); 3672 } 3673 this._rootNodeID = rootID; 3674 this._lifeCycleState = ComponentLifeCycle.MOUNTED; 3675 this._mountDepth = mountDepth; 3676 // Effectively: return ''; 3677 }, 3678 3679 /** 3680 * Releases any resources allocated by `mountComponent`. 3681 * 3682 * NOTE: This does not remove any nodes from the DOM. 3683 * 3684 * Subclasses that override this method should make sure to invoke 3685 * `ReactComponent.Mixin.unmountComponent.call(this)`. 3686 * 3687 * @internal 3688 */ 3689 unmountComponent: function() { 3690 ("production" !== "development" ? invariant( 3691 this.isMounted(), 3692 'unmountComponent(): Can only unmount a mounted component.' 3693 ) : invariant(this.isMounted())); 3694 var props = this.props; 3695 if (props.ref != null) { 3696 ReactOwner.removeComponentAsRefFrom(this, props.ref, props.__owner__); 3697 } 3698 ReactComponent.unmountIDFromEnvironment(this._rootNodeID); 3699 this._rootNodeID = null; 3700 this._lifeCycleState = ComponentLifeCycle.UNMOUNTED; 3701 }, 3702 3703 /** 3704 * Given a new instance of this component, updates the rendered DOM nodes 3705 * as if that instance was rendered instead. 3706 * 3707 * Subclasses that override this method should make sure to invoke 3708 * `ReactComponent.Mixin.receiveComponent.call(this, ...)`. 3709 * 3710 * @param {object} nextComponent Next set of properties. 3711 * @param {ReactReconcileTransaction} transaction 3712 * @internal 3713 */ 3714 receiveComponent: function(nextComponent, transaction) { 3715 ("production" !== "development" ? invariant( 3716 this.isMounted(), 3717 'receiveComponent(...): Can only update a mounted component.' 3718 ) : invariant(this.isMounted())); 3719 this._pendingProps = nextComponent.props; 3720 this._performUpdateIfNecessary(transaction); 3721 }, 3722 3723 /** 3724 * Call `_performUpdateIfNecessary` within a new transaction. 3725 * 3726 * @param {ReactReconcileTransaction} transaction 3727 * @internal 3728 */ 3729 performUpdateIfNecessary: function() { 3730 var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); 3731 transaction.perform(this._performUpdateIfNecessary, this, transaction); 3732 ReactComponent.ReactReconcileTransaction.release(transaction); 3733 }, 3734 3735 /** 3736 * If `_pendingProps` is set, update the component. 3737 * 3738 * @param {ReactReconcileTransaction} transaction 3739 * @internal 3740 */ 3741 _performUpdateIfNecessary: function(transaction) { 3742 if (this._pendingProps == null) { 3743 return; 3744 } 3745 var prevProps = this.props; 3746 this.props = this._pendingProps; 3747 this._pendingProps = null; 3748 this.updateComponent(transaction, prevProps); 3749 }, 3750 3751 /** 3752 * Updates the component's currently mounted representation. 3753 * 3754 * @param {ReactReconcileTransaction} transaction 3755 * @param {object} prevProps 3756 * @internal 3757 */ 3758 updateComponent: function(transaction, prevProps) { 3759 var props = this.props; 3760 // If either the owner or a `ref` has changed, make sure the newest owner 3761 // has stored a reference to `this`, and the previous owner (if different) 3762 // has forgotten the reference to `this`. 3763 if (props.__owner__ !== prevProps.__owner__ || 3764 props.ref !== prevProps.ref) { 3765 if (prevProps.ref != null) { 3766 ReactOwner.removeComponentAsRefFrom( 3767 this, prevProps.ref, prevProps.__owner__ 3768 ); 3769 } 3770 // Correct, even if the owner is the same, and only the ref has changed. 3771 if (props.ref != null) { 3772 ReactOwner.addComponentAsRefTo(this, props.ref, props.__owner__); 3773 } 3774 } 3775 }, 3776 3777 /** 3778 * Mounts this component and inserts it into the DOM. 3779 * 3780 * @param {string} rootID DOM ID of the root node. 3781 * @param {DOMElement} container DOM element to mount into. 3782 * @param {boolean} shouldReuseMarkup If true, do not insert markup 3783 * @final 3784 * @internal 3785 * @see {ReactMount.renderComponent} 3786 */ 3787 mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) { 3788 var transaction = ReactComponent.ReactReconcileTransaction.getPooled(); 3789 transaction.perform( 3790 this._mountComponentIntoNode, 3791 this, 3792 rootID, 3793 container, 3794 transaction, 3795 shouldReuseMarkup 3796 ); 3797 ReactComponent.ReactReconcileTransaction.release(transaction); 3798 }, 3799 3800 /** 3801 * @param {string} rootID DOM ID of the root node. 3802 * @param {DOMElement} container DOM element to mount into. 3803 * @param {ReactReconcileTransaction} transaction 3804 * @param {boolean} shouldReuseMarkup If true, do not insert markup 3805 * @final 3806 * @private 3807 */ 3808 _mountComponentIntoNode: function( 3809 rootID, 3810 container, 3811 transaction, 3812 shouldReuseMarkup) { 3813 var markup = this.mountComponent(rootID, transaction, 0); 3814 ReactComponent.mountImageIntoNode(markup, container, shouldReuseMarkup); 3815 }, 3816 3817 /** 3818 * Checks if this component is owned by the supplied `owner` component. 3819 * 3820 * @param {ReactComponent} owner Component to check. 3821 * @return {boolean} True if `owners` owns this component. 3822 * @final 3823 * @internal 3824 */ 3825 isOwnedBy: function(owner) { 3826 return this.props.__owner__ === owner; 3827 }, 3828 3829 /** 3830 * Gets another component, that shares the same owner as this one, by ref. 3831 * 3832 * @param {string} ref of a sibling Component. 3833 * @return {?ReactComponent} the actual sibling Component. 3834 * @final 3835 * @internal 3836 */ 3837 getSiblingByRef: function(ref) { 3838 var owner = this.props.__owner__; 3839 if (!owner || !owner.refs) { 3840 return null; 3841 } 3842 return owner.refs[ref]; 3843 } 3844 }) 3845 }; 3846 3847 module.exports = ReactComponent; 3848 3849 },{"./ReactComponentEnvironment":27,"./ReactCurrentOwner":29,"./ReactOwner":54,"./ReactUpdates":61,"./invariant":98,"./keyMirror":104,"./merge":107}],26:[function(require,module,exports){ 3850 /** 3851 * Copyright 2013 Facebook, Inc. 3852 * 3853 * Licensed under the Apache License, Version 2.0 (the "License"); 3854 * you may not use this file except in compliance with the License. 3855 * You may obtain a copy of the License at 3856 * 3857 * http://www.apache.org/licenses/LICENSE-2.0 3858 * 3859 * Unless required by applicable law or agreed to in writing, software 3860 * distributed under the License is distributed on an "AS IS" BASIS, 3861 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3862 * See the License for the specific language governing permissions and 3863 * limitations under the License. 3864 * 3865 * @providesModule ReactComponentBrowserEnvironment 3866 */ 3867 3868 /*jslint evil: true */ 3869 3870 "use strict"; 3871 3872 var ReactDOMIDOperations = require("./ReactDOMIDOperations"); 3873 var ReactMarkupChecksum = require("./ReactMarkupChecksum"); 3874 var ReactMount = require("./ReactMount"); 3875 var ReactReconcileTransaction = require("./ReactReconcileTransaction"); 3876 3877 var getReactRootElementInContainer = require("./getReactRootElementInContainer"); 3878 var invariant = require("./invariant"); 3879 var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup"); 3880 3881 3882 var ELEMENT_NODE_TYPE = 1; 3883 var DOC_NODE_TYPE = 9; 3884 3885 3886 /** 3887 * Abstracts away all functionality of `ReactComponent` requires knowledge of 3888 * the browser context. 3889 */ 3890 var ReactComponentBrowserEnvironment = { 3891 /** 3892 * Mixed into every component instance. 3893 */ 3894 Mixin: { 3895 /** 3896 * Returns the DOM node rendered by this component. 3897 * 3898 * @return {DOMElement} The root node of this component. 3899 * @final 3900 * @protected 3901 */ 3902 getDOMNode: function() { 3903 ("production" !== "development" ? invariant( 3904 this.isMounted(), 3905 'getDOMNode(): A component must be mounted to have a DOM node.' 3906 ) : invariant(this.isMounted())); 3907 return ReactMount.getNode(this._rootNodeID); 3908 } 3909 }, 3910 3911 ReactReconcileTransaction: ReactReconcileTransaction, 3912 3913 DOMIDOperations: ReactDOMIDOperations, 3914 3915 /** 3916 * If a particular environment requires that some resources be cleaned up, 3917 * specify this in the injected Mixin. In the DOM, we would likely want to 3918 * purge any cached node ID lookups. 3919 * 3920 * @private 3921 */ 3922 unmountIDFromEnvironment: function(rootNodeID) { 3923 ReactMount.purgeID(rootNodeID); 3924 }, 3925 3926 /** 3927 * @param {string} markup Markup string to place into the DOM Element. 3928 * @param {DOMElement} container DOM Element to insert markup into. 3929 * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the 3930 * container if possible. 3931 */ 3932 mountImageIntoNode: function(markup, container, shouldReuseMarkup) { 3933 ("production" !== "development" ? invariant( 3934 container && ( 3935 container.nodeType === ELEMENT_NODE_TYPE || 3936 container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender 3937 ), 3938 'mountComponentIntoNode(...): Target container is not valid.' 3939 ) : invariant(container && ( 3940 container.nodeType === ELEMENT_NODE_TYPE || 3941 container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender 3942 ))); 3943 if (shouldReuseMarkup) { 3944 if (ReactMarkupChecksum.canReuseMarkup( 3945 markup, 3946 getReactRootElementInContainer(container))) { 3947 return; 3948 } else { 3949 if ("production" !== "development") { 3950 console.warn( 3951 'React attempted to use reuse markup in a container but the ' + 3952 'checksum was invalid. This generally means that you are using ' + 3953 'server rendering and the markup generated on the server was ' + 3954 'not what the client was expecting. React injected new markup ' + 3955 'to compensate which works but you have lost many of the ' + 3956 'benefits of server rendering. Instead, figure out why the ' + 3957 'markup being generated is different on the client or server.' 3958 ); 3959 } 3960 } 3961 } 3962 3963 // You can't naively set the innerHTML of the entire document. You need 3964 // to mutate documentElement which requires doing some crazy tricks. See 3965 // mutateHTMLNodeWithMarkup() 3966 if (container.nodeType === DOC_NODE_TYPE) { 3967 mutateHTMLNodeWithMarkup(container.documentElement, markup); 3968 return; 3969 } 3970 3971 // Asynchronously inject markup by ensuring that the container is not in 3972 // the document when settings its `innerHTML`. 3973 var parent = container.parentNode; 3974 if (parent) { 3975 var next = container.nextSibling; 3976 parent.removeChild(container); 3977 container.innerHTML = markup; 3978 if (next) { 3979 parent.insertBefore(container, next); 3980 } else { 3981 parent.appendChild(container); 3982 } 3983 } else { 3984 container.innerHTML = markup; 3985 } 3986 } 3987 }; 3988 3989 module.exports = ReactComponentBrowserEnvironment; 3990 3991 },{"./ReactDOMIDOperations":34,"./ReactMarkupChecksum":49,"./ReactMount":50,"./ReactReconcileTransaction":58,"./getReactRootElementInContainer":94,"./invariant":98,"./mutateHTMLNodeWithMarkup":111}],27:[function(require,module,exports){ 3992 /** 3993 * Copyright 2013 Facebook, Inc. 3994 * 3995 * Licensed under the Apache License, Version 2.0 (the "License"); 3996 * you may not use this file except in compliance with the License. 3997 * You may obtain a copy of the License at 3998 * 3999 * http://www.apache.org/licenses/LICENSE-2.0 4000 * 4001 * Unless required by applicable law or agreed to in writing, software 4002 * distributed under the License is distributed on an "AS IS" BASIS, 4003 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4004 * See the License for the specific language governing permissions and 4005 * limitations under the License. 4006 * 4007 * @providesModule ReactComponentEnvironment 4008 */ 4009 4010 var ReactComponentBrowserEnvironment = 4011 require("./ReactComponentBrowserEnvironment"); 4012 4013 var ReactComponentEnvironment = ReactComponentBrowserEnvironment; 4014 4015 module.exports = ReactComponentEnvironment; 4016 4017 },{"./ReactComponentBrowserEnvironment":26}],28:[function(require,module,exports){ 4018 /** 4019 * Copyright 2013 Facebook, Inc. 4020 * 4021 * Licensed under the Apache License, Version 2.0 (the "License"); 4022 * you may not use this file except in compliance with the License. 4023 * You may obtain a copy of the License at 4024 * 4025 * http://www.apache.org/licenses/LICENSE-2.0 4026 * 4027 * Unless required by applicable law or agreed to in writing, software 4028 * distributed under the License is distributed on an "AS IS" BASIS, 4029 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4030 * See the License for the specific language governing permissions and 4031 * limitations under the License. 4032 * 4033 * @providesModule ReactCompositeComponent 4034 */ 4035 4036 "use strict"; 4037 4038 var ReactComponent = require("./ReactComponent"); 4039 var ReactCurrentOwner = require("./ReactCurrentOwner"); 4040 var ReactErrorUtils = require("./ReactErrorUtils"); 4041 var ReactOwner = require("./ReactOwner"); 4042 var ReactPerf = require("./ReactPerf"); 4043 var ReactPropTransferer = require("./ReactPropTransferer"); 4044 var ReactUpdates = require("./ReactUpdates"); 4045 4046 var invariant = require("./invariant"); 4047 var keyMirror = require("./keyMirror"); 4048 var merge = require("./merge"); 4049 var mixInto = require("./mixInto"); 4050 var objMap = require("./objMap"); 4051 4052 /** 4053 * Policies that describe methods in `ReactCompositeComponentInterface`. 4054 */ 4055 var SpecPolicy = keyMirror({ 4056 /** 4057 * These methods may be defined only once by the class specification or mixin. 4058 */ 4059 DEFINE_ONCE: null, 4060 /** 4061 * These methods may be defined by both the class specification and mixins. 4062 * Subsequent definitions will be chained. These methods must return void. 4063 */ 4064 DEFINE_MANY: null, 4065 /** 4066 * These methods are overriding the base ReactCompositeComponent class. 4067 */ 4068 OVERRIDE_BASE: null, 4069 /** 4070 * These methods are similar to DEFINE_MANY, except we assume they return 4071 * objects. We try to merge the keys of the return values of all the mixed in 4072 * functions. If there is a key conflict we throw. 4073 */ 4074 DEFINE_MANY_MERGED: null 4075 }); 4076 4077 /** 4078 * Composite components are higher-level components that compose other composite 4079 * or native components. 4080 * 4081 * To create a new type of `ReactCompositeComponent`, pass a specification of 4082 * your new class to `React.createClass`. The only requirement of your class 4083 * specification is that you implement a `render` method. 4084 * 4085 * var MyComponent = React.createClass({ 4086 * render: function() { 4087 * return <div>Hello World</div>; 4088 * } 4089 * }); 4090 * 4091 * The class specification supports a specific protocol of methods that have 4092 * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for 4093 * more the comprehensive protocol. Any other properties and methods in the 4094 * class specification will available on the prototype. 4095 * 4096 * @interface ReactCompositeComponentInterface 4097 * @internal 4098 */ 4099 var ReactCompositeComponentInterface = { 4100 4101 /** 4102 * An array of Mixin objects to include when defining your component. 4103 * 4104 * @type {array} 4105 * @optional 4106 */ 4107 mixins: SpecPolicy.DEFINE_MANY, 4108 4109 /** 4110 * Definition of prop types for this component. 4111 * 4112 * @type {object} 4113 * @optional 4114 */ 4115 propTypes: SpecPolicy.DEFINE_ONCE, 4116 4117 4118 4119 // ==== Definition methods ==== 4120 4121 /** 4122 * Invoked when the component is mounted. Values in the mapping will be set on 4123 * `this.props` if that prop is not specified (i.e. using an `in` check). 4124 * 4125 * This method is invoked before `getInitialState` and therefore cannot rely 4126 * on `this.state` or use `this.setState`. 4127 * 4128 * @return {object} 4129 * @optional 4130 */ 4131 getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED, 4132 4133 /** 4134 * Invoked once before the component is mounted. The return value will be used 4135 * as the initial value of `this.state`. 4136 * 4137 * getInitialState: function() { 4138 * return { 4139 * isOn: false, 4140 * fooBaz: new BazFoo() 4141 * } 4142 * } 4143 * 4144 * @return {object} 4145 * @optional 4146 */ 4147 getInitialState: SpecPolicy.DEFINE_MANY_MERGED, 4148 4149 /** 4150 * Uses props from `this.props` and state from `this.state` to render the 4151 * structure of the component. 4152 * 4153 * No guarantees are made about when or how often this method is invoked, so 4154 * it must not have side effects. 4155 * 4156 * render: function() { 4157 * var name = this.props.name; 4158 * return <div>Hello, {name}!</div>; 4159 * } 4160 * 4161 * @return {ReactComponent} 4162 * @nosideeffects 4163 * @required 4164 */ 4165 render: SpecPolicy.DEFINE_ONCE, 4166 4167 4168 4169 // ==== Delegate methods ==== 4170 4171 /** 4172 * Invoked when the component is initially created and about to be mounted. 4173 * This may have side effects, but any external subscriptions or data created 4174 * by this method must be cleaned up in `componentWillUnmount`. 4175 * 4176 * @optional 4177 */ 4178 componentWillMount: SpecPolicy.DEFINE_MANY, 4179 4180 /** 4181 * Invoked when the component has been mounted and has a DOM representation. 4182 * However, there is no guarantee that the DOM node is in the document. 4183 * 4184 * Use this as an opportunity to operate on the DOM when the component has 4185 * been mounted (initialized and rendered) for the first time. 4186 * 4187 * @param {DOMElement} rootNode DOM element representing the component. 4188 * @optional 4189 */ 4190 componentDidMount: SpecPolicy.DEFINE_MANY, 4191 4192 /** 4193 * Invoked before the component receives new props. 4194 * 4195 * Use this as an opportunity to react to a prop transition by updating the 4196 * state using `this.setState`. Current props are accessed via `this.props`. 4197 * 4198 * componentWillReceiveProps: function(nextProps) { 4199 * this.setState({ 4200 * likesIncreasing: nextProps.likeCount > this.props.likeCount 4201 * }); 4202 * } 4203 * 4204 * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop 4205 * transition may cause a state change, but the opposite is not true. If you 4206 * need it, you are probably looking for `componentWillUpdate`. 4207 * 4208 * @param {object} nextProps 4209 * @optional 4210 */ 4211 componentWillReceiveProps: SpecPolicy.DEFINE_MANY, 4212 4213 /** 4214 * Invoked while deciding if the component should be updated as a result of 4215 * receiving new props and state. 4216 * 4217 * Use this as an opportunity to `return false` when you're certain that the 4218 * transition to the new props and state will not require a component update. 4219 * 4220 * shouldComponentUpdate: function(nextProps, nextState) { 4221 * return !equal(nextProps, this.props) || !equal(nextState, this.state); 4222 * } 4223 * 4224 * @param {object} nextProps 4225 * @param {?object} nextState 4226 * @return {boolean} True if the component should update. 4227 * @optional 4228 */ 4229 shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, 4230 4231 /** 4232 * Invoked when the component is about to update due to a transition from 4233 * `this.props` and `this.state` to `nextProps` and `nextState`. 4234 * 4235 * Use this as an opportunity to perform preparation before an update occurs. 4236 * 4237 * NOTE: You **cannot** use `this.setState()` in this method. 4238 * 4239 * @param {object} nextProps 4240 * @param {?object} nextState 4241 * @param {ReactReconcileTransaction} transaction 4242 * @optional 4243 */ 4244 componentWillUpdate: SpecPolicy.DEFINE_MANY, 4245 4246 /** 4247 * Invoked when the component's DOM representation has been updated. 4248 * 4249 * Use this as an opportunity to operate on the DOM when the component has 4250 * been updated. 4251 * 4252 * @param {object} prevProps 4253 * @param {?object} prevState 4254 * @param {DOMElement} rootNode DOM element representing the component. 4255 * @optional 4256 */ 4257 componentDidUpdate: SpecPolicy.DEFINE_MANY, 4258 4259 /** 4260 * Invoked when the component is about to be removed from its parent and have 4261 * its DOM representation destroyed. 4262 * 4263 * Use this as an opportunity to deallocate any external resources. 4264 * 4265 * NOTE: There is no `componentDidUnmount` since your component will have been 4266 * destroyed by that point. 4267 * 4268 * @optional 4269 */ 4270 componentWillUnmount: SpecPolicy.DEFINE_MANY, 4271 4272 4273 4274 // ==== Advanced methods ==== 4275 4276 /** 4277 * Updates the component's currently mounted DOM representation. 4278 * 4279 * By default, this implements React's rendering and reconciliation algorithm. 4280 * Sophisticated clients may wish to override this. 4281 * 4282 * @param {ReactReconcileTransaction} transaction 4283 * @internal 4284 * @overridable 4285 */ 4286 updateComponent: SpecPolicy.OVERRIDE_BASE 4287 4288 }; 4289 4290 /** 4291 * Mapping from class specification keys to special processing functions. 4292 * 4293 * Although these are declared in the specification when defining classes 4294 * using `React.createClass`, they will not be on the component's prototype. 4295 */ 4296 var RESERVED_SPEC_KEYS = { 4297 displayName: function(Constructor, displayName) { 4298 Constructor.displayName = displayName; 4299 }, 4300 mixins: function(Constructor, mixins) { 4301 if (mixins) { 4302 for (var i = 0; i < mixins.length; i++) { 4303 mixSpecIntoComponent(Constructor, mixins[i]); 4304 } 4305 } 4306 }, 4307 propTypes: function(Constructor, propTypes) { 4308 Constructor.propTypes = propTypes; 4309 } 4310 }; 4311 4312 function validateMethodOverride(proto, name) { 4313 var specPolicy = ReactCompositeComponentInterface[name]; 4314 4315 // Disallow overriding of base class methods unless explicitly allowed. 4316 if (ReactCompositeComponentMixin.hasOwnProperty(name)) { 4317 ("production" !== "development" ? invariant( 4318 specPolicy === SpecPolicy.OVERRIDE_BASE, 4319 'ReactCompositeComponentInterface: You are attempting to override ' + 4320 '`%s` from your class specification. Ensure that your method names ' + 4321 'do not overlap with React methods.', 4322 name 4323 ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE)); 4324 } 4325 4326 // Disallow defining methods more than once unless explicitly allowed. 4327 if (proto.hasOwnProperty(name)) { 4328 ("production" !== "development" ? invariant( 4329 specPolicy === SpecPolicy.DEFINE_MANY || 4330 specPolicy === SpecPolicy.DEFINE_MANY_MERGED, 4331 'ReactCompositeComponentInterface: You are attempting to define ' + 4332 '`%s` on your component more than once. This conflict may be due ' + 4333 'to a mixin.', 4334 name 4335 ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY || 4336 specPolicy === SpecPolicy.DEFINE_MANY_MERGED)); 4337 } 4338 } 4339 4340 4341 function validateLifeCycleOnReplaceState(instance) { 4342 var compositeLifeCycleState = instance._compositeLifeCycleState; 4343 ("production" !== "development" ? invariant( 4344 instance.isMounted() || 4345 compositeLifeCycleState === CompositeLifeCycle.MOUNTING, 4346 'replaceState(...): Can only update a mounted or mounting component.' 4347 ) : invariant(instance.isMounted() || 4348 compositeLifeCycleState === CompositeLifeCycle.MOUNTING)); 4349 ("production" !== "development" ? invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE, 4350 'replaceState(...): Cannot update during an existing state transition ' + 4351 '(such as within `render`). This could potentially cause an infinite ' + 4352 'loop so it is forbidden.' 4353 ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE)); 4354 ("production" !== "development" ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, 4355 'replaceState(...): Cannot update while unmounting component. This ' + 4356 'usually means you called setState() on an unmounted component.' 4357 ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING)); 4358 } 4359 4360 /** 4361 * Custom version of `mixInto` which handles policy validation and reserved 4362 * specification keys when building `ReactCompositeComponent` classses. 4363 */ 4364 function mixSpecIntoComponent(Constructor, spec) { 4365 var proto = Constructor.prototype; 4366 for (var name in spec) { 4367 var property = spec[name]; 4368 if (!spec.hasOwnProperty(name) || !property) { 4369 continue; 4370 } 4371 validateMethodOverride(proto, name); 4372 4373 if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { 4374 RESERVED_SPEC_KEYS[name](Constructor, property); 4375 } else { 4376 // Setup methods on prototype: 4377 // The following member methods should not be automatically bound: 4378 // 1. Expected ReactCompositeComponent methods (in the "interface"). 4379 // 2. Overridden methods (that were mixed in). 4380 var isCompositeComponentMethod = name in ReactCompositeComponentInterface; 4381 var isInherited = name in proto; 4382 var markedDontBind = property.__reactDontBind; 4383 var isFunction = typeof property === 'function'; 4384 var shouldAutoBind = 4385 isFunction && 4386 !isCompositeComponentMethod && 4387 !isInherited && 4388 !markedDontBind; 4389 4390 if (shouldAutoBind) { 4391 if (!proto.__reactAutoBindMap) { 4392 proto.__reactAutoBindMap = {}; 4393 } 4394 proto.__reactAutoBindMap[name] = property; 4395 proto[name] = property; 4396 } else { 4397 if (isInherited) { 4398 // For methods which are defined more than once, call the existing 4399 // methods before calling the new property. 4400 if (ReactCompositeComponentInterface[name] === 4401 SpecPolicy.DEFINE_MANY_MERGED) { 4402 proto[name] = createMergedResultFunction(proto[name], property); 4403 } else { 4404 proto[name] = createChainedFunction(proto[name], property); 4405 } 4406 } else { 4407 proto[name] = property; 4408 } 4409 } 4410 } 4411 } 4412 } 4413 4414 /** 4415 * Merge two objects, but throw if both contain the same key. 4416 * 4417 * @param {object} one The first object, which is mutated. 4418 * @param {object} two The second object 4419 * @return {object} one after it has been mutated to contain everything in two. 4420 */ 4421 function mergeObjectsWithNoDuplicateKeys(one, two) { 4422 ("production" !== "development" ? invariant( 4423 one && two && typeof one === 'object' && typeof two === 'object', 4424 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects' 4425 ) : invariant(one && two && typeof one === 'object' && typeof two === 'object')); 4426 4427 objMap(two, function(value, key) { 4428 ("production" !== "development" ? invariant( 4429 one[key] === undefined, 4430 'mergeObjectsWithNoDuplicateKeys(): ' + 4431 'Tried to merge two objects with the same key: %s', 4432 key 4433 ) : invariant(one[key] === undefined)); 4434 one[key] = value; 4435 }); 4436 return one; 4437 } 4438 4439 /** 4440 * Creates a function that invokes two functions and merges their return values. 4441 * 4442 * @param {function} one Function to invoke first. 4443 * @param {function} two Function to invoke second. 4444 * @return {function} Function that invokes the two argument functions. 4445 * @private 4446 */ 4447 function createMergedResultFunction(one, two) { 4448 return function mergedResult() { 4449 return mergeObjectsWithNoDuplicateKeys( 4450 one.apply(this, arguments), 4451 two.apply(this, arguments) 4452 ); 4453 }; 4454 } 4455 4456 /** 4457 * Creates a function that invokes two functions and ignores their return vales. 4458 * 4459 * @param {function} one Function to invoke first. 4460 * @param {function} two Function to invoke second. 4461 * @return {function} Function that invokes the two argument functions. 4462 * @private 4463 */ 4464 function createChainedFunction(one, two) { 4465 return function chainedFunction() { 4466 one.apply(this, arguments); 4467 two.apply(this, arguments); 4468 }; 4469 } 4470 4471 /** 4472 * `ReactCompositeComponent` maintains an auxiliary life cycle state in 4473 * `this._compositeLifeCycleState` (which can be null). 4474 * 4475 * This is different from the life cycle state maintained by `ReactComponent` in 4476 * `this._lifeCycleState`. The following diagram shows how the states overlap in 4477 * time. There are times when the CompositeLifeCycle is null - at those times it 4478 * is only meaningful to look at ComponentLifeCycle alone. 4479 * 4480 * Top Row: ReactComponent.ComponentLifeCycle 4481 * Low Row: ReactComponent.CompositeLifeCycle 4482 * 4483 * +-------+------------------------------------------------------+--------+ 4484 * | UN | MOUNTED | UN | 4485 * |MOUNTED| | MOUNTED| 4486 * +-------+------------------------------------------------------+--------+ 4487 * | ^--------+ +------+ +------+ +------+ +--------^ | 4488 * | | | | | | | | | | | | 4489 * | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 | 4490 * | | | |PROPS | | PROPS| | STATE| |MOUNTING| | 4491 * | | | | | | | | | | | | 4492 * | | | | | | | | | | | | 4493 * | +--------+ +------+ +------+ +------+ +--------+ | 4494 * | | | | 4495 * +-------+------------------------------------------------------+--------+ 4496 */ 4497 var CompositeLifeCycle = keyMirror({ 4498 /** 4499 * Components in the process of being mounted respond to state changes 4500 * differently. 4501 */ 4502 MOUNTING: null, 4503 /** 4504 * Components in the process of being unmounted are guarded against state 4505 * changes. 4506 */ 4507 UNMOUNTING: null, 4508 /** 4509 * Components that are mounted and receiving new props respond to state 4510 * changes differently. 4511 */ 4512 RECEIVING_PROPS: null, 4513 /** 4514 * Components that are mounted and receiving new state are guarded against 4515 * additional state changes. 4516 */ 4517 RECEIVING_STATE: null 4518 }); 4519 4520 /** 4521 * @lends {ReactCompositeComponent.prototype} 4522 */ 4523 var ReactCompositeComponentMixin = { 4524 4525 /** 4526 * Base constructor for all composite component. 4527 * 4528 * @param {?object} initialProps 4529 * @param {*} children 4530 * @final 4531 * @internal 4532 */ 4533 construct: function(initialProps, children) { 4534 // Children can be either an array or more than one argument 4535 ReactComponent.Mixin.construct.apply(this, arguments); 4536 this.state = null; 4537 this._pendingState = null; 4538 this._compositeLifeCycleState = null; 4539 }, 4540 4541 /** 4542 * Checks whether or not this composite component is mounted. 4543 * @return {boolean} True if mounted, false otherwise. 4544 * @protected 4545 * @final 4546 */ 4547 isMounted: function() { 4548 return ReactComponent.Mixin.isMounted.call(this) && 4549 this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING; 4550 }, 4551 4552 /** 4553 * Initializes the component, renders markup, and registers event listeners. 4554 * 4555 * @param {string} rootID DOM ID of the root node. 4556 * @param {ReactReconcileTransaction} transaction 4557 * @param {number} mountDepth number of components in the owner hierarchy 4558 * @return {?string} Rendered markup to be inserted into the DOM. 4559 * @final 4560 * @internal 4561 */ 4562 mountComponent: ReactPerf.measure( 4563 'ReactCompositeComponent', 4564 'mountComponent', 4565 function(rootID, transaction, mountDepth) { 4566 ReactComponent.Mixin.mountComponent.call( 4567 this, 4568 rootID, 4569 transaction, 4570 mountDepth 4571 ); 4572 this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING; 4573 4574 this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null; 4575 this._processProps(this.props); 4576 4577 if (this.__reactAutoBindMap) { 4578 this._bindAutoBindMethods(); 4579 } 4580 4581 this.state = this.getInitialState ? this.getInitialState() : null; 4582 this._pendingState = null; 4583 this._pendingForceUpdate = false; 4584 4585 if (this.componentWillMount) { 4586 this.componentWillMount(); 4587 // When mounting, calls to `setState` by `componentWillMount` will set 4588 // `this._pendingState` without triggering a re-render. 4589 if (this._pendingState) { 4590 this.state = this._pendingState; 4591 this._pendingState = null; 4592 } 4593 } 4594 4595 this._renderedComponent = this._renderValidatedComponent(); 4596 4597 // Done with mounting, `setState` will now trigger UI changes. 4598 this._compositeLifeCycleState = null; 4599 var markup = this._renderedComponent.mountComponent( 4600 rootID, 4601 transaction, 4602 mountDepth + 1 4603 ); 4604 if (this.componentDidMount) { 4605 transaction.getReactMountReady().enqueue(this, this.componentDidMount); 4606 } 4607 return markup; 4608 } 4609 ), 4610 4611 /** 4612 * Releases any resources allocated by `mountComponent`. 4613 * 4614 * @final 4615 * @internal 4616 */ 4617 unmountComponent: function() { 4618 this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING; 4619 if (this.componentWillUnmount) { 4620 this.componentWillUnmount(); 4621 } 4622 this._compositeLifeCycleState = null; 4623 4624 this._defaultProps = null; 4625 4626 ReactComponent.Mixin.unmountComponent.call(this); 4627 this._renderedComponent.unmountComponent(); 4628 this._renderedComponent = null; 4629 4630 if (this.refs) { 4631 this.refs = null; 4632 } 4633 4634 // Some existing components rely on this.props even after they've been 4635 // destroyed (in event handlers). 4636 // TODO: this.props = null; 4637 // TODO: this.state = null; 4638 }, 4639 4640 /** 4641 * Sets a subset of the state. Always use this or `replaceState` to mutate 4642 * state. You should treat `this.state` as immutable. 4643 * 4644 * There is no guarantee that `this.state` will be immediately updated, so 4645 * accessing `this.state` after calling this method may return the old value. 4646 * 4647 * There is no guarantee that calls to `setState` will run synchronously, 4648 * as they may eventually be batched together. You can provide an optional 4649 * callback that will be executed when the call to setState is actually 4650 * completed. 4651 * 4652 * @param {object} partialState Next partial state to be merged with state. 4653 * @param {?function} callback Called after state is updated. 4654 * @final 4655 * @protected 4656 */ 4657 setState: function(partialState, callback) { 4658 // Merge with `_pendingState` if it exists, otherwise with existing state. 4659 this.replaceState( 4660 merge(this._pendingState || this.state, partialState), 4661 callback 4662 ); 4663 }, 4664 4665 /** 4666 * Replaces all of the state. Always use this or `setState` to mutate state. 4667 * You should treat `this.state` as immutable. 4668 * 4669 * There is no guarantee that `this.state` will be immediately updated, so 4670 * accessing `this.state` after calling this method may return the old value. 4671 * 4672 * @param {object} completeState Next state. 4673 * @param {?function} callback Called after state is updated. 4674 * @final 4675 * @protected 4676 */ 4677 replaceState: function(completeState, callback) { 4678 validateLifeCycleOnReplaceState(this); 4679 this._pendingState = completeState; 4680 ReactUpdates.enqueueUpdate(this, callback); 4681 }, 4682 4683 /** 4684 * Processes props by setting default values for unspecified props and 4685 * asserting that the props are valid. 4686 * 4687 * @param {object} props 4688 * @private 4689 */ 4690 _processProps: function(props) { 4691 var propName; 4692 var defaultProps = this._defaultProps; 4693 for (propName in defaultProps) { 4694 if (!(propName in props)) { 4695 props[propName] = defaultProps[propName]; 4696 } 4697 } 4698 var propTypes = this.constructor.propTypes; 4699 if (propTypes) { 4700 var componentName = this.constructor.displayName; 4701 for (propName in propTypes) { 4702 var checkProp = propTypes[propName]; 4703 if (checkProp) { 4704 checkProp(props, propName, componentName); 4705 } 4706 } 4707 } 4708 }, 4709 4710 performUpdateIfNecessary: function() { 4711 var compositeLifeCycleState = this._compositeLifeCycleState; 4712 // Do not trigger a state transition if we are in the middle of mounting or 4713 // receiving props because both of those will already be doing this. 4714 if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING || 4715 compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) { 4716 return; 4717 } 4718 ReactComponent.Mixin.performUpdateIfNecessary.call(this); 4719 }, 4720 4721 /** 4722 * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is 4723 * set, update the component. 4724 * 4725 * @param {ReactReconcileTransaction} transaction 4726 * @internal 4727 */ 4728 _performUpdateIfNecessary: function(transaction) { 4729 if (this._pendingProps == null && 4730 this._pendingState == null && 4731 !this._pendingForceUpdate) { 4732 return; 4733 } 4734 4735 var nextProps = this.props; 4736 if (this._pendingProps != null) { 4737 nextProps = this._pendingProps; 4738 this._processProps(nextProps); 4739 this._pendingProps = null; 4740 4741 this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS; 4742 if (this.componentWillReceiveProps) { 4743 this.componentWillReceiveProps(nextProps, transaction); 4744 } 4745 } 4746 4747 this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE; 4748 4749 var nextState = this._pendingState || this.state; 4750 this._pendingState = null; 4751 4752 if (this._pendingForceUpdate || 4753 !this.shouldComponentUpdate || 4754 this.shouldComponentUpdate(nextProps, nextState)) { 4755 this._pendingForceUpdate = false; 4756 // Will set `this.props` and `this.state`. 4757 this._performComponentUpdate(nextProps, nextState, transaction); 4758 } else { 4759 // If it's determined that a component should not update, we still want 4760 // to set props and state. 4761 this.props = nextProps; 4762 this.state = nextState; 4763 } 4764 4765 this._compositeLifeCycleState = null; 4766 }, 4767 4768 /** 4769 * Merges new props and state, notifies delegate methods of update and 4770 * performs update. 4771 * 4772 * @param {object} nextProps Next object to set as properties. 4773 * @param {?object} nextState Next object to set as state. 4774 * @param {ReactReconcileTransaction} transaction 4775 * @private 4776 */ 4777 _performComponentUpdate: function(nextProps, nextState, transaction) { 4778 var prevProps = this.props; 4779 var prevState = this.state; 4780 4781 if (this.componentWillUpdate) { 4782 this.componentWillUpdate(nextProps, nextState, transaction); 4783 } 4784 4785 this.props = nextProps; 4786 this.state = nextState; 4787 4788 this.updateComponent(transaction, prevProps, prevState); 4789 4790 if (this.componentDidUpdate) { 4791 transaction.getReactMountReady().enqueue( 4792 this, 4793 this.componentDidUpdate.bind(this, prevProps, prevState) 4794 ); 4795 } 4796 }, 4797 4798 /** 4799 * Updates the component's currently mounted DOM representation. 4800 * 4801 * By default, this implements React's rendering and reconciliation algorithm. 4802 * Sophisticated clients may wish to override this. 4803 * 4804 * @param {ReactReconcileTransaction} transaction 4805 * @param {object} prevProps 4806 * @param {?object} prevState 4807 * @internal 4808 * @overridable 4809 */ 4810 updateComponent: ReactPerf.measure( 4811 'ReactCompositeComponent', 4812 'updateComponent', 4813 function(transaction, prevProps, prevState) { 4814 ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); 4815 var currentComponent = this._renderedComponent; 4816 var nextComponent = this._renderValidatedComponent(); 4817 if (currentComponent.constructor === nextComponent.constructor) { 4818 currentComponent.receiveComponent(nextComponent, transaction); 4819 } else { 4820 // These two IDs are actually the same! But nothing should rely on that. 4821 var thisID = this._rootNodeID; 4822 var currentComponentID = currentComponent._rootNodeID; 4823 currentComponent.unmountComponent(); 4824 this._renderedComponent = nextComponent; 4825 var nextMarkup = nextComponent.mountComponent( 4826 thisID, 4827 transaction, 4828 this._mountDepth + 1 4829 ); 4830 ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( 4831 currentComponentID, 4832 nextMarkup 4833 ); 4834 } 4835 } 4836 ), 4837 4838 /** 4839 * Forces an update. This should only be invoked when it is known with 4840 * certainty that we are **not** in a DOM transaction. 4841 * 4842 * You may want to call this when you know that some deeper aspect of the 4843 * component's state has changed but `setState` was not called. 4844 * 4845 * This will not invoke `shouldUpdateComponent`, but it will invoke 4846 * `componentWillUpdate` and `componentDidUpdate`. 4847 * 4848 * @param {?function} callback Called after update is complete. 4849 * @final 4850 * @protected 4851 */ 4852 forceUpdate: function(callback) { 4853 var compositeLifeCycleState = this._compositeLifeCycleState; 4854 ("production" !== "development" ? invariant( 4855 this.isMounted() || 4856 compositeLifeCycleState === CompositeLifeCycle.MOUNTING, 4857 'forceUpdate(...): Can only force an update on mounted or mounting ' + 4858 'components.' 4859 ) : invariant(this.isMounted() || 4860 compositeLifeCycleState === CompositeLifeCycle.MOUNTING)); 4861 ("production" !== "development" ? invariant( 4862 compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && 4863 compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, 4864 'forceUpdate(...): Cannot force an update while unmounting component ' + 4865 'or during an existing state transition (such as within `render`).' 4866 ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && 4867 compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING)); 4868 this._pendingForceUpdate = true; 4869 ReactUpdates.enqueueUpdate(this, callback); 4870 }, 4871 4872 /** 4873 * @private 4874 */ 4875 _renderValidatedComponent: function() { 4876 var renderedComponent; 4877 ReactCurrentOwner.current = this; 4878 try { 4879 renderedComponent = this.render(); 4880 } catch (error) { 4881 // IE8 requires `catch` in order to use `finally`. 4882 throw error; 4883 } finally { 4884 ReactCurrentOwner.current = null; 4885 } 4886 ("production" !== "development" ? invariant( 4887 ReactComponent.isValidComponent(renderedComponent), 4888 '%s.render(): A valid ReactComponent must be returned. You may have ' + 4889 'returned null, undefined, an array, or some other invalid object.', 4890 this.constructor.displayName || 'ReactCompositeComponent' 4891 ) : invariant(ReactComponent.isValidComponent(renderedComponent))); 4892 return renderedComponent; 4893 }, 4894 4895 /** 4896 * @private 4897 */ 4898 _bindAutoBindMethods: function() { 4899 for (var autoBindKey in this.__reactAutoBindMap) { 4900 if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { 4901 continue; 4902 } 4903 var method = this.__reactAutoBindMap[autoBindKey]; 4904 this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard( 4905 method, 4906 this.constructor.displayName + '.' + autoBindKey 4907 )); 4908 } 4909 }, 4910 4911 /** 4912 * Binds a method to the component. 4913 * 4914 * @param {function} method Method to be bound. 4915 * @private 4916 */ 4917 _bindAutoBindMethod: function(method) { 4918 var component = this; 4919 var boundMethod = function() { 4920 return method.apply(component, arguments); 4921 }; 4922 if ("production" !== "development") { 4923 boundMethod.__reactBoundContext = component; 4924 boundMethod.__reactBoundMethod = method; 4925 boundMethod.__reactBoundArguments = null; 4926 var componentName = component.constructor.displayName; 4927 var _bind = boundMethod.bind; 4928 boundMethod.bind = function(newThis) { 4929 // User is trying to bind() an autobound method; we effectively will 4930 // ignore the value of "this" that the user is trying to use, so 4931 // let's warn. 4932 if (newThis !== component && newThis !== null) { 4933 console.warn( 4934 'bind(): React component methods may only be bound to the ' + 4935 'component instance. See ' + componentName 4936 ); 4937 } else if (arguments.length === 1) { 4938 console.warn( 4939 'bind(): You are binding a component method to the component. ' + 4940 'React does this for you automatically in a high-performance ' + 4941 'way, so you can safely remove this call. See ' + componentName 4942 ); 4943 return boundMethod; 4944 } 4945 var reboundMethod = _bind.apply(boundMethod, arguments); 4946 reboundMethod.__reactBoundContext = component; 4947 reboundMethod.__reactBoundMethod = method; 4948 reboundMethod.__reactBoundArguments = 4949 Array.prototype.slice.call(arguments, 1); 4950 return reboundMethod; 4951 }; 4952 } 4953 return boundMethod; 4954 } 4955 }; 4956 4957 var ReactCompositeComponentBase = function() {}; 4958 mixInto(ReactCompositeComponentBase, ReactComponent.Mixin); 4959 mixInto(ReactCompositeComponentBase, ReactOwner.Mixin); 4960 mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin); 4961 mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin); 4962 4963 /** 4964 * Module for creating composite components. 4965 * 4966 * @class ReactCompositeComponent 4967 * @extends ReactComponent 4968 * @extends ReactOwner 4969 * @extends ReactPropTransferer 4970 */ 4971 var ReactCompositeComponent = { 4972 4973 LifeCycle: CompositeLifeCycle, 4974 4975 Base: ReactCompositeComponentBase, 4976 4977 /** 4978 * Creates a composite component class given a class specification. 4979 * 4980 * @param {object} spec Class specification (which must define `render`). 4981 * @return {function} Component constructor function. 4982 * @public 4983 */ 4984 createClass: function(spec) { 4985 var Constructor = function() {}; 4986 Constructor.prototype = new ReactCompositeComponentBase(); 4987 Constructor.prototype.constructor = Constructor; 4988 mixSpecIntoComponent(Constructor, spec); 4989 4990 ("production" !== "development" ? invariant( 4991 Constructor.prototype.render, 4992 'createClass(...): Class specification must implement a `render` method.' 4993 ) : invariant(Constructor.prototype.render)); 4994 4995 if ("production" !== "development") { 4996 if (Constructor.prototype.componentShouldUpdate) { 4997 console.warn( 4998 (spec.displayName || 'A component') + ' has a method called ' + 4999 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 5000 'The name is phrased as a question because the function is ' + 5001 'expected to return a value.' 5002 ); 5003 } 5004 } 5005 5006 // Reduce time spent doing lookups by setting these on the prototype. 5007 for (var methodName in ReactCompositeComponentInterface) { 5008 if (!Constructor.prototype[methodName]) { 5009 Constructor.prototype[methodName] = null; 5010 } 5011 } 5012 5013 var ConvenienceConstructor = function(props, children) { 5014 var instance = new Constructor(); 5015 instance.construct.apply(instance, arguments); 5016 return instance; 5017 }; 5018 ConvenienceConstructor.componentConstructor = Constructor; 5019 ConvenienceConstructor.originalSpec = spec; 5020 return ConvenienceConstructor; 5021 }, 5022 5023 /** 5024 * Checks if a value is a valid component constructor. 5025 * 5026 * @param {*} 5027 * @return {boolean} 5028 * @public 5029 */ 5030 isValidClass: function(componentClass) { 5031 return componentClass instanceof Function && 5032 'componentConstructor' in componentClass && 5033 componentClass.componentConstructor instanceof Function; 5034 } 5035 }; 5036 5037 module.exports = ReactCompositeComponent; 5038 5039 },{"./ReactComponent":25,"./ReactCurrentOwner":29,"./ReactErrorUtils":43,"./ReactOwner":54,"./ReactPerf":55,"./ReactPropTransferer":56,"./ReactUpdates":61,"./invariant":98,"./keyMirror":104,"./merge":107,"./mixInto":110,"./objMap":112}],29:[function(require,module,exports){ 5040 /** 5041 * Copyright 2013 Facebook, Inc. 5042 * 5043 * Licensed under the Apache License, Version 2.0 (the "License"); 5044 * you may not use this file except in compliance with the License. 5045 * You may obtain a copy of the License at 5046 * 5047 * http://www.apache.org/licenses/LICENSE-2.0 5048 * 5049 * Unless required by applicable law or agreed to in writing, software 5050 * distributed under the License is distributed on an "AS IS" BASIS, 5051 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5052 * See the License for the specific language governing permissions and 5053 * limitations under the License. 5054 * 5055 * @providesModule ReactCurrentOwner 5056 */ 5057 5058 "use strict"; 5059 5060 /** 5061 * Keeps track of the current owner. 5062 * 5063 * The current owner is the component who should own any components that are 5064 * currently being constructed. 5065 * 5066 * The depth indicate how many composite components are above this render level. 5067 */ 5068 var ReactCurrentOwner = { 5069 5070 /** 5071 * @internal 5072 * @type {ReactComponent} 5073 */ 5074 current: null 5075 5076 }; 5077 5078 module.exports = ReactCurrentOwner; 5079 5080 },{}],30:[function(require,module,exports){ 5081 /** 5082 * Copyright 2013 Facebook, Inc. 5083 * 5084 * Licensed under the Apache License, Version 2.0 (the "License"); 5085 * you may not use this file except in compliance with the License. 5086 * You may obtain a copy of the License at 5087 * 5088 * http://www.apache.org/licenses/LICENSE-2.0 5089 * 5090 * Unless required by applicable law or agreed to in writing, software 5091 * distributed under the License is distributed on an "AS IS" BASIS, 5092 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5093 * See the License for the specific language governing permissions and 5094 * limitations under the License. 5095 * 5096 * @providesModule ReactDOM 5097 * @typechecks static-only 5098 */ 5099 5100 "use strict"; 5101 5102 var ReactDOMComponent = require("./ReactDOMComponent"); 5103 5104 var mergeInto = require("./mergeInto"); 5105 var objMapKeyVal = require("./objMapKeyVal"); 5106 5107 /** 5108 * Creates a new React class that is idempotent and capable of containing other 5109 * React components. It accepts event listeners and DOM properties that are 5110 * valid according to `DOMProperty`. 5111 * 5112 * - Event listeners: `onClick`, `onMouseDown`, etc. 5113 * - DOM properties: `className`, `name`, `title`, etc. 5114 * 5115 * The `style` property functions differently from the DOM API. It accepts an 5116 * object mapping of style properties to values. 5117 * 5118 * @param {string} tag Tag name (e.g. `div`). 5119 * @param {boolean} omitClose True if the close tag should be omitted. 5120 * @private 5121 */ 5122 function createDOMComponentClass(tag, omitClose) { 5123 var Constructor = function() {}; 5124 Constructor.prototype = new ReactDOMComponent(tag, omitClose); 5125 Constructor.prototype.constructor = Constructor; 5126 Constructor.displayName = tag; 5127 5128 var ConvenienceConstructor = function(props, children) { 5129 var instance = new Constructor(); 5130 instance.construct.apply(instance, arguments); 5131 return instance; 5132 }; 5133 ConvenienceConstructor.componentConstructor = Constructor; 5134 return ConvenienceConstructor; 5135 } 5136 5137 /** 5138 * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes. 5139 * This is also accessible via `React.DOM`. 5140 * 5141 * @public 5142 */ 5143 var ReactDOM = objMapKeyVal({ 5144 a: false, 5145 abbr: false, 5146 address: false, 5147 area: false, 5148 article: false, 5149 aside: false, 5150 audio: false, 5151 b: false, 5152 base: false, 5153 bdi: false, 5154 bdo: false, 5155 big: false, 5156 blockquote: false, 5157 body: false, 5158 br: true, 5159 button: false, 5160 canvas: false, 5161 caption: false, 5162 cite: false, 5163 code: false, 5164 col: true, 5165 colgroup: false, 5166 data: false, 5167 datalist: false, 5168 dd: false, 5169 del: false, 5170 details: false, 5171 dfn: false, 5172 div: false, 5173 dl: false, 5174 dt: false, 5175 em: false, 5176 embed: true, 5177 fieldset: false, 5178 figcaption: false, 5179 figure: false, 5180 footer: false, 5181 form: false, // NOTE: Injected, see `ReactDOMForm`. 5182 h1: false, 5183 h2: false, 5184 h3: false, 5185 h4: false, 5186 h5: false, 5187 h6: false, 5188 head: false, 5189 header: false, 5190 hr: true, 5191 html: false, 5192 i: false, 5193 iframe: false, 5194 img: true, 5195 input: true, 5196 ins: false, 5197 kbd: false, 5198 keygen: true, 5199 label: false, 5200 legend: false, 5201 li: false, 5202 link: false, 5203 main: false, 5204 map: false, 5205 mark: false, 5206 menu: false, 5207 menuitem: false, // NOTE: Close tag should be omitted, but causes problems. 5208 meta: true, 5209 meter: false, 5210 nav: false, 5211 noscript: false, 5212 object: false, 5213 ol: false, 5214 optgroup: false, 5215 option: false, 5216 output: false, 5217 p: false, 5218 param: true, 5219 pre: false, 5220 progress: false, 5221 q: false, 5222 rp: false, 5223 rt: false, 5224 ruby: false, 5225 s: false, 5226 samp: false, 5227 script: false, 5228 section: false, 5229 select: false, 5230 small: false, 5231 source: false, 5232 span: false, 5233 strong: false, 5234 style: false, 5235 sub: false, 5236 summary: false, 5237 sup: false, 5238 table: false, 5239 tbody: false, 5240 td: false, 5241 textarea: false, // NOTE: Injected, see `ReactDOMTextarea`. 5242 tfoot: false, 5243 th: false, 5244 thead: false, 5245 time: false, 5246 title: false, 5247 tr: false, 5248 track: true, 5249 u: false, 5250 ul: false, 5251 'var': false, 5252 video: false, 5253 wbr: false, 5254 5255 // SVG 5256 circle: false, 5257 g: false, 5258 line: false, 5259 path: false, 5260 polyline: false, 5261 rect: false, 5262 svg: false, 5263 text: false 5264 }, createDOMComponentClass); 5265 5266 var injection = { 5267 injectComponentClasses: function(componentClasses) { 5268 mergeInto(ReactDOM, componentClasses); 5269 } 5270 }; 5271 5272 ReactDOM.injection = injection; 5273 5274 module.exports = ReactDOM; 5275 5276 },{"./ReactDOMComponent":32,"./mergeInto":109,"./objMapKeyVal":113}],31:[function(require,module,exports){ 5277 /** 5278 * Copyright 2013 Facebook, Inc. 5279 * 5280 * Licensed under the Apache License, Version 2.0 (the "License"); 5281 * you may not use this file except in compliance with the License. 5282 * You may obtain a copy of the License at 5283 * 5284 * http://www.apache.org/licenses/LICENSE-2.0 5285 * 5286 * Unless required by applicable law or agreed to in writing, software 5287 * distributed under the License is distributed on an "AS IS" BASIS, 5288 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5289 * See the License for the specific language governing permissions and 5290 * limitations under the License. 5291 * 5292 * @providesModule ReactDOMButton 5293 */ 5294 5295 "use strict"; 5296 5297 var ReactCompositeComponent = require("./ReactCompositeComponent"); 5298 var ReactDOM = require("./ReactDOM"); 5299 5300 var keyMirror = require("./keyMirror"); 5301 5302 // Store a reference to the <button> `ReactDOMComponent`. 5303 var button = ReactDOM.button; 5304 5305 var mouseListenerNames = keyMirror({ 5306 onClick: true, 5307 onDoubleClick: true, 5308 onMouseDown: true, 5309 onMouseMove: true, 5310 onMouseUp: true, 5311 onClickCapture: true, 5312 onDoubleClickCapture: true, 5313 onMouseDownCapture: true, 5314 onMouseMoveCapture: true, 5315 onMouseUpCapture: true 5316 }); 5317 5318 /** 5319 * Implements a <button> native component that does not receive mouse events 5320 * when `disabled` is set. 5321 */ 5322 var ReactDOMButton = ReactCompositeComponent.createClass({ 5323 5324 render: function() { 5325 var props = {}; 5326 5327 // Copy the props; except the mouse listeners if we're disabled 5328 for (var key in this.props) { 5329 if (this.props.hasOwnProperty(key) && 5330 (!this.props.disabled || !mouseListenerNames[key])) { 5331 props[key] = this.props[key]; 5332 } 5333 } 5334 5335 return button(props, this.props.children); 5336 } 5337 5338 }); 5339 5340 module.exports = ReactDOMButton; 5341 5342 },{"./ReactCompositeComponent":28,"./ReactDOM":30,"./keyMirror":104}],32:[function(require,module,exports){ 5343 /** 5344 * Copyright 2013 Facebook, Inc. 5345 * 5346 * Licensed under the Apache License, Version 2.0 (the "License"); 5347 * you may not use this file except in compliance with the License. 5348 * You may obtain a copy of the License at 5349 * 5350 * http://www.apache.org/licenses/LICENSE-2.0 5351 * 5352 * Unless required by applicable law or agreed to in writing, software 5353 * distributed under the License is distributed on an "AS IS" BASIS, 5354 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5355 * See the License for the specific language governing permissions and 5356 * limitations under the License. 5357 * 5358 * @providesModule ReactDOMComponent 5359 * @typechecks static-only 5360 */ 5361 5362 "use strict"; 5363 5364 var CSSPropertyOperations = require("./CSSPropertyOperations"); 5365 var DOMProperty = require("./DOMProperty"); 5366 var DOMPropertyOperations = require("./DOMPropertyOperations"); 5367 var ReactComponent = require("./ReactComponent"); 5368 var ReactEventEmitter = require("./ReactEventEmitter"); 5369 var ReactMultiChild = require("./ReactMultiChild"); 5370 var ReactMount = require("./ReactMount"); 5371 var ReactPerf = require("./ReactPerf"); 5372 5373 var escapeTextForBrowser = require("./escapeTextForBrowser"); 5374 var invariant = require("./invariant"); 5375 var keyOf = require("./keyOf"); 5376 var merge = require("./merge"); 5377 var mixInto = require("./mixInto"); 5378 5379 var putListener = ReactEventEmitter.putListener; 5380 var deleteListener = ReactEventEmitter.deleteListener; 5381 var registrationNames = ReactEventEmitter.registrationNames; 5382 5383 // For quickly matching children type, to test if can be treated as content. 5384 var CONTENT_TYPES = {'string': true, 'number': true}; 5385 5386 var STYLE = keyOf({style: null}); 5387 5388 /** 5389 * @param {?object} props 5390 */ 5391 function assertValidProps(props) { 5392 if (!props) { 5393 return; 5394 } 5395 // Note the use of `==` which checks for null or undefined. 5396 ("production" !== "development" ? invariant( 5397 props.children == null || props.dangerouslySetInnerHTML == null, 5398 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.' 5399 ) : invariant(props.children == null || props.dangerouslySetInnerHTML == null)); 5400 ("production" !== "development" ? invariant( 5401 props.style == null || typeof props.style === 'object', 5402 'The `style` prop expects a mapping from style properties to values, ' + 5403 'not a string.' 5404 ) : invariant(props.style == null || typeof props.style === 'object')); 5405 } 5406 5407 /** 5408 * @constructor ReactDOMComponent 5409 * @extends ReactComponent 5410 * @extends ReactMultiChild 5411 */ 5412 function ReactDOMComponent(tag, omitClose) { 5413 this._tagOpen = '<' + tag; 5414 this._tagClose = omitClose ? '' : '</' + tag + '>'; 5415 this.tagName = tag.toUpperCase(); 5416 } 5417 5418 ReactDOMComponent.Mixin = { 5419 5420 /** 5421 * Generates root tag markup then recurses. This method has side effects and 5422 * is not idempotent. 5423 * 5424 * @internal 5425 * @param {string} rootID The root DOM ID for this node. 5426 * @param {ReactReconcileTransaction} transaction 5427 * @param {number} mountDepth number of components in the owner hierarchy 5428 * @return {string} The computed markup. 5429 */ 5430 mountComponent: ReactPerf.measure( 5431 'ReactDOMComponent', 5432 'mountComponent', 5433 function(rootID, transaction, mountDepth) { 5434 ReactComponent.Mixin.mountComponent.call( 5435 this, 5436 rootID, 5437 transaction, 5438 mountDepth 5439 ); 5440 assertValidProps(this.props); 5441 return ( 5442 this._createOpenTagMarkup() + 5443 this._createContentMarkup(transaction) + 5444 this._tagClose 5445 ); 5446 } 5447 ), 5448 5449 /** 5450 * Creates markup for the open tag and all attributes. 5451 * 5452 * This method has side effects because events get registered. 5453 * 5454 * Iterating over object properties is faster than iterating over arrays. 5455 * @see http://jsperf.com/obj-vs-arr-iteration 5456 * 5457 * @private 5458 * @return {string} Markup of opening tag. 5459 */ 5460 _createOpenTagMarkup: function() { 5461 var props = this.props; 5462 var ret = this._tagOpen; 5463 5464 for (var propKey in props) { 5465 if (!props.hasOwnProperty(propKey)) { 5466 continue; 5467 } 5468 var propValue = props[propKey]; 5469 if (propValue == null) { 5470 continue; 5471 } 5472 if (registrationNames[propKey]) { 5473 putListener(this._rootNodeID, propKey, propValue); 5474 } else { 5475 if (propKey === STYLE) { 5476 if (propValue) { 5477 propValue = props.style = merge(props.style); 5478 } 5479 propValue = CSSPropertyOperations.createMarkupForStyles(propValue); 5480 } 5481 var markup = 5482 DOMPropertyOperations.createMarkupForProperty(propKey, propValue); 5483 if (markup) { 5484 ret += ' ' + markup; 5485 } 5486 } 5487 } 5488 5489 var escapedID = escapeTextForBrowser(this._rootNodeID); 5490 return ret + ' ' + ReactMount.ATTR_NAME + '="' + escapedID + '">'; 5491 }, 5492 5493 /** 5494 * Creates markup for the content between the tags. 5495 * 5496 * @private 5497 * @param {ReactReconcileTransaction} transaction 5498 * @return {string} Content markup. 5499 */ 5500 _createContentMarkup: function(transaction) { 5501 // Intentional use of != to avoid catching zero/false. 5502 var innerHTML = this.props.dangerouslySetInnerHTML; 5503 if (innerHTML != null) { 5504 if (innerHTML.__html != null) { 5505 return innerHTML.__html; 5506 } 5507 } else { 5508 var contentToUse = 5509 CONTENT_TYPES[typeof this.props.children] ? this.props.children : null; 5510 var childrenToUse = contentToUse != null ? null : this.props.children; 5511 if (contentToUse != null) { 5512 return escapeTextForBrowser(contentToUse); 5513 } else if (childrenToUse != null) { 5514 var mountImages = this.mountChildren( 5515 childrenToUse, 5516 transaction 5517 ); 5518 return mountImages.join(''); 5519 } 5520 } 5521 return ''; 5522 }, 5523 5524 receiveComponent: function(nextComponent, transaction) { 5525 assertValidProps(nextComponent.props); 5526 ReactComponent.Mixin.receiveComponent.call( 5527 this, 5528 nextComponent, 5529 transaction 5530 ); 5531 }, 5532 5533 /** 5534 * Updates a native DOM component after it has already been allocated and 5535 * attached to the DOM. Reconciles the root DOM node, then recurses. 5536 * 5537 * @param {ReactReconcileTransaction} transaction 5538 * @param {object} prevProps 5539 * @internal 5540 * @overridable 5541 */ 5542 updateComponent: ReactPerf.measure( 5543 'ReactDOMComponent', 5544 'updateComponent', 5545 function(transaction, prevProps) { 5546 ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps); 5547 this._updateDOMProperties(prevProps); 5548 this._updateDOMChildren(prevProps, transaction); 5549 } 5550 ), 5551 5552 /** 5553 * Reconciles the properties by detecting differences in property values and 5554 * updating the DOM as necessary. This function is probably the single most 5555 * critical path for performance optimization. 5556 * 5557 * TODO: Benchmark whether checking for changed values in memory actually 5558 * improves performance (especially statically positioned elements). 5559 * TODO: Benchmark the effects of putting this at the top since 99% of props 5560 * do not change for a given reconciliation. 5561 * TODO: Benchmark areas that can be improved with caching. 5562 * 5563 * @private 5564 * @param {object} lastProps 5565 */ 5566 _updateDOMProperties: function(lastProps) { 5567 var nextProps = this.props; 5568 var propKey; 5569 var styleName; 5570 var styleUpdates; 5571 for (propKey in lastProps) { 5572 if (nextProps.hasOwnProperty(propKey) || 5573 !lastProps.hasOwnProperty(propKey)) { 5574 continue; 5575 } 5576 if (propKey === STYLE) { 5577 var lastStyle = lastProps[propKey]; 5578 for (styleName in lastStyle) { 5579 if (lastStyle.hasOwnProperty(styleName)) { 5580 styleUpdates = styleUpdates || {}; 5581 styleUpdates[styleName] = ''; 5582 } 5583 } 5584 } else if (registrationNames[propKey]) { 5585 deleteListener(this._rootNodeID, propKey); 5586 } else if ( 5587 DOMProperty.isStandardName[propKey] || 5588 DOMProperty.isCustomAttribute(propKey)) { 5589 ReactComponent.DOMIDOperations.deletePropertyByID( 5590 this._rootNodeID, 5591 propKey 5592 ); 5593 } 5594 } 5595 for (propKey in nextProps) { 5596 var nextProp = nextProps[propKey]; 5597 var lastProp = lastProps[propKey]; 5598 if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) { 5599 continue; 5600 } 5601 if (propKey === STYLE) { 5602 if (nextProp) { 5603 nextProp = nextProps.style = merge(nextProp); 5604 } 5605 if (lastProp) { 5606 // Unset styles on `lastProp` but not on `nextProp`. 5607 for (styleName in lastProp) { 5608 if (lastProp.hasOwnProperty(styleName) && 5609 !nextProp.hasOwnProperty(styleName)) { 5610 styleUpdates = styleUpdates || {}; 5611 styleUpdates[styleName] = ''; 5612 } 5613 } 5614 // Update styles that changed since `lastProp`. 5615 for (styleName in nextProp) { 5616 if (nextProp.hasOwnProperty(styleName) && 5617 lastProp[styleName] !== nextProp[styleName]) { 5618 styleUpdates = styleUpdates || {}; 5619 styleUpdates[styleName] = nextProp[styleName]; 5620 } 5621 } 5622 } else { 5623 // Relies on `updateStylesByID` not mutating `styleUpdates`. 5624 styleUpdates = nextProp; 5625 } 5626 } else if (registrationNames[propKey]) { 5627 putListener(this._rootNodeID, propKey, nextProp); 5628 } else if ( 5629 DOMProperty.isStandardName[propKey] || 5630 DOMProperty.isCustomAttribute(propKey)) { 5631 ReactComponent.DOMIDOperations.updatePropertyByID( 5632 this._rootNodeID, 5633 propKey, 5634 nextProp 5635 ); 5636 } 5637 } 5638 if (styleUpdates) { 5639 ReactComponent.DOMIDOperations.updateStylesByID( 5640 this._rootNodeID, 5641 styleUpdates 5642 ); 5643 } 5644 }, 5645 5646 /** 5647 * Reconciles the children with the various properties that affect the 5648 * children content. 5649 * 5650 * @param {object} lastProps 5651 * @param {ReactReconcileTransaction} transaction 5652 */ 5653 _updateDOMChildren: function(lastProps, transaction) { 5654 var nextProps = this.props; 5655 5656 var lastContent = 5657 CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null; 5658 var nextContent = 5659 CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null; 5660 5661 var lastHtml = 5662 lastProps.dangerouslySetInnerHTML && 5663 lastProps.dangerouslySetInnerHTML.__html; 5664 var nextHtml = 5665 nextProps.dangerouslySetInnerHTML && 5666 nextProps.dangerouslySetInnerHTML.__html; 5667 5668 // Note the use of `!=` which checks for null or undefined. 5669 var lastChildren = lastContent != null ? null : lastProps.children; 5670 var nextChildren = nextContent != null ? null : nextProps.children; 5671 5672 // If we're switching from children to content/html or vice versa, remove 5673 // the old content 5674 var lastHasContentOrHtml = lastContent != null || lastHtml != null; 5675 var nextHasContentOrHtml = nextContent != null || nextHtml != null; 5676 if (lastChildren != null && nextChildren == null) { 5677 this.updateChildren(null, transaction); 5678 } else if (lastHasContentOrHtml && !nextHasContentOrHtml) { 5679 this.updateTextContent(''); 5680 } 5681 5682 if (nextContent != null) { 5683 if (lastContent !== nextContent) { 5684 this.updateTextContent('' + nextContent); 5685 } 5686 } else if (nextHtml != null) { 5687 if (lastHtml !== nextHtml) { 5688 ReactComponent.DOMIDOperations.updateInnerHTMLByID( 5689 this._rootNodeID, 5690 nextHtml 5691 ); 5692 } 5693 } else if (nextChildren != null) { 5694 this.updateChildren(nextChildren, transaction); 5695 } 5696 }, 5697 5698 /** 5699 * Destroys all event registrations for this instance. Does not remove from 5700 * the DOM. That must be done by the parent. 5701 * 5702 * @internal 5703 */ 5704 unmountComponent: function() { 5705 ReactEventEmitter.deleteAllListeners(this._rootNodeID); 5706 ReactComponent.Mixin.unmountComponent.call(this); 5707 this.unmountChildren(); 5708 } 5709 5710 }; 5711 5712 mixInto(ReactDOMComponent, ReactComponent.Mixin); 5713 mixInto(ReactDOMComponent, ReactDOMComponent.Mixin); 5714 mixInto(ReactDOMComponent, ReactMultiChild.Mixin); 5715 5716 module.exports = ReactDOMComponent; 5717 5718 },{"./CSSPropertyOperations":3,"./DOMProperty":8,"./DOMPropertyOperations":9,"./ReactComponent":25,"./ReactEventEmitter":44,"./ReactMount":50,"./ReactMultiChild":52,"./ReactPerf":55,"./escapeTextForBrowser":84,"./invariant":98,"./keyOf":105,"./merge":107,"./mixInto":110}],33:[function(require,module,exports){ 5719 /** 5720 * Copyright 2013 Facebook, Inc. 5721 * 5722 * Licensed under the Apache License, Version 2.0 (the "License"); 5723 * you may not use this file except in compliance with the License. 5724 * You may obtain a copy of the License at 5725 * 5726 * http://www.apache.org/licenses/LICENSE-2.0 5727 * 5728 * Unless required by applicable law or agreed to in writing, software 5729 * distributed under the License is distributed on an "AS IS" BASIS, 5730 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5731 * See the License for the specific language governing permissions and 5732 * limitations under the License. 5733 * 5734 * @providesModule ReactDOMForm 5735 */ 5736 5737 "use strict"; 5738 5739 var ReactCompositeComponent = require("./ReactCompositeComponent"); 5740 var ReactDOM = require("./ReactDOM"); 5741 var ReactEventEmitter = require("./ReactEventEmitter"); 5742 var EventConstants = require("./EventConstants"); 5743 5744 // Store a reference to the <form> `ReactDOMComponent`. 5745 var form = ReactDOM.form; 5746 5747 /** 5748 * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need 5749 * to capture it on the <form> element itself. There are lots of hacks we could 5750 * do to accomplish this, but the most reliable is to make <form> a 5751 * composite component and use `componentDidMount` to attach the event handlers. 5752 */ 5753 var ReactDOMForm = ReactCompositeComponent.createClass({ 5754 render: function() { 5755 // TODO: Instead of using `ReactDOM` directly, we should use JSX. However, 5756 // `jshint` fails to parse JSX so in order for linting to work in the open 5757 // source repo, we need to just use `ReactDOM.form`. 5758 return this.transferPropsTo(form(null, this.props.children)); 5759 }, 5760 5761 componentDidMount: function(node) { 5762 ReactEventEmitter.trapBubbledEvent( 5763 EventConstants.topLevelTypes.topSubmit, 5764 'submit', 5765 node 5766 ); 5767 } 5768 }); 5769 5770 module.exports = ReactDOMForm; 5771 5772 },{"./EventConstants":14,"./ReactCompositeComponent":28,"./ReactDOM":30,"./ReactEventEmitter":44}],34:[function(require,module,exports){ 5773 /** 5774 * Copyright 2013 Facebook, Inc. 5775 * 5776 * Licensed under the Apache License, Version 2.0 (the "License"); 5777 * you may not use this file except in compliance with the License. 5778 * You may obtain a copy of the License at 5779 * 5780 * http://www.apache.org/licenses/LICENSE-2.0 5781 * 5782 * Unless required by applicable law or agreed to in writing, software 5783 * distributed under the License is distributed on an "AS IS" BASIS, 5784 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5785 * See the License for the specific language governing permissions and 5786 * limitations under the License. 5787 * 5788 * @providesModule ReactDOMIDOperations 5789 * @typechecks static-only 5790 */ 5791 5792 /*jslint evil: true */ 5793 5794 "use strict"; 5795 5796 var CSSPropertyOperations = require("./CSSPropertyOperations"); 5797 var DOMChildrenOperations = require("./DOMChildrenOperations"); 5798 var DOMPropertyOperations = require("./DOMPropertyOperations"); 5799 var ReactMount = require("./ReactMount"); 5800 5801 var getTextContentAccessor = require("./getTextContentAccessor"); 5802 var invariant = require("./invariant"); 5803 5804 /** 5805 * Errors for properties that should not be updated with `updatePropertyById()`. 5806 * 5807 * @type {object} 5808 * @private 5809 */ 5810 var INVALID_PROPERTY_ERRORS = { 5811 dangerouslySetInnerHTML: 5812 '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', 5813 style: '`style` must be set using `updateStylesByID()`.' 5814 }; 5815 5816 /** 5817 * The DOM property to use when setting text content. 5818 * 5819 * @type {string} 5820 * @private 5821 */ 5822 var textContentAccessor = getTextContentAccessor() || 'NA'; 5823 5824 var LEADING_SPACE = /^ /; 5825 5826 /** 5827 * Operations used to process updates to DOM nodes. This is made injectable via 5828 * `ReactComponent.DOMIDOperations`. 5829 */ 5830 var ReactDOMIDOperations = { 5831 5832 /** 5833 * Updates a DOM node with new property values. This should only be used to 5834 * update DOM properties in `DOMProperty`. 5835 * 5836 * @param {string} id ID of the node to update. 5837 * @param {string} name A valid property name, see `DOMProperty`. 5838 * @param {*} value New value of the property. 5839 * @internal 5840 */ 5841 updatePropertyByID: function(id, name, value) { 5842 var node = ReactMount.getNode(id); 5843 ("production" !== "development" ? invariant( 5844 !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 5845 'updatePropertyByID(...): %s', 5846 INVALID_PROPERTY_ERRORS[name] 5847 ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); 5848 5849 // If we're updating to null or undefined, we should remove the property 5850 // from the DOM node instead of inadvertantly setting to a string. This 5851 // brings us in line with the same behavior we have on initial render. 5852 if (value != null) { 5853 DOMPropertyOperations.setValueForProperty(node, name, value); 5854 } else { 5855 DOMPropertyOperations.deleteValueForProperty(node, name); 5856 } 5857 }, 5858 5859 /** 5860 * Updates a DOM node to remove a property. This should only be used to remove 5861 * DOM properties in `DOMProperty`. 5862 * 5863 * @param {string} id ID of the node to update. 5864 * @param {string} name A property name to remove, see `DOMProperty`. 5865 * @internal 5866 */ 5867 deletePropertyByID: function(id, name, value) { 5868 var node = ReactMount.getNode(id); 5869 ("production" !== "development" ? invariant( 5870 !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 5871 'updatePropertyByID(...): %s', 5872 INVALID_PROPERTY_ERRORS[name] 5873 ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); 5874 DOMPropertyOperations.deleteValueForProperty(node, name, value); 5875 }, 5876 5877 /** 5878 * Updates a DOM node with new style values. If a value is specified as '', 5879 * the corresponding style property will be unset. 5880 * 5881 * @param {string} id ID of the node to update. 5882 * @param {object} styles Mapping from styles to values. 5883 * @internal 5884 */ 5885 updateStylesByID: function(id, styles) { 5886 var node = ReactMount.getNode(id); 5887 CSSPropertyOperations.setValueForStyles(node, styles); 5888 }, 5889 5890 /** 5891 * Updates a DOM node's innerHTML. 5892 * 5893 * @param {string} id ID of the node to update. 5894 * @param {string} html An HTML string. 5895 * @internal 5896 */ 5897 updateInnerHTMLByID: function(id, html) { 5898 var node = ReactMount.getNode(id); 5899 // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces. 5900 // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html 5901 node.innerHTML = html.replace(LEADING_SPACE, ' '); 5902 }, 5903 5904 /** 5905 * Updates a DOM node's text content set by `props.content`. 5906 * 5907 * @param {string} id ID of the node to update. 5908 * @param {string} content Text content. 5909 * @internal 5910 */ 5911 updateTextContentByID: function(id, content) { 5912 var node = ReactMount.getNode(id); 5913 node[textContentAccessor] = content; 5914 }, 5915 5916 /** 5917 * Replaces a DOM node that exists in the document with markup. 5918 * 5919 * @param {string} id ID of child to be replaced. 5920 * @param {string} markup Dangerous markup to inject in place of child. 5921 * @internal 5922 * @see {Danger.dangerouslyReplaceNodeWithMarkup} 5923 */ 5924 dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { 5925 var node = ReactMount.getNode(id); 5926 DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); 5927 }, 5928 5929 /** 5930 * Updates a component's children by processing a series of updates. 5931 * 5932 * @param {array<object>} updates List of update configurations. 5933 * @param {array<string>} markup List of markup strings. 5934 * @internal 5935 */ 5936 dangerouslyProcessChildrenUpdates: function(updates, markup) { 5937 for (var i = 0; i < updates.length; i++) { 5938 updates[i].parentNode = ReactMount.getNode(updates[i].parentID); 5939 } 5940 DOMChildrenOperations.processUpdates(updates, markup); 5941 } 5942 5943 }; 5944 5945 module.exports = ReactDOMIDOperations; 5946 5947 },{"./CSSPropertyOperations":3,"./DOMChildrenOperations":7,"./DOMPropertyOperations":9,"./ReactMount":50,"./getTextContentAccessor":95,"./invariant":98}],35:[function(require,module,exports){ 5948 /** 5949 * Copyright 2013 Facebook, Inc. 5950 * 5951 * Licensed under the Apache License, Version 2.0 (the "License"); 5952 * you may not use this file except in compliance with the License. 5953 * You may obtain a copy of the License at 5954 * 5955 * http://www.apache.org/licenses/LICENSE-2.0 5956 * 5957 * Unless required by applicable law or agreed to in writing, software 5958 * distributed under the License is distributed on an "AS IS" BASIS, 5959 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5960 * See the License for the specific language governing permissions and 5961 * limitations under the License. 5962 * 5963 * @providesModule ReactDOMInput 5964 */ 5965 5966 "use strict"; 5967 5968 var DOMPropertyOperations = require("./DOMPropertyOperations"); 5969 var LinkedValueMixin = require("./LinkedValueMixin"); 5970 var ReactCompositeComponent = require("./ReactCompositeComponent"); 5971 var ReactDOM = require("./ReactDOM"); 5972 var ReactMount = require("./ReactMount"); 5973 5974 var invariant = require("./invariant"); 5975 var merge = require("./merge"); 5976 5977 // Store a reference to the <input> `ReactDOMComponent`. 5978 var input = ReactDOM.input; 5979 5980 var instancesByReactID = {}; 5981 5982 /** 5983 * Implements an <input> native component that allows setting these optional 5984 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. 5985 * 5986 * If `checked` or `value` are not supplied (or null/undefined), user actions 5987 * that affect the checked state or value will trigger updates to the element. 5988 * 5989 * If they are supplied (and not null/undefined), the rendered element will not 5990 * trigger updates to the element. Instead, the props must change in order for 5991 * the rendered element to be updated. 5992 * 5993 * The rendered element will be initialized as unchecked (or `defaultChecked`) 5994 * with an empty value (or `defaultValue`). 5995 * 5996 * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html 5997 */ 5998 var ReactDOMInput = ReactCompositeComponent.createClass({ 5999 mixins: [LinkedValueMixin], 6000 6001 getInitialState: function() { 6002 var defaultValue = this.props.defaultValue; 6003 return { 6004 checked: this.props.defaultChecked || false, 6005 value: defaultValue != null ? defaultValue : null 6006 }; 6007 }, 6008 6009 shouldComponentUpdate: function() { 6010 // Defer any updates to this component during the `onChange` handler. 6011 return !this._isChanging; 6012 }, 6013 6014 render: function() { 6015 // Clone `this.props` so we don't mutate the input. 6016 var props = merge(this.props); 6017 6018 props.defaultChecked = null; 6019 props.defaultValue = null; 6020 props.checked = 6021 this.props.checked != null ? this.props.checked : this.state.checked; 6022 6023 var value = this.getValue(); 6024 props.value = value != null ? value : this.state.value; 6025 6026 props.onChange = this._handleChange; 6027 6028 return input(props, this.props.children); 6029 }, 6030 6031 componentDidMount: function(rootNode) { 6032 var id = ReactMount.getID(rootNode); 6033 instancesByReactID[id] = this; 6034 }, 6035 6036 componentWillUnmount: function() { 6037 var rootNode = this.getDOMNode(); 6038 var id = ReactMount.getID(rootNode); 6039 delete instancesByReactID[id]; 6040 }, 6041 6042 componentDidUpdate: function(prevProps, prevState, rootNode) { 6043 if (this.props.checked != null) { 6044 DOMPropertyOperations.setValueForProperty( 6045 rootNode, 6046 'checked', 6047 this.props.checked || false 6048 ); 6049 } 6050 6051 var value = this.getValue(); 6052 if (value != null) { 6053 // Cast `value` to a string to ensure the value is set correctly. While 6054 // browsers typically do this as necessary, jsdom doesn't. 6055 DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value); 6056 } 6057 }, 6058 6059 _handleChange: function(event) { 6060 var returnValue; 6061 var onChange = this.getOnChange(); 6062 if (onChange) { 6063 this._isChanging = true; 6064 returnValue = onChange(event); 6065 this._isChanging = false; 6066 } 6067 this.setState({ 6068 checked: event.target.checked, 6069 value: event.target.value 6070 }); 6071 6072 var name = this.props.name; 6073 if (this.props.type === 'radio' && name != null) { 6074 var rootNode = this.getDOMNode(); 6075 // If `rootNode.form` was non-null, then we could try `form.elements`, 6076 // but that sometimes behaves strangely in IE8. We could also try using 6077 // `form.getElementsByName`, but that will only return direct children 6078 // and won't include inputs that use the HTML5 `form=` attribute. Since 6079 // the input might not even be in a form, let's just use the global 6080 // `getElementsByName` to ensure we don't miss anything. 6081 var group = document.getElementsByName(name); 6082 for (var i = 0, groupLen = group.length; i < groupLen; i++) { 6083 var otherNode = group[i]; 6084 if (otherNode === rootNode || 6085 otherNode.nodeName !== 'INPUT' || otherNode.type !== 'radio' || 6086 otherNode.form !== rootNode.form) { 6087 continue; 6088 } 6089 var otherID = ReactMount.getID(otherNode); 6090 ("production" !== "development" ? invariant( 6091 otherID, 6092 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 6093 'same `name` is not supported.' 6094 ) : invariant(otherID)); 6095 var otherInstance = instancesByReactID[otherID]; 6096 ("production" !== "development" ? invariant( 6097 otherInstance, 6098 'ReactDOMInput: Unknown radio button ID %s.', 6099 otherID 6100 ) : invariant(otherInstance)); 6101 // In some cases, this will actually change the `checked` state value. 6102 // In other cases, there's no change but this forces a reconcile upon 6103 // which componentDidUpdate will reset the DOM property to whatever it 6104 // should be. 6105 otherInstance.setState({ 6106 checked: false 6107 }); 6108 } 6109 } 6110 6111 return returnValue; 6112 } 6113 6114 }); 6115 6116 module.exports = ReactDOMInput; 6117 6118 },{"./DOMPropertyOperations":9,"./LinkedValueMixin":21,"./ReactCompositeComponent":28,"./ReactDOM":30,"./ReactMount":50,"./invariant":98,"./merge":107}],36:[function(require,module,exports){ 6119 /** 6120 * Copyright 2013 Facebook, Inc. 6121 * 6122 * Licensed under the Apache License, Version 2.0 (the "License"); 6123 * you may not use this file except in compliance with the License. 6124 * You may obtain a copy of the License at 6125 * 6126 * http://www.apache.org/licenses/LICENSE-2.0 6127 * 6128 * Unless required by applicable law or agreed to in writing, software 6129 * distributed under the License is distributed on an "AS IS" BASIS, 6130 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6131 * See the License for the specific language governing permissions and 6132 * limitations under the License. 6133 * 6134 * @providesModule ReactDOMOption 6135 */ 6136 6137 "use strict"; 6138 6139 var ReactCompositeComponent = require("./ReactCompositeComponent"); 6140 var ReactDOM = require("./ReactDOM"); 6141 6142 // Store a reference to the <option> `ReactDOMComponent`. 6143 var option = ReactDOM.option; 6144 6145 /** 6146 * Implements an <option> native component that warns when `selected` is set. 6147 */ 6148 var ReactDOMOption = ReactCompositeComponent.createClass({ 6149 6150 componentWillMount: function() { 6151 // TODO (yungsters): Remove support for `selected` in <option>. 6152 if (this.props.selected != null) { 6153 if ("production" !== "development") { 6154 console.warn( 6155 'Use the `defaultValue` or `value` props on <select> instead of ' + 6156 'setting `selected` on <option>.' 6157 ); 6158 } 6159 } 6160 }, 6161 6162 render: function() { 6163 return option(this.props, this.props.children); 6164 } 6165 6166 }); 6167 6168 module.exports = ReactDOMOption; 6169 6170 },{"./ReactCompositeComponent":28,"./ReactDOM":30}],37:[function(require,module,exports){ 6171 /** 6172 * Copyright 2013 Facebook, Inc. 6173 * 6174 * Licensed under the Apache License, Version 2.0 (the "License"); 6175 * you may not use this file except in compliance with the License. 6176 * You may obtain a copy of the License at 6177 * 6178 * http://www.apache.org/licenses/LICENSE-2.0 6179 * 6180 * Unless required by applicable law or agreed to in writing, software 6181 * distributed under the License is distributed on an "AS IS" BASIS, 6182 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6183 * See the License for the specific language governing permissions and 6184 * limitations under the License. 6185 * 6186 * @providesModule ReactDOMSelect 6187 */ 6188 6189 "use strict"; 6190 6191 var LinkedValueMixin = require("./LinkedValueMixin"); 6192 var ReactCompositeComponent = require("./ReactCompositeComponent"); 6193 var ReactDOM = require("./ReactDOM"); 6194 6195 var invariant = require("./invariant"); 6196 var merge = require("./merge"); 6197 6198 // Store a reference to the <select> `ReactDOMComponent`. 6199 var select = ReactDOM.select; 6200 6201 /** 6202 * Validation function for `value` and `defaultValue`. 6203 * @private 6204 */ 6205 function selectValueType(props, propName, componentName) { 6206 if (props[propName] == null) { 6207 return; 6208 } 6209 if (props.multiple) { 6210 ("production" !== "development" ? invariant( 6211 Array.isArray(props[propName]), 6212 'The `%s` prop supplied to <select> must be an array if `multiple` is ' + 6213 'true.', 6214 propName 6215 ) : invariant(Array.isArray(props[propName]))); 6216 } else { 6217 ("production" !== "development" ? invariant( 6218 !Array.isArray(props[propName]), 6219 'The `%s` prop supplied to <select> must be a scalar value if ' + 6220 '`multiple` is false.', 6221 propName 6222 ) : invariant(!Array.isArray(props[propName]))); 6223 } 6224 } 6225 6226 /** 6227 * If `value` is supplied, updates <option> elements on mount and update. 6228 * @private 6229 */ 6230 function updateOptions() { 6231 /*jshint validthis:true */ 6232 var propValue = this.getValue(); 6233 var value = propValue != null ? propValue : this.state.value; 6234 var options = this.getDOMNode().options; 6235 var selectedValue = '' + value; 6236 6237 for (var i = 0, l = options.length; i < l; i++) { 6238 var selected = this.props.multiple ? 6239 selectedValue.indexOf(options[i].value) >= 0 : 6240 selected = options[i].value === selectedValue; 6241 6242 if (selected !== options[i].selected) { 6243 options[i].selected = selected; 6244 } 6245 } 6246 } 6247 6248 /** 6249 * Implements a <select> native component that allows optionally setting the 6250 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a 6251 * string. If `multiple` is true, the prop must be an array of strings. 6252 * 6253 * If `value` is not supplied (or null/undefined), user actions that change the 6254 * selected option will trigger updates to the rendered options. 6255 * 6256 * If it is supplied (and not null/undefined), the rendered options will not 6257 * update in response to user actions. Instead, the `value` prop must change in 6258 * order for the rendered options to update. 6259 * 6260 * If `defaultValue` is provided, any options with the supplied values will be 6261 * selected. 6262 */ 6263 var ReactDOMSelect = ReactCompositeComponent.createClass({ 6264 mixins: [LinkedValueMixin], 6265 6266 propTypes: { 6267 defaultValue: selectValueType, 6268 value: selectValueType 6269 }, 6270 6271 getInitialState: function() { 6272 return {value: this.props.defaultValue || (this.props.multiple ? [] : '')}; 6273 }, 6274 6275 componentWillReceiveProps: function(nextProps) { 6276 if (!this.props.multiple && nextProps.multiple) { 6277 this.setState({value: [this.state.value]}); 6278 } else if (this.props.multiple && !nextProps.multiple) { 6279 this.setState({value: this.state.value[0]}); 6280 } 6281 }, 6282 6283 shouldComponentUpdate: function() { 6284 // Defer any updates to this component during the `onChange` handler. 6285 return !this._isChanging; 6286 }, 6287 6288 render: function() { 6289 // Clone `this.props` so we don't mutate the input. 6290 var props = merge(this.props); 6291 6292 props.onChange = this._handleChange; 6293 props.value = null; 6294 6295 return select(props, this.props.children); 6296 }, 6297 6298 componentDidMount: updateOptions, 6299 6300 componentDidUpdate: updateOptions, 6301 6302 _handleChange: function(event) { 6303 var returnValue; 6304 var onChange = this.getOnChange(); 6305 if (onChange) { 6306 this._isChanging = true; 6307 returnValue = onChange(event); 6308 this._isChanging = false; 6309 } 6310 6311 var selectedValue; 6312 if (this.props.multiple) { 6313 selectedValue = []; 6314 var options = event.target.options; 6315 for (var i = 0, l = options.length; i < l; i++) { 6316 if (options[i].selected) { 6317 selectedValue.push(options[i].value); 6318 } 6319 } 6320 } else { 6321 selectedValue = event.target.value; 6322 } 6323 6324 this.setState({value: selectedValue}); 6325 return returnValue; 6326 } 6327 6328 }); 6329 6330 module.exports = ReactDOMSelect; 6331 6332 },{"./LinkedValueMixin":21,"./ReactCompositeComponent":28,"./ReactDOM":30,"./invariant":98,"./merge":107}],38:[function(require,module,exports){ 6333 /** 6334 * Copyright 2013 Facebook, Inc. 6335 * 6336 * Licensed under the Apache License, Version 2.0 (the "License"); 6337 * you may not use this file except in compliance with the License. 6338 * You may obtain a copy of the License at 6339 * 6340 * http://www.apache.org/licenses/LICENSE-2.0 6341 * 6342 * Unless required by applicable law or agreed to in writing, software 6343 * distributed under the License is distributed on an "AS IS" BASIS, 6344 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6345 * See the License for the specific language governing permissions and 6346 * limitations under the License. 6347 * 6348 * @providesModule ReactDOMSelection 6349 */ 6350 6351 "use strict"; 6352 6353 var getNodeForCharacterOffset = require("./getNodeForCharacterOffset"); 6354 var getTextContentAccessor = require("./getTextContentAccessor"); 6355 6356 /** 6357 * Get the appropriate anchor and focus node/offset pairs for IE. 6358 * 6359 * The catch here is that IE's selection API doesn't provide information 6360 * about whether the selection is forward or backward, so we have to 6361 * behave as though it's always forward. 6362 * 6363 * IE text differs from modern selection in that it behaves as though 6364 * block elements end with a new line. This means character offsets will 6365 * differ between the two APIs. 6366 * 6367 * @param {DOMElement} node 6368 * @return {object} 6369 */ 6370 function getIEOffsets(node) { 6371 var selection = document.selection; 6372 var selectedRange = selection.createRange(); 6373 var selectedLength = selectedRange.text.length; 6374 6375 // Duplicate selection so we can move range without breaking user selection. 6376 var fromStart = selectedRange.duplicate(); 6377 fromStart.moveToElementText(node); 6378 fromStart.setEndPoint('EndToStart', selectedRange); 6379 6380 var startOffset = fromStart.text.length; 6381 var endOffset = startOffset + selectedLength; 6382 6383 return { 6384 start: startOffset, 6385 end: endOffset 6386 }; 6387 } 6388 6389 /** 6390 * @param {DOMElement} node 6391 * @return {?object} 6392 */ 6393 function getModernOffsets(node) { 6394 var selection = window.getSelection(); 6395 6396 if (selection.rangeCount === 0) { 6397 return null; 6398 } 6399 6400 var anchorNode = selection.anchorNode; 6401 var anchorOffset = selection.anchorOffset; 6402 var focusNode = selection.focusNode; 6403 var focusOffset = selection.focusOffset; 6404 6405 var currentRange = selection.getRangeAt(0); 6406 var rangeLength = currentRange.toString().length; 6407 6408 var tempRange = currentRange.cloneRange(); 6409 tempRange.selectNodeContents(node); 6410 tempRange.setEnd(currentRange.startContainer, currentRange.startOffset); 6411 6412 var start = tempRange.toString().length; 6413 var end = start + rangeLength; 6414 6415 // Detect whether the selection is backward. 6416 var detectionRange = document.createRange(); 6417 detectionRange.setStart(anchorNode, anchorOffset); 6418 detectionRange.setEnd(focusNode, focusOffset); 6419 var isBackward = detectionRange.collapsed; 6420 detectionRange.detach(); 6421 6422 return { 6423 start: isBackward ? end : start, 6424 end: isBackward ? start : end 6425 }; 6426 } 6427 6428 /** 6429 * @param {DOMElement|DOMTextNode} node 6430 * @param {object} offsets 6431 */ 6432 function setIEOffsets(node, offsets) { 6433 var range = document.selection.createRange().duplicate(); 6434 var start, end; 6435 6436 if (typeof offsets.end === 'undefined') { 6437 start = offsets.start; 6438 end = start; 6439 } else if (offsets.start > offsets.end) { 6440 start = offsets.end; 6441 end = offsets.start; 6442 } else { 6443 start = offsets.start; 6444 end = offsets.end; 6445 } 6446 6447 range.moveToElementText(node); 6448 range.moveStart('character', start); 6449 range.setEndPoint('EndToStart', range); 6450 range.moveEnd('character', end - start); 6451 range.select(); 6452 } 6453 6454 /** 6455 * In modern non-IE browsers, we can support both forward and backward 6456 * selections. 6457 * 6458 * Note: IE10+ supports the Selection object, but it does not support 6459 * the `extend` method, which means that even in modern IE, it's not possible 6460 * to programatically create a backward selection. Thus, for all IE 6461 * versions, we use the old IE API to create our selections. 6462 * 6463 * @param {DOMElement|DOMTextNode} node 6464 * @param {object} offsets 6465 */ 6466 function setModernOffsets(node, offsets) { 6467 var selection = window.getSelection(); 6468 6469 var length = node[getTextContentAccessor()].length; 6470 var start = Math.min(offsets.start, length); 6471 var end = typeof offsets.end === 'undefined' ? 6472 start : Math.min(offsets.end, length); 6473 6474 // IE 11 uses modern selection, but doesn't support the extend method. 6475 // Flip backward selections, so we can set with a single range. 6476 if (!selection.extend && start > end) { 6477 var temp = end; 6478 end = start; 6479 start = temp; 6480 } 6481 6482 var startMarker = getNodeForCharacterOffset(node, start); 6483 var endMarker = getNodeForCharacterOffset(node, end); 6484 6485 if (startMarker && endMarker) { 6486 var range = document.createRange(); 6487 range.setStart(startMarker.node, startMarker.offset); 6488 selection.removeAllRanges(); 6489 6490 if (start > end) { 6491 selection.addRange(range); 6492 selection.extend(endMarker.node, endMarker.offset); 6493 } else { 6494 range.setEnd(endMarker.node, endMarker.offset); 6495 selection.addRange(range); 6496 } 6497 6498 range.detach(); 6499 } 6500 } 6501 6502 var ReactDOMSelection = { 6503 /** 6504 * @param {DOMElement} node 6505 */ 6506 getOffsets: function(node) { 6507 var getOffsets = document.selection ? getIEOffsets : getModernOffsets; 6508 return getOffsets(node); 6509 }, 6510 6511 /** 6512 * @param {DOMElement|DOMTextNode} node 6513 * @param {object} offsets 6514 */ 6515 setOffsets: function(node, offsets) { 6516 var setOffsets = document.selection ? setIEOffsets : setModernOffsets; 6517 setOffsets(node, offsets); 6518 } 6519 }; 6520 6521 module.exports = ReactDOMSelection; 6522 6523 },{"./getNodeForCharacterOffset":93,"./getTextContentAccessor":95}],39:[function(require,module,exports){ 6524 /** 6525 * Copyright 2013 Facebook, Inc. 6526 * 6527 * Licensed under the Apache License, Version 2.0 (the "License"); 6528 * you may not use this file except in compliance with the License. 6529 * You may obtain a copy of the License at 6530 * 6531 * http://www.apache.org/licenses/LICENSE-2.0 6532 * 6533 * Unless required by applicable law or agreed to in writing, software 6534 * distributed under the License is distributed on an "AS IS" BASIS, 6535 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6536 * See the License for the specific language governing permissions and 6537 * limitations under the License. 6538 * 6539 * @providesModule ReactDOMTextarea 6540 */ 6541 6542 "use strict"; 6543 6544 var DOMPropertyOperations = require("./DOMPropertyOperations"); 6545 var LinkedValueMixin = require("./LinkedValueMixin"); 6546 var ReactCompositeComponent = require("./ReactCompositeComponent"); 6547 var ReactDOM = require("./ReactDOM"); 6548 6549 var invariant = require("./invariant"); 6550 var merge = require("./merge"); 6551 6552 // Store a reference to the <textarea> `ReactDOMComponent`. 6553 var textarea = ReactDOM.textarea; 6554 6555 /** 6556 * Implements a <textarea> native component that allows setting `value`, and 6557 * `defaultValue`. This differs from the traditional DOM API because value is 6558 * usually set as PCDATA children. 6559 * 6560 * If `value` is not supplied (or null/undefined), user actions that affect the 6561 * value will trigger updates to the element. 6562 * 6563 * If `value` is supplied (and not null/undefined), the rendered element will 6564 * not trigger updates to the element. Instead, the `value` prop must change in 6565 * order for the rendered element to be updated. 6566 * 6567 * The rendered element will be initialized with an empty value, the prop 6568 * `defaultValue` if specified, or the children content (deprecated). 6569 */ 6570 var ReactDOMTextarea = ReactCompositeComponent.createClass({ 6571 mixins: [LinkedValueMixin], 6572 6573 getInitialState: function() { 6574 var defaultValue = this.props.defaultValue; 6575 // TODO (yungsters): Remove support for children content in <textarea>. 6576 var children = this.props.children; 6577 if (children != null) { 6578 if ("production" !== "development") { 6579 console.warn( 6580 'Use the `defaultValue` or `value` props instead of setting ' + 6581 'children on <textarea>.' 6582 ); 6583 } 6584 ("production" !== "development" ? invariant( 6585 defaultValue == null, 6586 'If you supply `defaultValue` on a <textarea>, do not pass children.' 6587 ) : invariant(defaultValue == null)); 6588 if (Array.isArray(children)) { 6589 ("production" !== "development" ? invariant( 6590 children.length <= 1, 6591 '<textarea> can only have at most one child.' 6592 ) : invariant(children.length <= 1)); 6593 children = children[0]; 6594 } 6595 6596 defaultValue = '' + children; 6597 } 6598 if (defaultValue == null) { 6599 defaultValue = ''; 6600 } 6601 var value = this.getValue(); 6602 return { 6603 // We save the initial value so that `ReactDOMComponent` doesn't update 6604 // `textContent` (unnecessary since we update value). 6605 // The initial value can be a boolean or object so that's why it's 6606 // forced to be a string. 6607 initialValue: '' + (value != null ? value : defaultValue), 6608 value: defaultValue 6609 }; 6610 }, 6611 6612 shouldComponentUpdate: function() { 6613 // Defer any updates to this component during the `onChange` handler. 6614 return !this._isChanging; 6615 }, 6616 6617 render: function() { 6618 // Clone `this.props` so we don't mutate the input. 6619 var props = merge(this.props); 6620 var value = this.getValue(); 6621 6622 ("production" !== "development" ? invariant( 6623 props.dangerouslySetInnerHTML == null, 6624 '`dangerouslySetInnerHTML` does not make sense on <textarea>.' 6625 ) : invariant(props.dangerouslySetInnerHTML == null)); 6626 6627 props.defaultValue = null; 6628 props.value = value != null ? value : this.state.value; 6629 props.onChange = this._handleChange; 6630 6631 // Always set children to the same thing. In IE9, the selection range will 6632 // get reset if `textContent` is mutated. 6633 return textarea(props, this.state.initialValue); 6634 }, 6635 6636 componentDidUpdate: function(prevProps, prevState, rootNode) { 6637 var value = this.getValue(); 6638 if (value != null) { 6639 // Cast `value` to a string to ensure the value is set correctly. While 6640 // browsers typically do this as necessary, jsdom doesn't. 6641 DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value); 6642 } 6643 }, 6644 6645 _handleChange: function(event) { 6646 var returnValue; 6647 var onChange = this.getOnChange(); 6648 if (onChange) { 6649 this._isChanging = true; 6650 returnValue = onChange(event); 6651 this._isChanging = false; 6652 } 6653 this.setState({value: event.target.value}); 6654 return returnValue; 6655 } 6656 6657 }); 6658 6659 module.exports = ReactDOMTextarea; 6660 6661 },{"./DOMPropertyOperations":9,"./LinkedValueMixin":21,"./ReactCompositeComponent":28,"./ReactDOM":30,"./invariant":98,"./merge":107}],40:[function(require,module,exports){ 6662 /** 6663 * Copyright 2013 Facebook, Inc. 6664 * 6665 * Licensed under the Apache License, Version 2.0 (the "License"); 6666 * you may not use this file except in compliance with the License. 6667 * You may obtain a copy of the License at 6668 * 6669 * http://www.apache.org/licenses/LICENSE-2.0 6670 * 6671 * Unless required by applicable law or agreed to in writing, software 6672 * distributed under the License is distributed on an "AS IS" BASIS, 6673 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6674 * See the License for the specific language governing permissions and 6675 * limitations under the License. 6676 * 6677 * @providesModule ReactDefaultBatchingStrategy 6678 */ 6679 6680 "use strict"; 6681 6682 var ReactUpdates = require("./ReactUpdates"); 6683 var Transaction = require("./Transaction"); 6684 6685 var emptyFunction = require("./emptyFunction"); 6686 var mixInto = require("./mixInto"); 6687 6688 var RESET_BATCHED_UPDATES = { 6689 initialize: emptyFunction, 6690 close: function() { 6691 ReactDefaultBatchingStrategy.isBatchingUpdates = false; 6692 } 6693 }; 6694 6695 var FLUSH_BATCHED_UPDATES = { 6696 initialize: emptyFunction, 6697 close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates) 6698 }; 6699 6700 var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES]; 6701 6702 function ReactDefaultBatchingStrategyTransaction() { 6703 this.reinitializeTransaction(); 6704 } 6705 6706 mixInto(ReactDefaultBatchingStrategyTransaction, Transaction.Mixin); 6707 mixInto(ReactDefaultBatchingStrategyTransaction, { 6708 getTransactionWrappers: function() { 6709 return TRANSACTION_WRAPPERS; 6710 } 6711 }); 6712 6713 var transaction = new ReactDefaultBatchingStrategyTransaction(); 6714 6715 var ReactDefaultBatchingStrategy = { 6716 isBatchingUpdates: false, 6717 6718 /** 6719 * Call the provided function in a context within which calls to `setState` 6720 * and friends are batched such that components aren't updated unnecessarily. 6721 */ 6722 batchedUpdates: function(callback, param) { 6723 var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates; 6724 6725 ReactDefaultBatchingStrategy.isBatchingUpdates = true; 6726 6727 // The code is written this way to avoid extra allocations 6728 if (alreadyBatchingUpdates) { 6729 callback(param); 6730 } else { 6731 transaction.perform(callback, null, param); 6732 } 6733 } 6734 }; 6735 6736 module.exports = ReactDefaultBatchingStrategy; 6737 6738 },{"./ReactUpdates":61,"./Transaction":73,"./emptyFunction":83,"./mixInto":110}],41:[function(require,module,exports){ 6739 /** 6740 * Copyright 2013 Facebook, Inc. 6741 * 6742 * Licensed under the Apache License, Version 2.0 (the "License"); 6743 * you may not use this file except in compliance with the License. 6744 * You may obtain a copy of the License at 6745 * 6746 * http://www.apache.org/licenses/LICENSE-2.0 6747 * 6748 * Unless required by applicable law or agreed to in writing, software 6749 * distributed under the License is distributed on an "AS IS" BASIS, 6750 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6751 * See the License for the specific language governing permissions and 6752 * limitations under the License. 6753 * 6754 * @providesModule ReactDefaultInjection 6755 */ 6756 6757 "use strict"; 6758 6759 var ReactDOM = require("./ReactDOM"); 6760 var ReactDOMButton = require("./ReactDOMButton"); 6761 var ReactDOMForm = require("./ReactDOMForm"); 6762 var ReactDOMInput = require("./ReactDOMInput"); 6763 var ReactDOMOption = require("./ReactDOMOption"); 6764 var ReactDOMSelect = require("./ReactDOMSelect"); 6765 var ReactDOMTextarea = require("./ReactDOMTextarea"); 6766 var ReactEventEmitter = require("./ReactEventEmitter"); 6767 var ReactEventTopLevelCallback = require("./ReactEventTopLevelCallback"); 6768 var ReactPerf = require("./ReactPerf"); 6769 6770 var DefaultDOMPropertyConfig = require("./DefaultDOMPropertyConfig"); 6771 var DOMProperty = require("./DOMProperty"); 6772 6773 var ChangeEventPlugin = require("./ChangeEventPlugin"); 6774 var CompositionEventPlugin = require("./CompositionEventPlugin"); 6775 var DefaultEventPluginOrder = require("./DefaultEventPluginOrder"); 6776 var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin"); 6777 var EventPluginHub = require("./EventPluginHub"); 6778 var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin"); 6779 var ReactInstanceHandles = require("./ReactInstanceHandles"); 6780 var SelectEventPlugin = require("./SelectEventPlugin"); 6781 var SimpleEventPlugin = require("./SimpleEventPlugin"); 6782 6783 var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy"); 6784 var ReactUpdates = require("./ReactUpdates"); 6785 6786 function inject() { 6787 ReactEventEmitter.TopLevelCallbackCreator = ReactEventTopLevelCallback; 6788 /** 6789 * Inject module for resolving DOM hierarchy and plugin ordering. 6790 */ 6791 EventPluginHub.injection.injectEventPluginOrder(DefaultEventPluginOrder); 6792 EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles); 6793 6794 /** 6795 * Some important event plugins included by default (without having to require 6796 * them). 6797 */ 6798 EventPluginHub.injection.injectEventPluginsByName({ 6799 SimpleEventPlugin: SimpleEventPlugin, 6800 EnterLeaveEventPlugin: EnterLeaveEventPlugin, 6801 ChangeEventPlugin: ChangeEventPlugin, 6802 CompositionEventPlugin: CompositionEventPlugin, 6803 MobileSafariClickEventPlugin: MobileSafariClickEventPlugin, 6804 SelectEventPlugin: SelectEventPlugin 6805 }); 6806 6807 ReactDOM.injection.injectComponentClasses({ 6808 button: ReactDOMButton, 6809 form: ReactDOMForm, 6810 input: ReactDOMInput, 6811 option: ReactDOMOption, 6812 select: ReactDOMSelect, 6813 textarea: ReactDOMTextarea 6814 }); 6815 6816 DOMProperty.injection.injectDOMPropertyConfig(DefaultDOMPropertyConfig); 6817 6818 if ("production" !== "development") { 6819 ReactPerf.injection.injectMeasure(require("./ReactDefaultPerf").measure); 6820 } 6821 6822 ReactUpdates.injection.injectBatchingStrategy( 6823 ReactDefaultBatchingStrategy 6824 ); 6825 } 6826 6827 module.exports = { 6828 inject: inject 6829 }; 6830 6831 },{"./ChangeEventPlugin":5,"./CompositionEventPlugin":6,"./DOMProperty":8,"./DefaultDOMPropertyConfig":11,"./DefaultEventPluginOrder":12,"./EnterLeaveEventPlugin":13,"./EventPluginHub":16,"./MobileSafariClickEventPlugin":22,"./ReactDOM":30,"./ReactDOMButton":31,"./ReactDOMForm":33,"./ReactDOMInput":35,"./ReactDOMOption":36,"./ReactDOMSelect":37,"./ReactDOMTextarea":39,"./ReactDefaultBatchingStrategy":40,"./ReactDefaultPerf":42,"./ReactEventEmitter":44,"./ReactEventTopLevelCallback":46,"./ReactInstanceHandles":48,"./ReactPerf":55,"./ReactUpdates":61,"./SelectEventPlugin":62,"./SimpleEventPlugin":63}],42:[function(require,module,exports){ 6832 /** 6833 * Copyright 2013 Facebook, Inc. 6834 * 6835 * Licensed under the Apache License, Version 2.0 (the "License"); 6836 * you may not use this file except in compliance with the License. 6837 * You may obtain a copy of the License at 6838 * 6839 * http://www.apache.org/licenses/LICENSE-2.0 6840 * 6841 * Unless required by applicable law or agreed to in writing, software 6842 * distributed under the License is distributed on an "AS IS" BASIS, 6843 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6844 * See the License for the specific language governing permissions and 6845 * limitations under the License. 6846 * 6847 * @providesModule ReactDefaultPerf 6848 * @typechecks static-only 6849 */ 6850 6851 "use strict"; 6852 6853 var performanceNow = require("./performanceNow"); 6854 6855 var ReactDefaultPerf = {}; 6856 6857 if ("production" !== "development") { 6858 ReactDefaultPerf = { 6859 /** 6860 * Gets the stored information for a given object's function. 6861 * 6862 * @param {string} objName 6863 * @param {string} fnName 6864 * @return {?object} 6865 */ 6866 getInfo: function(objName, fnName) { 6867 if (!this.info[objName] || !this.info[objName][fnName]) { 6868 return null; 6869 } 6870 return this.info[objName][fnName]; 6871 }, 6872 6873 /** 6874 * Gets the logs pertaining to a given object's function. 6875 * 6876 * @param {string} objName 6877 * @param {string} fnName 6878 * @return {?array<object>} 6879 */ 6880 getLogs: function(objName, fnName) { 6881 if (!this.getInfo(objName, fnName)) { 6882 return null; 6883 } 6884 return this.logs.filter(function(log) { 6885 return log.objName === objName && log.fnName === fnName; 6886 }); 6887 }, 6888 6889 /** 6890 * Runs through the logs and builds an array of arrays, where each array 6891 * walks through the mounting/updating of each component underneath. 6892 * 6893 * @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]' 6894 * @return {array<array>} 6895 */ 6896 getRawRenderHistory: function(rootID) { 6897 var history = []; 6898 /** 6899 * Since logs are added after the method returns, the logs are in a sense 6900 * upside-down: the inner-most elements from mounting/updating are logged 6901 * first, and the last addition to the log is the top renderComponent. 6902 * Therefore, we flip the logs upside down for ease of processing, and 6903 * reverse the history array at the end so the earliest event has index 0. 6904 */ 6905 var logs = this.logs.filter(function(log) { 6906 return log.reactID.indexOf(rootID) === 0; 6907 }).reverse(); 6908 6909 var subHistory = []; 6910 logs.forEach(function(log, i) { 6911 if (i && log.reactID === rootID && logs[i - 1].reactID !== rootID) { 6912 subHistory.length && history.push(subHistory); 6913 subHistory = []; 6914 } 6915 subHistory.push(log); 6916 }); 6917 if (subHistory.length) { 6918 history.push(subHistory); 6919 } 6920 return history.reverse(); 6921 }, 6922 6923 /** 6924 * Runs through the logs and builds an array of strings, where each string 6925 * is a multiline formatted way of walking through the mounting/updating 6926 * underneath. 6927 * 6928 * @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]' 6929 * @return {array<string>} 6930 */ 6931 getRenderHistory: function(rootID) { 6932 var history = this.getRawRenderHistory(rootID); 6933 6934 return history.map(function(subHistory) { 6935 var headerString = ( 6936 'log# Component (execution time) [bloat from logging]\n' + 6937 '================================================================\n' 6938 ); 6939 return headerString + subHistory.map(function(log) { 6940 // Add two spaces for every layer in the reactID. 6941 var indents = '\t' + Array(log.reactID.split('.[').length).join(' '); 6942 var delta = _microTime(log.timing.delta); 6943 var bloat = _microTime(log.timing.timeToLog); 6944 6945 return log.index + indents + log.name + ' (' + delta + 'ms)' + 6946 ' [' + bloat + 'ms]'; 6947 }).join('\n'); 6948 }); 6949 }, 6950 6951 /** 6952 * Print the render history from `getRenderHistory` using console.log. 6953 * This is currently the best way to display perf data from 6954 * any React component; working on that. 6955 * 6956 * @param {string} rootID The reactID of the root node, e.g. '.r[2cpyq]' 6957 * @param {number} index 6958 */ 6959 printRenderHistory: function(rootID, index) { 6960 var history = this.getRenderHistory(rootID); 6961 if (!history[index]) { 6962 console.warn( 6963 'Index', index, 'isn\'t available! ' + 6964 'The render history is', history.length, 'long.' 6965 ); 6966 return; 6967 } 6968 console.log( 6969 'Loading render history #' + (index + 1) + 6970 ' of ' + history.length + ':\n' + history[index] 6971 ); 6972 }, 6973 6974 /** 6975 * Prints the heatmap legend to console, showing how the colors correspond 6976 * with render times. This relies on console.log styles. 6977 */ 6978 printHeatmapLegend: function() { 6979 if (!this.options.heatmap.enabled) { 6980 return; 6981 } 6982 var max = this.info.React 6983 && this.info.React.renderComponent 6984 && this.info.React.renderComponent.max; 6985 if (max) { 6986 var logStr = 'Heatmap: '; 6987 for (var ii = 0; ii <= 10 * max; ii += max) { 6988 logStr += '%c ' + (Math.round(ii) / 10) + 'ms '; 6989 } 6990 console.log( 6991 logStr, 6992 'background-color: hsla(100, 100%, 50%, 0.6);', 6993 'background-color: hsla( 90, 100%, 50%, 0.6);', 6994 'background-color: hsla( 80, 100%, 50%, 0.6);', 6995 'background-color: hsla( 70, 100%, 50%, 0.6);', 6996 'background-color: hsla( 60, 100%, 50%, 0.6);', 6997 'background-color: hsla( 50, 100%, 50%, 0.6);', 6998 'background-color: hsla( 40, 100%, 50%, 0.6);', 6999 'background-color: hsla( 30, 100%, 50%, 0.6);', 7000 'background-color: hsla( 20, 100%, 50%, 0.6);', 7001 'background-color: hsla( 10, 100%, 50%, 0.6);', 7002 'background-color: hsla( 0, 100%, 50%, 0.6);' 7003 ); 7004 } 7005 }, 7006 7007 /** 7008 * Measure a given function with logging information, and calls a callback 7009 * if there is one. 7010 * 7011 * @param {string} objName 7012 * @param {string} fnName 7013 * @param {function} func 7014 * @return {function} 7015 */ 7016 measure: function(objName, fnName, func) { 7017 var info = _getNewInfo(objName, fnName); 7018 7019 var fnArgs = _getFnArguments(func); 7020 7021 return function() { 7022 var timeBeforeFn = performanceNow(); 7023 var fnReturn = func.apply(this, arguments); 7024 var timeAfterFn = performanceNow(); 7025 7026 /** 7027 * Hold onto arguments in a readable way: args[1] -> args.component. 7028 * args is also passed to the callback, so if you want to save an 7029 * argument in the log, do so in the callback. 7030 */ 7031 var args = {}; 7032 for (var i = 0; i < arguments.length; i++) { 7033 args[fnArgs[i]] = arguments[i]; 7034 } 7035 7036 var log = { 7037 index: ReactDefaultPerf.logs.length, 7038 fnName: fnName, 7039 objName: objName, 7040 timing: { 7041 before: timeBeforeFn, 7042 after: timeAfterFn, 7043 delta: timeAfterFn - timeBeforeFn 7044 } 7045 }; 7046 7047 ReactDefaultPerf.logs.push(log); 7048 7049 /** 7050 * The callback gets: 7051 * - this (the component) 7052 * - the original method's arguments 7053 * - what the method returned 7054 * - the log object, and 7055 * - the wrapped method's info object. 7056 */ 7057 var callback = _getCallback(objName, fnName); 7058 callback && callback(this, args, fnReturn, log, info); 7059 7060 log.timing.timeToLog = performanceNow() - timeAfterFn; 7061 7062 return fnReturn; 7063 }; 7064 }, 7065 7066 /** 7067 * Holds information on wrapped objects/methods. 7068 * For instance, ReactDefaultPerf.info.React.renderComponent 7069 */ 7070 info: {}, 7071 7072 /** 7073 * Holds all of the logs. Filter this to pull desired information. 7074 */ 7075 logs: [], 7076 7077 /** 7078 * Toggle settings for ReactDefaultPerf 7079 */ 7080 options: { 7081 /** 7082 * The heatmap sets the background color of the React containers 7083 * according to how much total time has been spent rendering them. 7084 * The most temporally expensive component is set as pure red, 7085 * and the others are colored from green to red as a fraction 7086 * of that max component time. 7087 */ 7088 heatmap: { 7089 enabled: true 7090 } 7091 } 7092 }; 7093 7094 /** 7095 * Gets a info area for a given object's function, adding a new one if 7096 * necessary. 7097 * 7098 * @param {string} objName 7099 * @param {string} fnName 7100 * @return {object} 7101 */ 7102 var _getNewInfo = function(objName, fnName) { 7103 var info = ReactDefaultPerf.getInfo(objName, fnName); 7104 if (info) { 7105 return info; 7106 } 7107 ReactDefaultPerf.info[objName] = ReactDefaultPerf.info[objName] || {}; 7108 7109 return ReactDefaultPerf.info[objName][fnName] = { 7110 getLogs: function() { 7111 return ReactDefaultPerf.getLogs(objName, fnName); 7112 } 7113 }; 7114 }; 7115 7116 /** 7117 * Gets a list of the argument names from a function's definition. 7118 * This is useful for storing arguments by their names within wrapFn(). 7119 * 7120 * @param {function} fn 7121 * @return {array<string>} 7122 */ 7123 var _getFnArguments = function(fn) { 7124 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 7125 var fnStr = fn.toString().replace(STRIP_COMMENTS, ''); 7126 fnStr = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')); 7127 return fnStr.match(/([^\s,]+)/g); 7128 }; 7129 7130 /** 7131 * Store common callbacks within ReactDefaultPerf. 7132 * 7133 * @param {string} objName 7134 * @param {string} fnName 7135 * @return {?function} 7136 */ 7137 var _getCallback = function(objName, fnName) { 7138 switch (objName + '.' + fnName) { 7139 case 'React.renderComponent': 7140 return _renderComponentCallback; 7141 case 'ReactDOMComponent.mountComponent': 7142 case 'ReactDOMComponent.updateComponent': 7143 return _nativeComponentCallback; 7144 case 'ReactCompositeComponent.mountComponent': 7145 case 'ReactCompositeComponent.updateComponent': 7146 return _compositeComponentCallback; 7147 default: 7148 return null; 7149 } 7150 }; 7151 7152 /** 7153 * Callback function for React.renderComponent 7154 * 7155 * @param {object} component 7156 * @param {object} args 7157 * @param {?object} fnReturn 7158 * @param {object} log 7159 * @param {object} info 7160 */ 7161 var _renderComponentCallback = 7162 function(component, args, fnReturn, log, info) { 7163 log.name = args.nextComponent.constructor.displayName || '[unknown]'; 7164 log.reactID = fnReturn._rootNodeID || null; 7165 7166 if (ReactDefaultPerf.options.heatmap.enabled) { 7167 var container = args.container; 7168 if (!container.loggedByReactDefaultPerf) { 7169 container.loggedByReactDefaultPerf = true; 7170 info.components = info.components || []; 7171 info.components.push(container); 7172 } 7173 7174 container.count = container.count || 0; 7175 container.count += log.timing.delta; 7176 info.max = info.max || 0; 7177 if (container.count > info.max) { 7178 info.max = container.count; 7179 info.components.forEach(function(component) { 7180 _setHue(component, 100 - 100 * component.count / info.max); 7181 }); 7182 } else { 7183 _setHue(container, 100 - 100 * container.count / info.max); 7184 } 7185 } 7186 }; 7187 7188 /** 7189 * Callback function for ReactDOMComponent 7190 * 7191 * @param {object} component 7192 * @param {object} args 7193 * @param {?object} fnReturn 7194 * @param {object} log 7195 * @param {object} info 7196 */ 7197 var _nativeComponentCallback = 7198 function(component, args, fnReturn, log, info) { 7199 log.name = component.tagName || '[unknown]'; 7200 log.reactID = component._rootNodeID; 7201 }; 7202 7203 /** 7204 * Callback function for ReactCompositeComponent 7205 * 7206 * @param {object} component 7207 * @param {object} args 7208 * @param {?object} fnReturn 7209 * @param {object} log 7210 * @param {object} info 7211 */ 7212 var _compositeComponentCallback = 7213 function(component, args, fnReturn, log, info) { 7214 log.name = component.constructor.displayName || '[unknown]'; 7215 log.reactID = component._rootNodeID; 7216 }; 7217 7218 /** 7219 * Using the hsl() background-color attribute, colors an element. 7220 * 7221 * @param {DOMElement} el 7222 * @param {number} hue [0 for red, 120 for green, 240 for blue] 7223 */ 7224 var _setHue = function(el, hue) { 7225 el.style.backgroundColor = 'hsla(' + hue + ', 100%, 50%, 0.6)'; 7226 }; 7227 7228 /** 7229 * Round to the thousandth place. 7230 * @param {number} time 7231 * @return {number} 7232 */ 7233 var _microTime = function(time) { 7234 return Math.round(time * 1000) / 1000; 7235 }; 7236 } 7237 7238 module.exports = ReactDefaultPerf; 7239 7240 },{"./performanceNow":114}],43:[function(require,module,exports){ 7241 /** 7242 * Copyright 2013 Facebook, Inc. 7243 * 7244 * Licensed under the Apache License, Version 2.0 (the "License"); 7245 * you may not use this file except in compliance with the License. 7246 * You may obtain a copy of the License at 7247 * 7248 * http://www.apache.org/licenses/LICENSE-2.0 7249 * 7250 * Unless required by applicable law or agreed to in writing, software 7251 * distributed under the License is distributed on an "AS IS" BASIS, 7252 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7253 * See the License for the specific language governing permissions and 7254 * limitations under the License. 7255 * 7256 * @providesModule ReactErrorUtils 7257 * @typechecks 7258 */ 7259 7260 var ReactErrorUtils = { 7261 /** 7262 * Creates a guarded version of a function. This is supposed to make debugging 7263 * of event handlers easier. This implementation provides only basic error 7264 * logging and re-throws the error. 7265 * 7266 * @param {function} func Function to be executed 7267 * @param {string} name The name of the guard 7268 * @return {function} 7269 */ 7270 guard: function(func, name) { 7271 if ("production" !== "development") { 7272 return function guarded() { 7273 try { 7274 return func.apply(this, arguments); 7275 } catch(ex) { 7276 console.error(name + ': ' + ex.message); 7277 throw ex; 7278 } 7279 }; 7280 } else { 7281 return func; 7282 } 7283 } 7284 }; 7285 7286 module.exports = ReactErrorUtils; 7287 7288 },{}],44:[function(require,module,exports){ 7289 /** 7290 * Copyright 2013 Facebook, Inc. 7291 * 7292 * Licensed under the Apache License, Version 2.0 (the "License"); 7293 * you may not use this file except in compliance with the License. 7294 * You may obtain a copy of the License at 7295 * 7296 * http://www.apache.org/licenses/LICENSE-2.0 7297 * 7298 * Unless required by applicable law or agreed to in writing, software 7299 * distributed under the License is distributed on an "AS IS" BASIS, 7300 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7301 * See the License for the specific language governing permissions and 7302 * limitations under the License. 7303 * 7304 * @providesModule ReactEventEmitter 7305 * @typechecks static-only 7306 */ 7307 7308 "use strict"; 7309 7310 var EventConstants = require("./EventConstants"); 7311 var EventListener = require("./EventListener"); 7312 var EventPluginHub = require("./EventPluginHub"); 7313 var ExecutionEnvironment = require("./ExecutionEnvironment"); 7314 var ReactEventEmitterMixin = require("./ReactEventEmitterMixin"); 7315 var ViewportMetrics = require("./ViewportMetrics"); 7316 7317 var invariant = require("./invariant"); 7318 var isEventSupported = require("./isEventSupported"); 7319 var merge = require("./merge"); 7320 7321 /** 7322 * Summary of `ReactEventEmitter` event handling: 7323 * 7324 * - Top-level delegation is used to trap native browser events. We normalize 7325 * and de-duplicate events to account for browser quirks. 7326 * 7327 * - Forward these native events (with the associated top-level type used to 7328 * trap it) to `EventPluginHub`, which in turn will ask plugins if they want 7329 * to extract any synthetic events. 7330 * 7331 * - The `EventPluginHub` will then process each event by annotating them with 7332 * "dispatches", a sequence of listeners and IDs that care about that event. 7333 * 7334 * - The `EventPluginHub` then dispatches the events. 7335 * 7336 * Overview of React and the event system: 7337 * 7338 * . 7339 * +------------+ . 7340 * | DOM | . 7341 * +------------+ . +-----------+ 7342 * + . +--------+|SimpleEvent| 7343 * | . | |Plugin | 7344 * +-----|------+ . v +-----------+ 7345 * | | | . +--------------+ +------------+ 7346 * | +-----------.--->|EventPluginHub| | Event | 7347 * | | . | | +-----------+ | Propagators| 7348 * | ReactEvent | . | | |TapEvent | |------------| 7349 * | Emitter | . | |<---+|Plugin | |other plugin| 7350 * | | . | | +-----------+ | utilities | 7351 * | +-----------.---------+ | +------------+ 7352 * | | | . +----|---------+ 7353 * +-----|------+ . | ^ +-----------+ 7354 * | . | | |Enter/Leave| 7355 * + . | +-------+|Plugin | 7356 * +-------------+ . v +-----------+ 7357 * | application | . +----------+ 7358 * |-------------| . | callback | 7359 * | | . | registry | 7360 * | | . +----------+ 7361 * +-------------+ . 7362 * . 7363 * React Core . General Purpose Event Plugin System 7364 */ 7365 7366 /** 7367 * Traps top-level events by using event bubbling. 7368 * 7369 * @param {string} topLevelType Record from `EventConstants`. 7370 * @param {string} handlerBaseName Event name (e.g. "click"). 7371 * @param {DOMEventTarget} element Element on which to attach listener. 7372 * @internal 7373 */ 7374 function trapBubbledEvent(topLevelType, handlerBaseName, element) { 7375 EventListener.listen( 7376 element, 7377 handlerBaseName, 7378 ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback( 7379 topLevelType 7380 ) 7381 ); 7382 } 7383 7384 /** 7385 * Traps a top-level event by using event capturing. 7386 * 7387 * @param {string} topLevelType Record from `EventConstants`. 7388 * @param {string} handlerBaseName Event name (e.g. "click"). 7389 * @param {DOMEventTarget} element Element on which to attach listener. 7390 * @internal 7391 */ 7392 function trapCapturedEvent(topLevelType, handlerBaseName, element) { 7393 EventListener.capture( 7394 element, 7395 handlerBaseName, 7396 ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback( 7397 topLevelType 7398 ) 7399 ); 7400 } 7401 7402 /** 7403 * Listens to window scroll and resize events. We cache scroll values so that 7404 * application code can access them without triggering reflows. 7405 * 7406 * NOTE: Scroll events do not bubble. 7407 * 7408 * @private 7409 * @see http://www.quirksmode.org/dom/events/scroll.html 7410 */ 7411 function registerScrollValueMonitoring() { 7412 var refresh = ViewportMetrics.refreshScrollValues; 7413 EventListener.listen(window, 'scroll', refresh); 7414 EventListener.listen(window, 'resize', refresh); 7415 } 7416 7417 /** 7418 * `ReactEventEmitter` is used to attach top-level event listeners. For example: 7419 * 7420 * ReactEventEmitter.putListener('myID', 'onClick', myFunction); 7421 * 7422 * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'. 7423 * 7424 * @internal 7425 */ 7426 var ReactEventEmitter = merge(ReactEventEmitterMixin, { 7427 7428 /** 7429 * React references `ReactEventTopLevelCallback` using this property in order 7430 * to allow dependency injection. 7431 */ 7432 TopLevelCallbackCreator: null, 7433 7434 /** 7435 * Ensures that top-level event delegation listeners are installed. 7436 * 7437 * There are issues with listening to both touch events and mouse events on 7438 * the top-level, so we make the caller choose which one to listen to. (If 7439 * there's a touch top-level listeners, anchors don't receive clicks for some 7440 * reason, and only in some cases). 7441 * 7442 * @param {boolean} touchNotMouse Listen to touch events instead of mouse. 7443 * @param {DOMDocument} contentDocument DOM document to listen on 7444 */ 7445 ensureListening: function(touchNotMouse, contentDocument) { 7446 ("production" !== "development" ? invariant( 7447 ExecutionEnvironment.canUseDOM, 7448 'ensureListening(...): Cannot toggle event listening in a Worker ' + 7449 'thread. This is likely a bug in the framework. Please report ' + 7450 'immediately.' 7451 ) : invariant(ExecutionEnvironment.canUseDOM)); 7452 ("production" !== "development" ? invariant( 7453 ReactEventEmitter.TopLevelCallbackCreator, 7454 'ensureListening(...): Cannot be called without a top level callback ' + 7455 'creator being injected.' 7456 ) : invariant(ReactEventEmitter.TopLevelCallbackCreator)); 7457 // Call out to base implementation. 7458 ReactEventEmitterMixin.ensureListening.call( 7459 ReactEventEmitter, 7460 { 7461 touchNotMouse: touchNotMouse, 7462 contentDocument: contentDocument 7463 } 7464 ); 7465 }, 7466 7467 /** 7468 * Sets whether or not any created callbacks should be enabled. 7469 * 7470 * @param {boolean} enabled True if callbacks should be enabled. 7471 */ 7472 setEnabled: function(enabled) { 7473 ("production" !== "development" ? invariant( 7474 ExecutionEnvironment.canUseDOM, 7475 'setEnabled(...): Cannot toggle event listening in a Worker thread. ' + 7476 'This is likely a bug in the framework. Please report immediately.' 7477 ) : invariant(ExecutionEnvironment.canUseDOM)); 7478 if (ReactEventEmitter.TopLevelCallbackCreator) { 7479 ReactEventEmitter.TopLevelCallbackCreator.setEnabled(enabled); 7480 } 7481 }, 7482 7483 /** 7484 * @return {boolean} True if callbacks are enabled. 7485 */ 7486 isEnabled: function() { 7487 return !!( 7488 ReactEventEmitter.TopLevelCallbackCreator && 7489 ReactEventEmitter.TopLevelCallbackCreator.isEnabled() 7490 ); 7491 }, 7492 7493 /** 7494 * We listen for bubbled touch events on the document object. 7495 * 7496 * Firefox v8.01 (and possibly others) exhibited strange behavior when 7497 * mounting `onmousemove` events at some node that was not the document 7498 * element. The symptoms were that if your mouse is not moving over something 7499 * contained within that mount point (for example on the background) the 7500 * top-level listeners for `onmousemove` won't be called. However, if you 7501 * register the `mousemove` on the document object, then it will of course 7502 * catch all `mousemove`s. This along with iOS quirks, justifies restricting 7503 * top-level listeners to the document object only, at least for these 7504 * movement types of events and possibly all events. 7505 * 7506 * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html 7507 * 7508 * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but 7509 * they bubble to document. 7510 * 7511 * @param {boolean} touchNotMouse Listen to touch events instead of mouse. 7512 * @param {DOMDocument} contentDocument Document which owns the container 7513 * @private 7514 * @see http://www.quirksmode.org/dom/events/keys.html. 7515 */ 7516 listenAtTopLevel: function(touchNotMouse, contentDocument) { 7517 ("production" !== "development" ? invariant( 7518 !contentDocument._isListening, 7519 'listenAtTopLevel(...): Cannot setup top-level listener more than once.' 7520 ) : invariant(!contentDocument._isListening)); 7521 var topLevelTypes = EventConstants.topLevelTypes; 7522 var mountAt = contentDocument; 7523 7524 registerScrollValueMonitoring(); 7525 trapBubbledEvent(topLevelTypes.topMouseOver, 'mouseover', mountAt); 7526 trapBubbledEvent(topLevelTypes.topMouseDown, 'mousedown', mountAt); 7527 trapBubbledEvent(topLevelTypes.topMouseUp, 'mouseup', mountAt); 7528 trapBubbledEvent(topLevelTypes.topMouseMove, 'mousemove', mountAt); 7529 trapBubbledEvent(topLevelTypes.topMouseOut, 'mouseout', mountAt); 7530 trapBubbledEvent(topLevelTypes.topClick, 'click', mountAt); 7531 trapBubbledEvent(topLevelTypes.topDoubleClick, 'dblclick', mountAt); 7532 trapBubbledEvent(topLevelTypes.topContextMenu, 'contextmenu', mountAt); 7533 if (touchNotMouse) { 7534 trapBubbledEvent(topLevelTypes.topTouchStart, 'touchstart', mountAt); 7535 trapBubbledEvent(topLevelTypes.topTouchEnd, 'touchend', mountAt); 7536 trapBubbledEvent(topLevelTypes.topTouchMove, 'touchmove', mountAt); 7537 trapBubbledEvent(topLevelTypes.topTouchCancel, 'touchcancel', mountAt); 7538 } 7539 trapBubbledEvent(topLevelTypes.topKeyUp, 'keyup', mountAt); 7540 trapBubbledEvent(topLevelTypes.topKeyPress, 'keypress', mountAt); 7541 trapBubbledEvent(topLevelTypes.topKeyDown, 'keydown', mountAt); 7542 trapBubbledEvent(topLevelTypes.topInput, 'input', mountAt); 7543 trapBubbledEvent(topLevelTypes.topChange, 'change', mountAt); 7544 trapBubbledEvent( 7545 topLevelTypes.topSelectionChange, 7546 'selectionchange', 7547 mountAt 7548 ); 7549 7550 trapBubbledEvent( 7551 topLevelTypes.topCompositionEnd, 7552 'compositionend', 7553 mountAt 7554 ); 7555 trapBubbledEvent( 7556 topLevelTypes.topCompositionStart, 7557 'compositionstart', 7558 mountAt 7559 ); 7560 trapBubbledEvent( 7561 topLevelTypes.topCompositionUpdate, 7562 'compositionupdate', 7563 mountAt 7564 ); 7565 7566 if (isEventSupported('drag')) { 7567 trapBubbledEvent(topLevelTypes.topDrag, 'drag', mountAt); 7568 trapBubbledEvent(topLevelTypes.topDragEnd, 'dragend', mountAt); 7569 trapBubbledEvent(topLevelTypes.topDragEnter, 'dragenter', mountAt); 7570 trapBubbledEvent(topLevelTypes.topDragExit, 'dragexit', mountAt); 7571 trapBubbledEvent(topLevelTypes.topDragLeave, 'dragleave', mountAt); 7572 trapBubbledEvent(topLevelTypes.topDragOver, 'dragover', mountAt); 7573 trapBubbledEvent(topLevelTypes.topDragStart, 'dragstart', mountAt); 7574 trapBubbledEvent(topLevelTypes.topDrop, 'drop', mountAt); 7575 } 7576 7577 if (isEventSupported('wheel')) { 7578 trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt); 7579 } else if (isEventSupported('mousewheel')) { 7580 trapBubbledEvent(topLevelTypes.topWheel, 'mousewheel', mountAt); 7581 } else { 7582 // Firefox needs to capture a different mouse scroll event. 7583 // @see http://www.quirksmode.org/dom/events/tests/scroll.html 7584 trapBubbledEvent(topLevelTypes.topWheel, 'DOMMouseScroll', mountAt); 7585 } 7586 7587 // IE<9 does not support capturing so just trap the bubbled event there. 7588 if (isEventSupported('scroll', true)) { 7589 trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt); 7590 } else { 7591 trapBubbledEvent(topLevelTypes.topScroll, 'scroll', window); 7592 } 7593 7594 if (isEventSupported('focus', true)) { 7595 trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt); 7596 trapCapturedEvent(topLevelTypes.topBlur, 'blur', mountAt); 7597 } else if (isEventSupported('focusin')) { 7598 // IE has `focusin` and `focusout` events which bubble. 7599 // @see 7600 // http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html 7601 trapBubbledEvent(topLevelTypes.topFocus, 'focusin', mountAt); 7602 trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt); 7603 } 7604 7605 if (isEventSupported('copy')) { 7606 trapBubbledEvent(topLevelTypes.topCopy, 'copy', mountAt); 7607 trapBubbledEvent(topLevelTypes.topCut, 'cut', mountAt); 7608 trapBubbledEvent(topLevelTypes.topPaste, 'paste', mountAt); 7609 } 7610 }, 7611 7612 registrationNames: EventPluginHub.registrationNames, 7613 7614 putListener: EventPluginHub.putListener, 7615 7616 getListener: EventPluginHub.getListener, 7617 7618 deleteListener: EventPluginHub.deleteListener, 7619 7620 deleteAllListeners: EventPluginHub.deleteAllListeners, 7621 7622 trapBubbledEvent: trapBubbledEvent, 7623 7624 trapCapturedEvent: trapCapturedEvent 7625 7626 }); 7627 7628 7629 module.exports = ReactEventEmitter; 7630 7631 },{"./EventConstants":14,"./EventListener":15,"./EventPluginHub":16,"./ExecutionEnvironment":20,"./ReactEventEmitterMixin":45,"./ViewportMetrics":74,"./invariant":98,"./isEventSupported":99,"./merge":107}],45:[function(require,module,exports){ 7632 /** 7633 * Copyright 2013 Facebook, Inc. 7634 * 7635 * Licensed under the Apache License, Version 2.0 (the "License"); 7636 * you may not use this file except in compliance with the License. 7637 * You may obtain a copy of the License at 7638 * 7639 * http://www.apache.org/licenses/LICENSE-2.0 7640 * 7641 * Unless required by applicable law or agreed to in writing, software 7642 * distributed under the License is distributed on an "AS IS" BASIS, 7643 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7644 * See the License for the specific language governing permissions and 7645 * limitations under the License. 7646 * 7647 * @providesModule ReactEventEmitterMixin 7648 */ 7649 7650 "use strict"; 7651 7652 var EventPluginHub = require("./EventPluginHub"); 7653 var ReactUpdates = require("./ReactUpdates"); 7654 7655 function runEventQueueInBatch(events) { 7656 EventPluginHub.enqueueEvents(events); 7657 EventPluginHub.processEventQueue(); 7658 } 7659 7660 var ReactEventEmitterMixin = { 7661 /** 7662 * Whether or not `ensureListening` has been invoked. 7663 * @type {boolean} 7664 * @private 7665 */ 7666 _isListening: false, 7667 7668 /** 7669 * Function, must be implemented. Listens to events on the top level of the 7670 * application. 7671 * 7672 * @abstract 7673 * 7674 * listenAtTopLevel: null, 7675 */ 7676 7677 /** 7678 * Ensures that top-level event delegation listeners are installed. 7679 * 7680 * There are issues with listening to both touch events and mouse events on 7681 * the top-level, so we make the caller choose which one to listen to. (If 7682 * there's a touch top-level listeners, anchors don't receive clicks for some 7683 * reason, and only in some cases). 7684 * 7685 * @param {*} config Configuration passed through to `listenAtTopLevel`. 7686 */ 7687 ensureListening: function(config) { 7688 if (!config.contentDocument._reactIsListening) { 7689 this.listenAtTopLevel(config.touchNotMouse, config.contentDocument); 7690 config.contentDocument._reactIsListening = true; 7691 } 7692 }, 7693 7694 /** 7695 * Streams a fired top-level event to `EventPluginHub` where plugins have the 7696 * opportunity to create `ReactEvent`s to be dispatched. 7697 * 7698 * @param {string} topLevelType Record from `EventConstants`. 7699 * @param {object} topLevelTarget The listening component root node. 7700 * @param {string} topLevelTargetID ID of `topLevelTarget`. 7701 * @param {object} nativeEvent Native environment event. 7702 */ 7703 handleTopLevel: function( 7704 topLevelType, 7705 topLevelTarget, 7706 topLevelTargetID, 7707 nativeEvent) { 7708 var events = EventPluginHub.extractEvents( 7709 topLevelType, 7710 topLevelTarget, 7711 topLevelTargetID, 7712 nativeEvent 7713 ); 7714 7715 // Event queue being processed in the same cycle allows `preventDefault`. 7716 ReactUpdates.batchedUpdates(runEventQueueInBatch, events); 7717 } 7718 }; 7719 7720 module.exports = ReactEventEmitterMixin; 7721 7722 },{"./EventPluginHub":16,"./ReactUpdates":61}],46:[function(require,module,exports){ 7723 /** 7724 * Copyright 2013 Facebook, Inc. 7725 * 7726 * Licensed under the Apache License, Version 2.0 (the "License"); 7727 * you may not use this file except in compliance with the License. 7728 * You may obtain a copy of the License at 7729 * 7730 * http://www.apache.org/licenses/LICENSE-2.0 7731 * 7732 * Unless required by applicable law or agreed to in writing, software 7733 * distributed under the License is distributed on an "AS IS" BASIS, 7734 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7735 * See the License for the specific language governing permissions and 7736 * limitations under the License. 7737 * 7738 * @providesModule ReactEventTopLevelCallback 7739 * @typechecks static-only 7740 */ 7741 7742 "use strict"; 7743 7744 var ReactEventEmitter = require("./ReactEventEmitter"); 7745 var ReactMount = require("./ReactMount"); 7746 7747 var getEventTarget = require("./getEventTarget"); 7748 7749 /** 7750 * @type {boolean} 7751 * @private 7752 */ 7753 var _topLevelListenersEnabled = true; 7754 7755 /** 7756 * Top-level callback creator used to implement event handling using delegation. 7757 * This is used via dependency injection. 7758 */ 7759 var ReactEventTopLevelCallback = { 7760 7761 /** 7762 * Sets whether or not any created callbacks should be enabled. 7763 * 7764 * @param {boolean} enabled True if callbacks should be enabled. 7765 */ 7766 setEnabled: function(enabled) { 7767 _topLevelListenersEnabled = !!enabled; 7768 }, 7769 7770 /** 7771 * @return {boolean} True if callbacks are enabled. 7772 */ 7773 isEnabled: function() { 7774 return _topLevelListenersEnabled; 7775 }, 7776 7777 /** 7778 * Creates a callback for the supplied `topLevelType` that could be added as 7779 * a listener to the document. The callback computes a `topLevelTarget` which 7780 * should be the root node of a mounted React component where the listener 7781 * is attached. 7782 * 7783 * @param {string} topLevelType Record from `EventConstants`. 7784 * @return {function} Callback for handling top-level events. 7785 */ 7786 createTopLevelCallback: function(topLevelType) { 7787 return function(nativeEvent) { 7788 if (!_topLevelListenersEnabled) { 7789 return; 7790 } 7791 // TODO: Remove when synthetic events are ready, this is for IE<9. 7792 if (nativeEvent.srcElement && 7793 nativeEvent.srcElement !== nativeEvent.target) { 7794 nativeEvent.target = nativeEvent.srcElement; 7795 } 7796 var topLevelTarget = ReactMount.getFirstReactDOM( 7797 getEventTarget(nativeEvent) 7798 ) || window; 7799 var topLevelTargetID = ReactMount.getID(topLevelTarget) || ''; 7800 ReactEventEmitter.handleTopLevel( 7801 topLevelType, 7802 topLevelTarget, 7803 topLevelTargetID, 7804 nativeEvent 7805 ); 7806 }; 7807 } 7808 7809 }; 7810 7811 module.exports = ReactEventTopLevelCallback; 7812 7813 },{"./ReactEventEmitter":44,"./ReactMount":50,"./getEventTarget":91}],47:[function(require,module,exports){ 7814 /** 7815 * Copyright 2013 Facebook, Inc. 7816 * 7817 * Licensed under the Apache License, Version 2.0 (the "License"); 7818 * you may not use this file except in compliance with the License. 7819 * You may obtain a copy of the License at 7820 * 7821 * http://www.apache.org/licenses/LICENSE-2.0 7822 * 7823 * Unless required by applicable law or agreed to in writing, software 7824 * distributed under the License is distributed on an "AS IS" BASIS, 7825 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7826 * See the License for the specific language governing permissions and 7827 * limitations under the License. 7828 * 7829 * @providesModule ReactInputSelection 7830 */ 7831 7832 "use strict"; 7833 7834 var ReactDOMSelection = require("./ReactDOMSelection"); 7835 7836 var containsNode = require("./containsNode"); 7837 var getActiveElement = require("./getActiveElement"); 7838 7839 function isInDocument(node) { 7840 return containsNode(document.documentElement, node); 7841 } 7842 7843 /** 7844 * @ReactInputSelection: React input selection module. Based on Selection.js, 7845 * but modified to be suitable for react and has a couple of bug fixes (doesn't 7846 * assume buttons have range selections allowed). 7847 * Input selection module for React. 7848 */ 7849 var ReactInputSelection = { 7850 7851 hasSelectionCapabilities: function(elem) { 7852 return elem && ( 7853 (elem.nodeName === 'INPUT' && elem.type === 'text') || 7854 elem.nodeName === 'TEXTAREA' || 7855 elem.contentEditable === 'true' 7856 ); 7857 }, 7858 7859 getSelectionInformation: function() { 7860 var focusedElem = getActiveElement(); 7861 return { 7862 focusedElem: focusedElem, 7863 selectionRange: 7864 ReactInputSelection.hasSelectionCapabilities(focusedElem) ? 7865 ReactInputSelection.getSelection(focusedElem) : 7866 null 7867 }; 7868 }, 7869 7870 /** 7871 * @restoreSelection: If any selection information was potentially lost, 7872 * restore it. This is useful when performing operations that could remove dom 7873 * nodes and place them back in, resulting in focus being lost. 7874 */ 7875 restoreSelection: function(priorSelectionInformation) { 7876 var curFocusedElem = getActiveElement(); 7877 var priorFocusedElem = priorSelectionInformation.focusedElem; 7878 var priorSelectionRange = priorSelectionInformation.selectionRange; 7879 if (curFocusedElem !== priorFocusedElem && 7880 isInDocument(priorFocusedElem)) { 7881 if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) { 7882 ReactInputSelection.setSelection( 7883 priorFocusedElem, 7884 priorSelectionRange 7885 ); 7886 } 7887 priorFocusedElem.focus(); 7888 } 7889 }, 7890 7891 /** 7892 * @getSelection: Gets the selection bounds of a focused textarea, input or 7893 * contentEditable node. 7894 * -@input: Look up selection bounds of this input 7895 * -@return {start: selectionStart, end: selectionEnd} 7896 */ 7897 getSelection: function(input) { 7898 var selection; 7899 7900 if ('selectionStart' in input) { 7901 // Modern browser with input or textarea. 7902 selection = { 7903 start: input.selectionStart, 7904 end: input.selectionEnd 7905 }; 7906 } else if (document.selection && input.nodeName === 'INPUT') { 7907 // IE8 input. 7908 var range = document.selection.createRange(); 7909 // There can only be one selection per document in IE, so it must 7910 // be in our element. 7911 if (range.parentElement() === input) { 7912 selection = { 7913 start: -range.moveStart('character', -input.value.length), 7914 end: -range.moveEnd('character', -input.value.length) 7915 }; 7916 } 7917 } else { 7918 // Content editable or old IE textarea. 7919 selection = ReactDOMSelection.getOffsets(input); 7920 } 7921 7922 return selection || {start: 0, end: 0}; 7923 }, 7924 7925 /** 7926 * @setSelection: Sets the selection bounds of a textarea or input and focuses 7927 * the input. 7928 * -@input Set selection bounds of this input or textarea 7929 * -@offsets Object of same form that is returned from get* 7930 */ 7931 setSelection: function(input, offsets) { 7932 var start = offsets.start; 7933 var end = offsets.end; 7934 if (typeof end === 'undefined') { 7935 end = start; 7936 } 7937 7938 if ('selectionStart' in input) { 7939 input.selectionStart = start; 7940 input.selectionEnd = Math.min(end, input.value.length); 7941 } else if (document.selection && input.nodeName === 'INPUT') { 7942 var range = input.createTextRange(); 7943 range.collapse(true); 7944 range.moveStart('character', start); 7945 range.moveEnd('character', end - start); 7946 range.select(); 7947 } else { 7948 ReactDOMSelection.setOffsets(input, offsets); 7949 } 7950 } 7951 }; 7952 7953 module.exports = ReactInputSelection; 7954 7955 },{"./ReactDOMSelection":38,"./containsNode":77,"./getActiveElement":90}],48:[function(require,module,exports){ 7956 /** 7957 * Copyright 2013 Facebook, Inc. 7958 * 7959 * Licensed under the Apache License, Version 2.0 (the "License"); 7960 * you may not use this file except in compliance with the License. 7961 * You may obtain a copy of the License at 7962 * 7963 * http://www.apache.org/licenses/LICENSE-2.0 7964 * 7965 * Unless required by applicable law or agreed to in writing, software 7966 * distributed under the License is distributed on an "AS IS" BASIS, 7967 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7968 * See the License for the specific language governing permissions and 7969 * limitations under the License. 7970 * 7971 * @providesModule ReactInstanceHandles 7972 * @typechecks static-only 7973 */ 7974 7975 "use strict"; 7976 7977 var invariant = require("./invariant"); 7978 7979 var SEPARATOR = '.'; 7980 var SEPARATOR_LENGTH = SEPARATOR.length; 7981 7982 /** 7983 * Maximum depth of traversals before we consider the possibility of a bad ID. 7984 */ 7985 var MAX_TREE_DEPTH = 100; 7986 7987 /** 7988 * Size of the reactRoot ID space. We generate random numbers for React root 7989 * IDs and if there's a collision the events and DOM update system will 7990 * get confused. If we assume 100 React components per page, and a user 7991 * loads 1 page per minute 24/7 for 50 years, with a mount point space of 7992 * 9,999,999 the likelihood of never having a collision is 99.997%. 7993 */ 7994 var GLOBAL_MOUNT_POINT_MAX = 9999999; 7995 7996 /** 7997 * Creates a DOM ID prefix to use when mounting React components. 7998 * 7999 * @param {number} index A unique integer 8000 * @return {string} React root ID. 8001 * @internal 8002 */ 8003 function getReactRootIDString(index) { 8004 return SEPARATOR + 'r[' + index.toString(36) + ']'; 8005 } 8006 8007 /** 8008 * Checks if a character in the supplied ID is a separator or the end. 8009 * 8010 * @param {string} id A React DOM ID. 8011 * @param {number} index Index of the character to check. 8012 * @return {boolean} True if the character is a separator or end of the ID. 8013 * @private 8014 */ 8015 function isBoundary(id, index) { 8016 return id.charAt(index) === SEPARATOR || index === id.length; 8017 } 8018 8019 /** 8020 * Checks if the supplied string is a valid React DOM ID. 8021 * 8022 * @param {string} id A React DOM ID, maybe. 8023 * @return {boolean} True if the string is a valid React DOM ID. 8024 * @private 8025 */ 8026 function isValidID(id) { 8027 return id === '' || ( 8028 id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR 8029 ); 8030 } 8031 8032 /** 8033 * Checks if the first ID is an ancestor of or equal to the second ID. 8034 * 8035 * @param {string} ancestorID 8036 * @param {string} descendantID 8037 * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`. 8038 * @internal 8039 */ 8040 function isAncestorIDOf(ancestorID, descendantID) { 8041 return ( 8042 descendantID.indexOf(ancestorID) === 0 && 8043 isBoundary(descendantID, ancestorID.length) 8044 ); 8045 } 8046 8047 /** 8048 * Gets the parent ID of the supplied React DOM ID, `id`. 8049 * 8050 * @param {string} id ID of a component. 8051 * @return {string} ID of the parent, or an empty string. 8052 * @private 8053 */ 8054 function getParentID(id) { 8055 return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : ''; 8056 } 8057 8058 /** 8059 * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the 8060 * supplied `destinationID`. If they are equal, the ID is returned. 8061 * 8062 * @param {string} ancestorID ID of an ancestor node of `destinationID`. 8063 * @param {string} destinationID ID of the destination node. 8064 * @return {string} Next ID on the path from `ancestorID` to `destinationID`. 8065 * @private 8066 */ 8067 function getNextDescendantID(ancestorID, destinationID) { 8068 ("production" !== "development" ? invariant( 8069 isValidID(ancestorID) && isValidID(destinationID), 8070 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.', 8071 ancestorID, 8072 destinationID 8073 ) : invariant(isValidID(ancestorID) && isValidID(destinationID))); 8074 ("production" !== "development" ? invariant( 8075 isAncestorIDOf(ancestorID, destinationID), 8076 'getNextDescendantID(...): React has made an invalid assumption about ' + 8077 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.', 8078 ancestorID, 8079 destinationID 8080 ) : invariant(isAncestorIDOf(ancestorID, destinationID))); 8081 if (ancestorID === destinationID) { 8082 return ancestorID; 8083 } 8084 // Skip over the ancestor and the immediate separator. Traverse until we hit 8085 // another separator or we reach the end of `destinationID`. 8086 var start = ancestorID.length + SEPARATOR_LENGTH; 8087 for (var i = start; i < destinationID.length; i++) { 8088 if (isBoundary(destinationID, i)) { 8089 break; 8090 } 8091 } 8092 return destinationID.substr(0, i); 8093 } 8094 8095 /** 8096 * Gets the nearest common ancestor ID of two IDs. 8097 * 8098 * Using this ID scheme, the nearest common ancestor ID is the longest common 8099 * prefix of the two IDs that immediately preceded a "marker" in both strings. 8100 * 8101 * @param {string} oneID 8102 * @param {string} twoID 8103 * @return {string} Nearest common ancestor ID, or the empty string if none. 8104 * @private 8105 */ 8106 function getFirstCommonAncestorID(oneID, twoID) { 8107 var minLength = Math.min(oneID.length, twoID.length); 8108 if (minLength === 0) { 8109 return ''; 8110 } 8111 var lastCommonMarkerIndex = 0; 8112 // Use `<=` to traverse until the "EOL" of the shorter string. 8113 for (var i = 0; i <= minLength; i++) { 8114 if (isBoundary(oneID, i) && isBoundary(twoID, i)) { 8115 lastCommonMarkerIndex = i; 8116 } else if (oneID.charAt(i) !== twoID.charAt(i)) { 8117 break; 8118 } 8119 } 8120 var longestCommonID = oneID.substr(0, lastCommonMarkerIndex); 8121 ("production" !== "development" ? invariant( 8122 isValidID(longestCommonID), 8123 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s', 8124 oneID, 8125 twoID, 8126 longestCommonID 8127 ) : invariant(isValidID(longestCommonID))); 8128 return longestCommonID; 8129 } 8130 8131 /** 8132 * Traverses the parent path between two IDs (either up or down). The IDs must 8133 * not be the same, and there must exist a parent path between them. 8134 * 8135 * @param {?string} start ID at which to start traversal. 8136 * @param {?string} stop ID at which to end traversal. 8137 * @param {function} cb Callback to invoke each ID with. 8138 * @param {?boolean} skipFirst Whether or not to skip the first node. 8139 * @param {?boolean} skipLast Whether or not to skip the last node. 8140 * @private 8141 */ 8142 function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) { 8143 start = start || ''; 8144 stop = stop || ''; 8145 ("production" !== "development" ? invariant( 8146 start !== stop, 8147 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.', 8148 start 8149 ) : invariant(start !== stop)); 8150 var traverseUp = isAncestorIDOf(stop, start); 8151 ("production" !== "development" ? invariant( 8152 traverseUp || isAncestorIDOf(start, stop), 8153 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' + 8154 'not have a parent path.', 8155 start, 8156 stop 8157 ) : invariant(traverseUp || isAncestorIDOf(start, stop))); 8158 // Traverse from `start` to `stop` one depth at a time. 8159 var depth = 0; 8160 var traverse = traverseUp ? getParentID : getNextDescendantID; 8161 for (var id = start; /* until break */; id = traverse(id, stop)) { 8162 if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) { 8163 cb(id, traverseUp, arg); 8164 } 8165 if (id === stop) { 8166 // Only break //after// visiting `stop`. 8167 break; 8168 } 8169 ("production" !== "development" ? invariant( 8170 depth++ < MAX_TREE_DEPTH, 8171 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' + 8172 'traversing the React DOM ID tree. This may be due to malformed IDs: %s', 8173 start, stop 8174 ) : invariant(depth++ < MAX_TREE_DEPTH)); 8175 } 8176 } 8177 8178 /** 8179 * Manages the IDs assigned to DOM representations of React components. This 8180 * uses a specific scheme in order to traverse the DOM efficiently (e.g. in 8181 * order to simulate events). 8182 * 8183 * @internal 8184 */ 8185 var ReactInstanceHandles = { 8186 8187 createReactRootID: function() { 8188 return getReactRootIDString( 8189 Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX) 8190 ); 8191 }, 8192 8193 /** 8194 * Constructs a React ID by joining a root ID with a name. 8195 * 8196 * @param {string} rootID Root ID of a parent component. 8197 * @param {string} name A component's name (as flattened children). 8198 * @return {string} A React ID. 8199 * @internal 8200 */ 8201 createReactID: function(rootID, name) { 8202 return rootID + SEPARATOR + name; 8203 }, 8204 8205 /** 8206 * Gets the DOM ID of the React component that is the root of the tree that 8207 * contains the React component with the supplied DOM ID. 8208 * 8209 * @param {string} id DOM ID of a React component. 8210 * @return {?string} DOM ID of the React component that is the root. 8211 * @internal 8212 */ 8213 getReactRootIDFromNodeID: function(id) { 8214 var regexResult = /\.r\[[^\]]+\]/.exec(id); 8215 return regexResult && regexResult[0]; 8216 }, 8217 8218 /** 8219 * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that 8220 * should would receive a `mouseEnter` or `mouseLeave` event. 8221 * 8222 * NOTE: Does not invoke the callback on the nearest common ancestor because 8223 * nothing "entered" or "left" that element. 8224 * 8225 * @param {string} leaveID ID being left. 8226 * @param {string} enterID ID being entered. 8227 * @param {function} cb Callback to invoke on each entered/left ID. 8228 * @param {*} upArg Argument to invoke the callback with on left IDs. 8229 * @param {*} downArg Argument to invoke the callback with on entered IDs. 8230 * @internal 8231 */ 8232 traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) { 8233 var ancestorID = getFirstCommonAncestorID(leaveID, enterID); 8234 if (ancestorID !== leaveID) { 8235 traverseParentPath(leaveID, ancestorID, cb, upArg, false, true); 8236 } 8237 if (ancestorID !== enterID) { 8238 traverseParentPath(ancestorID, enterID, cb, downArg, true, false); 8239 } 8240 }, 8241 8242 /** 8243 * Simulates the traversal of a two-phase, capture/bubble event dispatch. 8244 * 8245 * NOTE: This traversal happens on IDs without touching the DOM. 8246 * 8247 * @param {string} targetID ID of the target node. 8248 * @param {function} cb Callback to invoke. 8249 * @param {*} arg Argument to invoke the callback with. 8250 * @internal 8251 */ 8252 traverseTwoPhase: function(targetID, cb, arg) { 8253 if (targetID) { 8254 traverseParentPath('', targetID, cb, arg, true, false); 8255 traverseParentPath(targetID, '', cb, arg, false, true); 8256 } 8257 }, 8258 8259 /** 8260 * Exposed for unit testing. 8261 * @private 8262 */ 8263 _getFirstCommonAncestorID: getFirstCommonAncestorID, 8264 8265 /** 8266 * Exposed for unit testing. 8267 * @private 8268 */ 8269 _getNextDescendantID: getNextDescendantID, 8270 8271 isAncestorIDOf: isAncestorIDOf, 8272 8273 SEPARATOR: SEPARATOR 8274 8275 }; 8276 8277 module.exports = ReactInstanceHandles; 8278 8279 },{"./invariant":98}],49:[function(require,module,exports){ 8280 /** 8281 * Copyright 2013 Facebook, Inc. 8282 * 8283 * Licensed under the Apache License, Version 2.0 (the "License"); 8284 * you may not use this file except in compliance with the License. 8285 * You may obtain a copy of the License at 8286 * 8287 * http://www.apache.org/licenses/LICENSE-2.0 8288 * 8289 * Unless required by applicable law or agreed to in writing, software 8290 * distributed under the License is distributed on an "AS IS" BASIS, 8291 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8292 * See the License for the specific language governing permissions and 8293 * limitations under the License. 8294 * 8295 * @providesModule ReactMarkupChecksum 8296 */ 8297 8298 "use strict"; 8299 8300 var adler32 = require("./adler32"); 8301 8302 var ReactMarkupChecksum = { 8303 CHECKSUM_ATTR_NAME: 'data-react-checksum', 8304 8305 /** 8306 * @param {string} markup Markup string 8307 * @return {string} Markup string with checksum attribute attached 8308 */ 8309 addChecksumToMarkup: function(markup) { 8310 var checksum = adler32(markup); 8311 return markup.replace( 8312 '>', 8313 ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">' 8314 ); 8315 }, 8316 8317 /** 8318 * @param {string} markup to use 8319 * @param {DOMElement} element root React element 8320 * @returns {boolean} whether or not the markup is the same 8321 */ 8322 canReuseMarkup: function(markup, element) { 8323 var existingChecksum = element.getAttribute( 8324 ReactMarkupChecksum.CHECKSUM_ATTR_NAME 8325 ); 8326 existingChecksum = existingChecksum && parseInt(existingChecksum, 10); 8327 var markupChecksum = adler32(markup); 8328 return markupChecksum === existingChecksum; 8329 } 8330 }; 8331 8332 module.exports = ReactMarkupChecksum; 8333 8334 },{"./adler32":76}],50:[function(require,module,exports){ 8335 /** 8336 * Copyright 2013 Facebook, Inc. 8337 * 8338 * Licensed under the Apache License, Version 2.0 (the "License"); 8339 * you may not use this file except in compliance with the License. 8340 * You may obtain a copy of the License at 8341 * 8342 * http://www.apache.org/licenses/LICENSE-2.0 8343 * 8344 * Unless required by applicable law or agreed to in writing, software 8345 * distributed under the License is distributed on an "AS IS" BASIS, 8346 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8347 * See the License for the specific language governing permissions and 8348 * limitations under the License. 8349 * 8350 * @providesModule ReactMount 8351 */ 8352 8353 "use strict"; 8354 8355 var ReactEventEmitter = require("./ReactEventEmitter"); 8356 var ReactInstanceHandles = require("./ReactInstanceHandles"); 8357 8358 var $ = require("./$"); 8359 var containsNode = require("./containsNode"); 8360 var getReactRootElementInContainer = require("./getReactRootElementInContainer"); 8361 var invariant = require("./invariant"); 8362 8363 var SEPARATOR = ReactInstanceHandles.SEPARATOR; 8364 8365 var ATTR_NAME = 'data-reactid'; 8366 var nodeCache = {}; 8367 8368 var ELEMENT_NODE_TYPE = 1; 8369 var DOC_NODE_TYPE = 9; 8370 8371 /** Mapping from reactRootID to React component instance. */ 8372 var instancesByReactRootID = {}; 8373 8374 /** Mapping from reactRootID to `container` nodes. */ 8375 var containersByReactRootID = {}; 8376 8377 if ("production" !== "development") { 8378 /** __DEV__-only mapping from reactRootID to root elements. */ 8379 var rootElementsByReactRootID = {}; 8380 } 8381 8382 /** 8383 * @param {DOMElement} container DOM element that may contain a React component. 8384 * @return {?string} A "reactRoot" ID, if a React component is rendered. 8385 */ 8386 function getReactRootID(container) { 8387 var rootElement = getReactRootElementInContainer(container); 8388 return rootElement && ReactMount.getID(rootElement); 8389 } 8390 8391 /** 8392 * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form 8393 * element can return its control whose name or ID equals ATTR_NAME. All 8394 * DOM nodes support `getAttributeNode` but this can also get called on 8395 * other objects so just return '' if we're given something other than a 8396 * DOM node (such as window). 8397 * 8398 * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node. 8399 * @return {string} ID of the supplied `domNode`. 8400 */ 8401 function getID(node) { 8402 var id = internalGetID(node); 8403 if (id) { 8404 if (nodeCache.hasOwnProperty(id)) { 8405 var cached = nodeCache[id]; 8406 if (cached !== node) { 8407 ("production" !== "development" ? invariant( 8408 !isValid(cached, id), 8409 'ReactMount: Two valid but unequal nodes with the same `%s`: %s', 8410 ATTR_NAME, id 8411 ) : invariant(!isValid(cached, id))); 8412 8413 nodeCache[id] = node; 8414 } 8415 } else { 8416 nodeCache[id] = node; 8417 } 8418 } 8419 8420 return id; 8421 } 8422 8423 function internalGetID(node) { 8424 // If node is something like a window, document, or text node, none of 8425 // which support attributes or a .getAttribute method, gracefully return 8426 // the empty string, as if the attribute were missing. 8427 return node && node.getAttribute && node.getAttribute(ATTR_NAME) || ''; 8428 } 8429 8430 /** 8431 * Sets the React-specific ID of the given node. 8432 * 8433 * @param {DOMElement} node The DOM node whose ID will be set. 8434 * @param {string} id The value of the ID attribute. 8435 */ 8436 function setID(node, id) { 8437 var oldID = internalGetID(node); 8438 if (oldID !== id) { 8439 delete nodeCache[oldID]; 8440 } 8441 node.setAttribute(ATTR_NAME, id); 8442 nodeCache[id] = node; 8443 } 8444 8445 /** 8446 * Finds the node with the supplied React-generated DOM ID. 8447 * 8448 * @param {string} id A React-generated DOM ID. 8449 * @return {DOMElement} DOM node with the suppled `id`. 8450 * @internal 8451 */ 8452 function getNode(id) { 8453 if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) { 8454 nodeCache[id] = ReactMount.findReactNodeByID(id); 8455 } 8456 return nodeCache[id]; 8457 } 8458 8459 /** 8460 * A node is "valid" if it is contained by a currently mounted container. 8461 * 8462 * This means that the node does not have to be contained by a document in 8463 * order to be considered valid. 8464 * 8465 * @param {?DOMElement} node The candidate DOM node. 8466 * @param {string} id The expected ID of the node. 8467 * @return {boolean} Whether the node is contained by a mounted container. 8468 */ 8469 function isValid(node, id) { 8470 if (node) { 8471 ("production" !== "development" ? invariant( 8472 internalGetID(node) === id, 8473 'ReactMount: Unexpected modification of `%s`', 8474 ATTR_NAME 8475 ) : invariant(internalGetID(node) === id)); 8476 8477 var container = ReactMount.findReactContainerForID(id); 8478 if (container && containsNode(container, node)) { 8479 return true; 8480 } 8481 } 8482 8483 return false; 8484 } 8485 8486 /** 8487 * Causes the cache to forget about one React-specific ID. 8488 * 8489 * @param {string} id The ID to forget. 8490 */ 8491 function purgeID(id) { 8492 delete nodeCache[id]; 8493 } 8494 8495 /** 8496 * Mounting is the process of initializing a React component by creatings its 8497 * representative DOM elements and inserting them into a supplied `container`. 8498 * Any prior content inside `container` is destroyed in the process. 8499 * 8500 * ReactMount.renderComponent(component, $('container')); 8501 * 8502 * <div id="container"> <-- Supplied `container`. 8503 * <div data-reactid=".r[3]"> <-- Rendered reactRoot of React 8504 * // ... component. 8505 * </div> 8506 * </div> 8507 * 8508 * Inside of `container`, the first element rendered is the "reactRoot". 8509 */ 8510 var ReactMount = { 8511 /** 8512 * Safety guard to prevent accidentally rendering over the entire HTML tree. 8513 */ 8514 allowFullPageRender: false, 8515 8516 /** Time spent generating markup. */ 8517 totalInstantiationTime: 0, 8518 8519 /** Time spent inserting markup into the DOM. */ 8520 totalInjectionTime: 0, 8521 8522 /** Whether support for touch events should be initialized. */ 8523 useTouchEvents: false, 8524 8525 /** Exposed for debugging purposes **/ 8526 _instancesByReactRootID: instancesByReactRootID, 8527 8528 /** 8529 * This is a hook provided to support rendering React components while 8530 * ensuring that the apparent scroll position of its `container` does not 8531 * change. 8532 * 8533 * @param {DOMElement} container The `container` being rendered into. 8534 * @param {function} renderCallback This must be called once to do the render. 8535 */ 8536 scrollMonitor: function(container, renderCallback) { 8537 renderCallback(); 8538 }, 8539 8540 /** 8541 * Ensures that the top-level event delegation listener is set up. This will 8542 * be invoked some time before the first time any React component is rendered. 8543 * @param {DOMElement} container container we're rendering into 8544 * 8545 * @private 8546 */ 8547 prepareEnvironmentForDOM: function(container) { 8548 ("production" !== "development" ? invariant( 8549 container && ( 8550 container.nodeType === ELEMENT_NODE_TYPE || 8551 container.nodeType === DOC_NODE_TYPE 8552 ), 8553 'prepareEnvironmentForDOM(...): Target container is not a DOM element.' 8554 ) : invariant(container && ( 8555 container.nodeType === ELEMENT_NODE_TYPE || 8556 container.nodeType === DOC_NODE_TYPE 8557 ))); 8558 var doc = container.nodeType === ELEMENT_NODE_TYPE ? 8559 container.ownerDocument : 8560 container; 8561 ReactEventEmitter.ensureListening(ReactMount.useTouchEvents, doc); 8562 }, 8563 8564 /** 8565 * Take a component that's already mounted into the DOM and replace its props 8566 * @param {ReactComponent} prevComponent component instance already in the DOM 8567 * @param {ReactComponent} nextComponent component instance to render 8568 * @param {DOMElement} container container to render into 8569 * @param {?function} callback function triggered on completion 8570 */ 8571 _updateRootComponent: function( 8572 prevComponent, 8573 nextComponent, 8574 container, 8575 callback) { 8576 var nextProps = nextComponent.props; 8577 ReactMount.scrollMonitor(container, function() { 8578 prevComponent.replaceProps(nextProps, callback); 8579 }); 8580 8581 if ("production" !== "development") { 8582 // Record the root element in case it later gets transplanted. 8583 rootElementsByReactRootID[getReactRootID(container)] = 8584 getReactRootElementInContainer(container); 8585 } 8586 8587 return prevComponent; 8588 }, 8589 8590 /** 8591 * Register a component into the instance map and start the events system. 8592 * @param {ReactComponent} nextComponent component instance to render 8593 * @param {DOMElement} container container to render into 8594 * @return {string} reactRoot ID prefix 8595 */ 8596 _registerComponent: function(nextComponent, container) { 8597 ReactMount.prepareEnvironmentForDOM(container); 8598 8599 var reactRootID = ReactMount.registerContainer(container); 8600 instancesByReactRootID[reactRootID] = nextComponent; 8601 return reactRootID; 8602 }, 8603 8604 /** 8605 * Render a new component into the DOM. 8606 * @param {ReactComponent} nextComponent component instance to render 8607 * @param {DOMElement} container container to render into 8608 * @param {boolean} shouldReuseMarkup if we should skip the markup insertion 8609 * @return {ReactComponent} nextComponent 8610 */ 8611 _renderNewRootComponent: function( 8612 nextComponent, 8613 container, 8614 shouldReuseMarkup) { 8615 var reactRootID = ReactMount._registerComponent(nextComponent, container); 8616 nextComponent.mountComponentIntoNode( 8617 reactRootID, 8618 container, 8619 shouldReuseMarkup 8620 ); 8621 8622 if ("production" !== "development") { 8623 // Record the root element in case it later gets transplanted. 8624 rootElementsByReactRootID[reactRootID] = 8625 getReactRootElementInContainer(container); 8626 } 8627 8628 return nextComponent; 8629 }, 8630 8631 /** 8632 * Renders a React component into the DOM in the supplied `container`. 8633 * 8634 * If the React component was previously rendered into `container`, this will 8635 * perform an update on it and only mutate the DOM as necessary to reflect the 8636 * latest React component. 8637 * 8638 * @param {ReactComponent} nextComponent Component instance to render. 8639 * @param {DOMElement} container DOM element to render into. 8640 * @param {?function} callback function triggered on completion 8641 * @return {ReactComponent} Component instance rendered in `container`. 8642 */ 8643 renderComponent: function(nextComponent, container, callback) { 8644 var registeredComponent = instancesByReactRootID[getReactRootID(container)]; 8645 8646 if (registeredComponent) { 8647 if (registeredComponent.constructor === nextComponent.constructor) { 8648 return ReactMount._updateRootComponent( 8649 registeredComponent, 8650 nextComponent, 8651 container, 8652 callback 8653 ); 8654 } else { 8655 ReactMount.unmountComponentAtNode(container); 8656 } 8657 } 8658 8659 var reactRootElement = getReactRootElementInContainer(container); 8660 var containerHasReactMarkup = 8661 reactRootElement && ReactMount.isRenderedByReact(reactRootElement); 8662 8663 var shouldReuseMarkup = containerHasReactMarkup && !registeredComponent; 8664 8665 var component = ReactMount._renderNewRootComponent( 8666 nextComponent, 8667 container, 8668 shouldReuseMarkup 8669 ); 8670 callback && callback(); 8671 return component; 8672 }, 8673 8674 /** 8675 * Constructs a component instance of `constructor` with `initialProps` and 8676 * renders it into the supplied `container`. 8677 * 8678 * @param {function} constructor React component constructor. 8679 * @param {?object} props Initial props of the component instance. 8680 * @param {DOMElement} container DOM element to render into. 8681 * @return {ReactComponent} Component instance rendered in `container`. 8682 */ 8683 constructAndRenderComponent: function(constructor, props, container) { 8684 return ReactMount.renderComponent(constructor(props), container); 8685 }, 8686 8687 /** 8688 * Constructs a component instance of `constructor` with `initialProps` and 8689 * renders it into a container node identified by supplied `id`. 8690 * 8691 * @param {function} componentConstructor React component constructor 8692 * @param {?object} props Initial props of the component instance. 8693 * @param {string} id ID of the DOM element to render into. 8694 * @return {ReactComponent} Component instance rendered in the container node. 8695 */ 8696 constructAndRenderComponentByID: function(constructor, props, id) { 8697 return ReactMount.constructAndRenderComponent(constructor, props, $(id)); 8698 }, 8699 8700 /** 8701 * Registers a container node into which React components will be rendered. 8702 * This also creates the "reatRoot" ID that will be assigned to the element 8703 * rendered within. 8704 * 8705 * @param {DOMElement} container DOM element to register as a container. 8706 * @return {string} The "reactRoot" ID of elements rendered within. 8707 */ 8708 registerContainer: function(container) { 8709 var reactRootID = getReactRootID(container); 8710 if (reactRootID) { 8711 // If one exists, make sure it is a valid "reactRoot" ID. 8712 reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); 8713 } 8714 if (!reactRootID) { 8715 // No valid "reactRoot" ID found, create one. 8716 reactRootID = ReactInstanceHandles.createReactRootID(); 8717 } 8718 containersByReactRootID[reactRootID] = container; 8719 return reactRootID; 8720 }, 8721 8722 /** 8723 * Unmounts and destroys the React component rendered in the `container`. 8724 * 8725 * @param {DOMElement} container DOM element containing a React component. 8726 * @return {boolean} True if a component was found in and unmounted from 8727 * `container` 8728 */ 8729 unmountComponentAtNode: function(container) { 8730 var reactRootID = getReactRootID(container); 8731 var component = instancesByReactRootID[reactRootID]; 8732 if (!component) { 8733 return false; 8734 } 8735 ReactMount.unmountComponentFromNode(component, container); 8736 delete instancesByReactRootID[reactRootID]; 8737 delete containersByReactRootID[reactRootID]; 8738 if ("production" !== "development") { 8739 delete rootElementsByReactRootID[reactRootID]; 8740 } 8741 return true; 8742 }, 8743 8744 /** 8745 * @deprecated 8746 */ 8747 unmountAndReleaseReactRootNode: function() { 8748 if ("production" !== "development") { 8749 console.warn( 8750 'unmountAndReleaseReactRootNode() has been renamed to ' + 8751 'unmountComponentAtNode() and will be removed in the next ' + 8752 'version of React.' 8753 ); 8754 } 8755 return ReactMount.unmountComponentAtNode.apply(this, arguments); 8756 }, 8757 8758 /** 8759 * Unmounts a component and removes it from the DOM. 8760 * 8761 * @param {ReactComponent} instance React component instance. 8762 * @param {DOMElement} container DOM element to unmount from. 8763 * @final 8764 * @internal 8765 * @see {ReactMount.unmountComponentAtNode} 8766 */ 8767 unmountComponentFromNode: function(instance, container) { 8768 instance.unmountComponent(); 8769 8770 if (container.nodeType === DOC_NODE_TYPE) { 8771 container = container.documentElement; 8772 } 8773 8774 // http://jsperf.com/emptying-a-node 8775 while (container.lastChild) { 8776 container.removeChild(container.lastChild); 8777 } 8778 }, 8779 8780 /** 8781 * Finds the container DOM element that contains React component to which the 8782 * supplied DOM `id` belongs. 8783 * 8784 * @param {string} id The ID of an element rendered by a React component. 8785 * @return {?DOMElement} DOM element that contains the `id`. 8786 */ 8787 findReactContainerForID: function(id) { 8788 var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); 8789 var container = containersByReactRootID[reactRootID]; 8790 8791 if ("production" !== "development") { 8792 var rootElement = rootElementsByReactRootID[reactRootID]; 8793 if (rootElement && rootElement.parentNode !== container) { 8794 ("production" !== "development" ? invariant( 8795 // Call internalGetID here because getID calls isValid which calls 8796 // findReactContainerForID (this function). 8797 internalGetID(rootElement) === reactRootID, 8798 'ReactMount: Root element ID differed from reactRootID.' 8799 ) : invariant(// Call internalGetID here because getID calls isValid which calls 8800 // findReactContainerForID (this function). 8801 internalGetID(rootElement) === reactRootID)); 8802 8803 var containerChild = container.firstChild; 8804 if (containerChild && 8805 reactRootID === internalGetID(containerChild)) { 8806 // If the container has a new child with the same ID as the old 8807 // root element, then rootElementsByReactRootID[reactRootID] is 8808 // just stale and needs to be updated. The case that deserves a 8809 // warning is when the container is empty. 8810 rootElementsByReactRootID[reactRootID] = containerChild; 8811 } else { 8812 console.warn( 8813 'ReactMount: Root element has been removed from its original ' + 8814 'container. New container:', rootElement.parentNode 8815 ); 8816 } 8817 } 8818 } 8819 8820 return container; 8821 }, 8822 8823 /** 8824 * Finds an element rendered by React with the supplied ID. 8825 * 8826 * @param {string} id ID of a DOM node in the React component. 8827 * @return {DOMElement} Root DOM node of the React component. 8828 */ 8829 findReactNodeByID: function(id) { 8830 var reactRoot = ReactMount.findReactContainerForID(id); 8831 return ReactMount.findComponentRoot(reactRoot, id); 8832 }, 8833 8834 /** 8835 * True if the supplied `node` is rendered by React. 8836 * 8837 * @param {*} node DOM Element to check. 8838 * @return {boolean} True if the DOM Element appears to be rendered by React. 8839 * @internal 8840 */ 8841 isRenderedByReact: function(node) { 8842 if (node.nodeType !== 1) { 8843 // Not a DOMElement, therefore not a React component 8844 return false; 8845 } 8846 var id = ReactMount.getID(node); 8847 return id ? id.charAt(0) === SEPARATOR : false; 8848 }, 8849 8850 /** 8851 * Traverses up the ancestors of the supplied node to find a node that is a 8852 * DOM representation of a React component. 8853 * 8854 * @param {*} node 8855 * @return {?DOMEventTarget} 8856 * @internal 8857 */ 8858 getFirstReactDOM: function(node) { 8859 var current = node; 8860 while (current && current.parentNode !== current) { 8861 if (ReactMount.isRenderedByReact(current)) { 8862 return current; 8863 } 8864 current = current.parentNode; 8865 } 8866 return null; 8867 }, 8868 8869 /** 8870 * Finds a node with the supplied `id` inside of the supplied `ancestorNode`. 8871 * Exploits the ID naming scheme to perform the search quickly. 8872 * 8873 * @param {DOMEventTarget} ancestorNode Search from this root. 8874 * @pararm {string} id ID of the DOM representation of the component. 8875 * @return {DOMEventTarget} DOM node with the supplied `id`. 8876 * @internal 8877 */ 8878 findComponentRoot: function(ancestorNode, id) { 8879 var firstChildren = [ancestorNode.firstChild]; 8880 var childIndex = 0; 8881 8882 while (childIndex < firstChildren.length) { 8883 var child = firstChildren[childIndex++]; 8884 while (child) { 8885 var childID = ReactMount.getID(child); 8886 if (childID) { 8887 if (id === childID) { 8888 return child; 8889 } else if (ReactInstanceHandles.isAncestorIDOf(childID, id)) { 8890 // If we find a child whose ID is an ancestor of the given ID, 8891 // then we can be sure that we only want to search the subtree 8892 // rooted at this child, so we can throw out the rest of the 8893 // search state. 8894 firstChildren.length = childIndex = 0; 8895 firstChildren.push(child.firstChild); 8896 break; 8897 } else { 8898 // TODO This should not be necessary if the ID hierarchy is 8899 // correct, but is occasionally necessary if the DOM has been 8900 // modified in unexpected ways. 8901 firstChildren.push(child.firstChild); 8902 } 8903 } else { 8904 // If this child had no ID, then there's a chance that it was 8905 // injected automatically by the browser, as when a `<table>` 8906 // element sprouts an extra `<tbody>` child as a side effect of 8907 // `.innerHTML` parsing. Optimistically continue down this 8908 // branch, but not before examining the other siblings. 8909 firstChildren.push(child.firstChild); 8910 } 8911 child = child.nextSibling; 8912 } 8913 } 8914 8915 if ("production" !== "development") { 8916 console.error( 8917 'Error while invoking `findComponentRoot` with the following ' + 8918 'ancestor node:', 8919 ancestorNode 8920 ); 8921 } 8922 ("production" !== "development" ? invariant( 8923 false, 8924 'findComponentRoot(..., %s): Unable to find element. This probably ' + 8925 'means the DOM was unexpectedly mutated (e.g. by the browser).', 8926 id, 8927 ReactMount.getID(ancestorNode) 8928 ) : invariant(false)); 8929 }, 8930 8931 8932 /** 8933 * React ID utilities. 8934 */ 8935 8936 ATTR_NAME: ATTR_NAME, 8937 8938 getReactRootID: getReactRootID, 8939 8940 getID: getID, 8941 8942 setID: setID, 8943 8944 getNode: getNode, 8945 8946 purgeID: purgeID, 8947 8948 injection: {} 8949 }; 8950 8951 module.exports = ReactMount; 8952 8953 },{"./$":1,"./ReactEventEmitter":44,"./ReactInstanceHandles":48,"./containsNode":77,"./getReactRootElementInContainer":94,"./invariant":98}],51:[function(require,module,exports){ 8954 /** 8955 * Copyright 2013 Facebook, Inc. 8956 * 8957 * Licensed under the Apache License, Version 2.0 (the "License"); 8958 * you may not use this file except in compliance with the License. 8959 * You may obtain a copy of the License at 8960 * 8961 * http://www.apache.org/licenses/LICENSE-2.0 8962 * 8963 * Unless required by applicable law or agreed to in writing, software 8964 * distributed under the License is distributed on an "AS IS" BASIS, 8965 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8966 * See the License for the specific language governing permissions and 8967 * limitations under the License. 8968 * 8969 * @providesModule ReactMountReady 8970 */ 8971 8972 "use strict"; 8973 8974 var PooledClass = require("./PooledClass"); 8975 8976 var mixInto = require("./mixInto"); 8977 8978 /** 8979 * A specialized pseudo-event module to help keep track of components waiting to 8980 * be notified when their DOM representations are available for use. 8981 * 8982 * This implements `PooledClass`, so you should never need to instantiate this. 8983 * Instead, use `ReactMountReady.getPooled()`. 8984 * 8985 * @param {?array<function>} initialCollection 8986 * @class ReactMountReady 8987 * @implements PooledClass 8988 * @internal 8989 */ 8990 function ReactMountReady(initialCollection) { 8991 this._queue = initialCollection || null; 8992 } 8993 8994 mixInto(ReactMountReady, { 8995 8996 /** 8997 * Enqueues a callback to be invoked when `notifyAll` is invoked. This is used 8998 * to enqueue calls to `componentDidMount` and `componentDidUpdate`. 8999 * 9000 * @param {ReactComponent} component Component being rendered. 9001 * @param {function(DOMElement)} callback Invoked when `notifyAll` is invoked. 9002 * @internal 9003 */ 9004 enqueue: function(component, callback) { 9005 this._queue = this._queue || []; 9006 this._queue.push({component: component, callback: callback}); 9007 }, 9008 9009 /** 9010 * Invokes all enqueued callbacks and clears the queue. This is invoked after 9011 * the DOM representation of a component has been created or updated. 9012 * 9013 * @internal 9014 */ 9015 notifyAll: function() { 9016 var queue = this._queue; 9017 if (queue) { 9018 this._queue = null; 9019 for (var i = 0, l = queue.length; i < l; i++) { 9020 var component = queue[i].component; 9021 var callback = queue[i].callback; 9022 callback.call(component, component.getDOMNode()); 9023 } 9024 queue.length = 0; 9025 } 9026 }, 9027 9028 /** 9029 * Resets the internal queue. 9030 * 9031 * @internal 9032 */ 9033 reset: function() { 9034 this._queue = null; 9035 }, 9036 9037 /** 9038 * `PooledClass` looks for this. 9039 */ 9040 destructor: function() { 9041 this.reset(); 9042 } 9043 9044 }); 9045 9046 PooledClass.addPoolingTo(ReactMountReady); 9047 9048 module.exports = ReactMountReady; 9049 9050 },{"./PooledClass":23,"./mixInto":110}],52:[function(require,module,exports){ 9051 /** 9052 * Copyright 2013 Facebook, Inc. 9053 * 9054 * Licensed under the Apache License, Version 2.0 (the "License"); 9055 * you may not use this file except in compliance with the License. 9056 * You may obtain a copy of the License at 9057 * 9058 * http://www.apache.org/licenses/LICENSE-2.0 9059 * 9060 * Unless required by applicable law or agreed to in writing, software 9061 * distributed under the License is distributed on an "AS IS" BASIS, 9062 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9063 * See the License for the specific language governing permissions and 9064 * limitations under the License. 9065 * 9066 * @providesModule ReactMultiChild 9067 * @typechecks static-only 9068 */ 9069 9070 "use strict"; 9071 9072 var ReactComponent = require("./ReactComponent"); 9073 var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); 9074 9075 var flattenChildren = require("./flattenChildren"); 9076 9077 /** 9078 * Given a `curChild` and `newChild`, determines if `curChild` should be 9079 * updated as opposed to being destroyed or replaced. 9080 * 9081 * @param {?ReactComponent} curChild 9082 * @param {?ReactComponent} newChild 9083 * @return {boolean} True if `curChild` should be updated with `newChild`. 9084 * @protected 9085 */ 9086 function shouldUpdateChild(curChild, newChild) { 9087 return curChild && newChild && curChild.constructor === newChild.constructor; 9088 } 9089 9090 /** 9091 * Updating children of a component may trigger recursive updates. The depth is 9092 * used to batch recursive updates to render markup more efficiently. 9093 * 9094 * @type {number} 9095 * @private 9096 */ 9097 var updateDepth = 0; 9098 9099 /** 9100 * Queue of update configuration objects. 9101 * 9102 * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`. 9103 * 9104 * @type {array<object>} 9105 * @private 9106 */ 9107 var updateQueue = []; 9108 9109 /** 9110 * Queue of markup to be rendered. 9111 * 9112 * @type {array<string>} 9113 * @private 9114 */ 9115 var markupQueue = []; 9116 9117 /** 9118 * Enqueues markup to be rendered and inserted at a supplied index. 9119 * 9120 * @param {string} parentID ID of the parent component. 9121 * @param {string} markup Markup that renders into an element. 9122 * @param {number} toIndex Destination index. 9123 * @private 9124 */ 9125 function enqueueMarkup(parentID, markup, toIndex) { 9126 // NOTE: Null values reduce hidden classes. 9127 updateQueue.push({ 9128 parentID: parentID, 9129 parentNode: null, 9130 type: ReactMultiChildUpdateTypes.INSERT_MARKUP, 9131 markupIndex: markupQueue.push(markup) - 1, 9132 textContent: null, 9133 fromIndex: null, 9134 toIndex: toIndex 9135 }); 9136 } 9137 9138 /** 9139 * Enqueues moving an existing element to another index. 9140 * 9141 * @param {string} parentID ID of the parent component. 9142 * @param {number} fromIndex Source index of the existing element. 9143 * @param {number} toIndex Destination index of the element. 9144 * @private 9145 */ 9146 function enqueueMove(parentID, fromIndex, toIndex) { 9147 // NOTE: Null values reduce hidden classes. 9148 updateQueue.push({ 9149 parentID: parentID, 9150 parentNode: null, 9151 type: ReactMultiChildUpdateTypes.MOVE_EXISTING, 9152 markupIndex: null, 9153 textContent: null, 9154 fromIndex: fromIndex, 9155 toIndex: toIndex 9156 }); 9157 } 9158 9159 /** 9160 * Enqueues removing an element at an index. 9161 * 9162 * @param {string} parentID ID of the parent component. 9163 * @param {number} fromIndex Index of the element to remove. 9164 * @private 9165 */ 9166 function enqueueRemove(parentID, fromIndex) { 9167 // NOTE: Null values reduce hidden classes. 9168 updateQueue.push({ 9169 parentID: parentID, 9170 parentNode: null, 9171 type: ReactMultiChildUpdateTypes.REMOVE_NODE, 9172 markupIndex: null, 9173 textContent: null, 9174 fromIndex: fromIndex, 9175 toIndex: null 9176 }); 9177 } 9178 9179 /** 9180 * Enqueues setting the text content. 9181 * 9182 * @param {string} parentID ID of the parent component. 9183 * @param {string} textContent Text content to set. 9184 * @private 9185 */ 9186 function enqueueTextContent(parentID, textContent) { 9187 // NOTE: Null values reduce hidden classes. 9188 updateQueue.push({ 9189 parentID: parentID, 9190 parentNode: null, 9191 type: ReactMultiChildUpdateTypes.TEXT_CONTENT, 9192 markupIndex: null, 9193 textContent: textContent, 9194 fromIndex: null, 9195 toIndex: null 9196 }); 9197 } 9198 9199 /** 9200 * Processes any enqueued updates. 9201 * 9202 * @private 9203 */ 9204 function processQueue() { 9205 if (updateQueue.length) { 9206 ReactComponent.DOMIDOperations.dangerouslyProcessChildrenUpdates( 9207 updateQueue, 9208 markupQueue 9209 ); 9210 clearQueue(); 9211 } 9212 } 9213 9214 /** 9215 * Clears any enqueued updates. 9216 * 9217 * @private 9218 */ 9219 function clearQueue() { 9220 updateQueue.length = 0; 9221 markupQueue.length = 0; 9222 } 9223 9224 /** 9225 * ReactMultiChild are capable of reconciling multiple children. 9226 * 9227 * @class ReactMultiChild 9228 * @internal 9229 */ 9230 var ReactMultiChild = { 9231 9232 /** 9233 * Provides common functionality for components that must reconcile multiple 9234 * children. This is used by `ReactDOMComponent` to mount, update, and 9235 * unmount child components. 9236 * 9237 * @lends {ReactMultiChild.prototype} 9238 */ 9239 Mixin: { 9240 9241 /** 9242 * Generates a "mount image" for each of the supplied children. In the case 9243 * of `ReactDOMComponent`, a mount image is a string of markup. 9244 * 9245 * @param {?object} nestedChildren Nested child maps. 9246 * @return {array} An array of mounted representations. 9247 * @internal 9248 */ 9249 mountChildren: function(nestedChildren, transaction) { 9250 var children = flattenChildren(nestedChildren); 9251 var mountImages = []; 9252 var index = 0; 9253 this._renderedChildren = children; 9254 for (var name in children) { 9255 var child = children[name]; 9256 if (children.hasOwnProperty(name) && child) { 9257 // Inlined for performance, see `ReactInstanceHandles.createReactID`. 9258 var rootID = this._rootNodeID + '.' + name; 9259 var mountImage = child.mountComponent( 9260 rootID, 9261 transaction, 9262 this._mountDepth + 1 9263 ); 9264 child._mountImage = mountImage; 9265 child._mountIndex = index; 9266 mountImages.push(mountImage); 9267 index++; 9268 } 9269 } 9270 return mountImages; 9271 }, 9272 9273 /** 9274 * Replaces any rendered children with a text content string. 9275 * 9276 * @param {string} nextContent String of content. 9277 * @internal 9278 */ 9279 updateTextContent: function(nextContent) { 9280 updateDepth++; 9281 try { 9282 var prevChildren = this._renderedChildren; 9283 // Remove any rendered children. 9284 for (var name in prevChildren) { 9285 if (prevChildren.hasOwnProperty(name) && 9286 prevChildren[name]) { 9287 this._unmountChildByName(prevChildren[name], name); 9288 } 9289 } 9290 // Set new text content. 9291 this.setTextContent(nextContent); 9292 } catch (error) { 9293 updateDepth--; 9294 updateDepth || clearQueue(); 9295 throw error; 9296 } 9297 updateDepth--; 9298 updateDepth || processQueue(); 9299 }, 9300 9301 /** 9302 * Updates the rendered children with new children. 9303 * 9304 * @param {?object} nextNestedChildren Nested child maps. 9305 * @param {ReactReconcileTransaction} transaction 9306 * @internal 9307 */ 9308 updateChildren: function(nextNestedChildren, transaction) { 9309 updateDepth++; 9310 try { 9311 this._updateChildren(nextNestedChildren, transaction); 9312 } catch (error) { 9313 updateDepth--; 9314 updateDepth || clearQueue(); 9315 throw error; 9316 } 9317 updateDepth--; 9318 updateDepth || processQueue(); 9319 }, 9320 9321 /** 9322 * Improve performance by isolating this hot code path from the try/catch 9323 * block in `updateChildren`. 9324 * 9325 * @param {?object} nextNestedChildren Nested child maps. 9326 * @param {ReactReconcileTransaction} transaction 9327 * @final 9328 * @protected 9329 */ 9330 _updateChildren: function(nextNestedChildren, transaction) { 9331 var nextChildren = flattenChildren(nextNestedChildren); 9332 var prevChildren = this._renderedChildren; 9333 if (!nextChildren && !prevChildren) { 9334 return; 9335 } 9336 var name; 9337 // `nextIndex` will increment for each child in `nextChildren`, but 9338 // `lastIndex` will be the last index visited in `prevChildren`. 9339 var lastIndex = 0; 9340 var nextIndex = 0; 9341 for (name in nextChildren) { 9342 if (!nextChildren.hasOwnProperty(name)) { 9343 continue; 9344 } 9345 var prevChild = prevChildren && prevChildren[name]; 9346 var nextChild = nextChildren[name]; 9347 if (shouldUpdateChild(prevChild, nextChild)) { 9348 this.moveChild(prevChild, nextIndex, lastIndex); 9349 lastIndex = Math.max(prevChild._mountIndex, lastIndex); 9350 prevChild.receiveComponent(nextChild, transaction); 9351 prevChild._mountIndex = nextIndex; 9352 } else { 9353 if (prevChild) { 9354 // Update `lastIndex` before `_mountIndex` gets unset by unmounting. 9355 lastIndex = Math.max(prevChild._mountIndex, lastIndex); 9356 this._unmountChildByName(prevChild, name); 9357 } 9358 if (nextChild) { 9359 this._mountChildByNameAtIndex( 9360 nextChild, name, nextIndex, transaction 9361 ); 9362 } 9363 } 9364 if (nextChild) { 9365 nextIndex++; 9366 } 9367 } 9368 // Remove children that are no longer present. 9369 for (name in prevChildren) { 9370 if (prevChildren.hasOwnProperty(name) && 9371 prevChildren[name] && 9372 !(nextChildren && nextChildren[name])) { 9373 this._unmountChildByName(prevChildren[name], name); 9374 } 9375 } 9376 }, 9377 9378 /** 9379 * Unmounts all rendered children. This should be used to clean up children 9380 * when this component is unmounted. 9381 * 9382 * @internal 9383 */ 9384 unmountChildren: function() { 9385 var renderedChildren = this._renderedChildren; 9386 for (var name in renderedChildren) { 9387 var renderedChild = renderedChildren[name]; 9388 if (renderedChild && renderedChild.unmountComponent) { 9389 renderedChild.unmountComponent(); 9390 } 9391 } 9392 this._renderedChildren = null; 9393 }, 9394 9395 /** 9396 * Moves a child component to the supplied index. 9397 * 9398 * @param {ReactComponent} child Component to move. 9399 * @param {number} toIndex Destination index of the element. 9400 * @param {number} lastIndex Last index visited of the siblings of `child`. 9401 * @protected 9402 */ 9403 moveChild: function(child, toIndex, lastIndex) { 9404 // If the index of `child` is less than `lastIndex`, then it needs to 9405 // be moved. Otherwise, we do not need to move it because a child will be 9406 // inserted or moved before `child`. 9407 if (child._mountIndex < lastIndex) { 9408 enqueueMove(this._rootNodeID, child._mountIndex, toIndex); 9409 } 9410 }, 9411 9412 /** 9413 * Creates a child component. 9414 * 9415 * @param {ReactComponent} child Component to create. 9416 * @protected 9417 */ 9418 createChild: function(child) { 9419 enqueueMarkup(this._rootNodeID, child._mountImage, child._mountIndex); 9420 }, 9421 9422 /** 9423 * Removes a child component. 9424 * 9425 * @param {ReactComponent} child Child to remove. 9426 * @protected 9427 */ 9428 removeChild: function(child) { 9429 enqueueRemove(this._rootNodeID, child._mountIndex); 9430 }, 9431 9432 /** 9433 * Sets this text content string. 9434 * 9435 * @param {string} textContent Text content to set. 9436 * @protected 9437 */ 9438 setTextContent: function(textContent) { 9439 enqueueTextContent(this._rootNodeID, textContent); 9440 }, 9441 9442 /** 9443 * Mounts a child with the supplied name. 9444 * 9445 * NOTE: This is part of `updateChildren` and is here for readability. 9446 * 9447 * @param {ReactComponent} child Component to mount. 9448 * @param {string} name Name of the child. 9449 * @param {number} index Index at which to insert the child. 9450 * @param {ReactReconcileTransaction} transaction 9451 * @private 9452 */ 9453 _mountChildByNameAtIndex: function(child, name, index, transaction) { 9454 // Inlined for performance, see `ReactInstanceHandles.createReactID`. 9455 var rootID = this._rootNodeID + '.' + name; 9456 var mountImage = child.mountComponent( 9457 rootID, 9458 transaction, 9459 this._mountDepth + 1 9460 ); 9461 child._mountImage = mountImage; 9462 child._mountIndex = index; 9463 this.createChild(child); 9464 this._renderedChildren = this._renderedChildren || {}; 9465 this._renderedChildren[name] = child; 9466 }, 9467 9468 /** 9469 * Unmounts a rendered child by name. 9470 * 9471 * NOTE: This is part of `updateChildren` and is here for readability. 9472 * 9473 * @param {ReactComponent} child Component to unmount. 9474 * @param {string} name Name of the child in `this._renderedChildren`. 9475 * @private 9476 */ 9477 _unmountChildByName: function(child, name) { 9478 if (ReactComponent.isValidComponent(child)) { 9479 this.removeChild(child); 9480 child._mountImage = null; 9481 child._mountIndex = null; 9482 child.unmountComponent(); 9483 delete this._renderedChildren[name]; 9484 } 9485 } 9486 9487 } 9488 9489 }; 9490 9491 module.exports = ReactMultiChild; 9492 9493 },{"./ReactComponent":25,"./ReactMultiChildUpdateTypes":53,"./flattenChildren":87}],53:[function(require,module,exports){ 9494 /** 9495 * Copyright 2013 Facebook, Inc. 9496 * 9497 * Licensed under the Apache License, Version 2.0 (the "License"); 9498 * you may not use this file except in compliance with the License. 9499 * You may obtain a copy of the License at 9500 * 9501 * http://www.apache.org/licenses/LICENSE-2.0 9502 * 9503 * Unless required by applicable law or agreed to in writing, software 9504 * distributed under the License is distributed on an "AS IS" BASIS, 9505 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9506 * See the License for the specific language governing permissions and 9507 * limitations under the License. 9508 * 9509 * @providesModule ReactMultiChildUpdateTypes 9510 */ 9511 9512 var keyMirror = require("./keyMirror"); 9513 9514 /** 9515 * When a component's children are updated, a series of update configuration 9516 * objects are created in order to batch and serialize the required changes. 9517 * 9518 * Enumerates all the possible types of update configurations. 9519 * 9520 * @internal 9521 */ 9522 var ReactMultiChildUpdateTypes = keyMirror({ 9523 INSERT_MARKUP: null, 9524 MOVE_EXISTING: null, 9525 REMOVE_NODE: null, 9526 TEXT_CONTENT: null 9527 }); 9528 9529 module.exports = ReactMultiChildUpdateTypes; 9530 9531 },{"./keyMirror":104}],54:[function(require,module,exports){ 9532 /** 9533 * Copyright 2013 Facebook, Inc. 9534 * 9535 * Licensed under the Apache License, Version 2.0 (the "License"); 9536 * you may not use this file except in compliance with the License. 9537 * You may obtain a copy of the License at 9538 * 9539 * http://www.apache.org/licenses/LICENSE-2.0 9540 * 9541 * Unless required by applicable law or agreed to in writing, software 9542 * distributed under the License is distributed on an "AS IS" BASIS, 9543 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9544 * See the License for the specific language governing permissions and 9545 * limitations under the License. 9546 * 9547 * @providesModule ReactOwner 9548 */ 9549 9550 "use strict"; 9551 9552 var invariant = require("./invariant"); 9553 9554 /** 9555 * ReactOwners are capable of storing references to owned components. 9556 * 9557 * All components are capable of //being// referenced by owner components, but 9558 * only ReactOwner components are capable of //referencing// owned components. 9559 * The named reference is known as a "ref". 9560 * 9561 * Refs are available when mounted and updated during reconciliation. 9562 * 9563 * var MyComponent = React.createClass({ 9564 * render: function() { 9565 * return ( 9566 * <div onClick={this.handleClick}> 9567 * <CustomComponent ref="custom" /> 9568 * </div> 9569 * ); 9570 * }, 9571 * handleClick: function() { 9572 * this.refs.custom.handleClick(); 9573 * }, 9574 * componentDidMount: function() { 9575 * this.refs.custom.initialize(); 9576 * } 9577 * }); 9578 * 9579 * Refs should rarely be used. When refs are used, they should only be done to 9580 * control data that is not handled by React's data flow. 9581 * 9582 * @class ReactOwner 9583 */ 9584 var ReactOwner = { 9585 9586 /** 9587 * @param {?object} object 9588 * @return {boolean} True if `object` is a valid owner. 9589 * @final 9590 */ 9591 isValidOwner: function(object) { 9592 return !!( 9593 object && 9594 typeof object.attachRef === 'function' && 9595 typeof object.detachRef === 'function' 9596 ); 9597 }, 9598 9599 /** 9600 * Adds a component by ref to an owner component. 9601 * 9602 * @param {ReactComponent} component Component to reference. 9603 * @param {string} ref Name by which to refer to the component. 9604 * @param {ReactOwner} owner Component on which to record the ref. 9605 * @final 9606 * @internal 9607 */ 9608 addComponentAsRefTo: function(component, ref, owner) { 9609 ("production" !== "development" ? invariant( 9610 ReactOwner.isValidOwner(owner), 9611 'addComponentAsRefTo(...): Only a ReactOwner can have refs.' 9612 ) : invariant(ReactOwner.isValidOwner(owner))); 9613 owner.attachRef(ref, component); 9614 }, 9615 9616 /** 9617 * Removes a component by ref from an owner component. 9618 * 9619 * @param {ReactComponent} component Component to dereference. 9620 * @param {string} ref Name of the ref to remove. 9621 * @param {ReactOwner} owner Component on which the ref is recorded. 9622 * @final 9623 * @internal 9624 */ 9625 removeComponentAsRefFrom: function(component, ref, owner) { 9626 ("production" !== "development" ? invariant( 9627 ReactOwner.isValidOwner(owner), 9628 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs.' 9629 ) : invariant(ReactOwner.isValidOwner(owner))); 9630 // Check that `component` is still the current ref because we do not want to 9631 // detach the ref if another component stole it. 9632 if (owner.refs[ref] === component) { 9633 owner.detachRef(ref); 9634 } 9635 }, 9636 9637 /** 9638 * A ReactComponent must mix this in to have refs. 9639 * 9640 * @lends {ReactOwner.prototype} 9641 */ 9642 Mixin: { 9643 9644 /** 9645 * Lazily allocates the refs object and stores `component` as `ref`. 9646 * 9647 * @param {string} ref Reference name. 9648 * @param {component} component Component to store as `ref`. 9649 * @final 9650 * @private 9651 */ 9652 attachRef: function(ref, component) { 9653 ("production" !== "development" ? invariant( 9654 component.isOwnedBy(this), 9655 'attachRef(%s, ...): Only a component\'s owner can store a ref to it.', 9656 ref 9657 ) : invariant(component.isOwnedBy(this))); 9658 var refs = this.refs || (this.refs = {}); 9659 refs[ref] = component; 9660 }, 9661 9662 /** 9663 * Detaches a reference name. 9664 * 9665 * @param {string} ref Name to dereference. 9666 * @final 9667 * @private 9668 */ 9669 detachRef: function(ref) { 9670 delete this.refs[ref]; 9671 } 9672 9673 } 9674 9675 }; 9676 9677 module.exports = ReactOwner; 9678 9679 },{"./invariant":98}],55:[function(require,module,exports){ 9680 /** 9681 * Copyright 2013 Facebook, Inc. 9682 * 9683 * Licensed under the Apache License, Version 2.0 (the "License"); 9684 * you may not use this file except in compliance with the License. 9685 * You may obtain a copy of the License at 9686 * 9687 * http://www.apache.org/licenses/LICENSE-2.0 9688 * 9689 * Unless required by applicable law or agreed to in writing, software 9690 * distributed under the License is distributed on an "AS IS" BASIS, 9691 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9692 * See the License for the specific language governing permissions and 9693 * limitations under the License. 9694 * 9695 * @providesModule ReactPerf 9696 * @typechecks static-only 9697 */ 9698 9699 "use strict"; 9700 9701 var ReactPerf = { 9702 /** 9703 * Boolean to enable/disable measurement. Set to false by default to prevent 9704 * accidental logging and perf loss. 9705 */ 9706 enableMeasure: false, 9707 9708 /** 9709 * Holds onto the measure function in use. By default, don't measure 9710 * anything, but we'll override this if we inject a measure function. 9711 */ 9712 storedMeasure: _noMeasure, 9713 9714 /** 9715 * Use this to wrap methods you want to measure. 9716 * 9717 * @param {string} objName 9718 * @param {string} fnName 9719 * @param {function} func 9720 * @return {function} 9721 */ 9722 measure: function(objName, fnName, func) { 9723 if ("production" !== "development") { 9724 var measuredFunc = null; 9725 return function() { 9726 if (ReactPerf.enableMeasure) { 9727 if (!measuredFunc) { 9728 measuredFunc = ReactPerf.storedMeasure(objName, fnName, func); 9729 } 9730 return measuredFunc.apply(this, arguments); 9731 } 9732 return func.apply(this, arguments); 9733 }; 9734 } 9735 return func; 9736 }, 9737 9738 injection: { 9739 /** 9740 * @param {function} measure 9741 */ 9742 injectMeasure: function(measure) { 9743 ReactPerf.storedMeasure = measure; 9744 } 9745 } 9746 }; 9747 9748 if ("production" !== "development") { 9749 var ExecutionEnvironment = require("./ExecutionEnvironment"); 9750 var url = (ExecutionEnvironment.canUseDOM && window.location.href) || ''; 9751 ReactPerf.enableMeasure = ReactPerf.enableMeasure || 9752 (/[?&]react_perf\b/).test(url); 9753 } 9754 9755 /** 9756 * Simply passes through the measured function, without measuring it. 9757 * 9758 * @param {string} objName 9759 * @param {string} fnName 9760 * @param {function} func 9761 * @return {function} 9762 */ 9763 function _noMeasure(objName, fnName, func) { 9764 return func; 9765 } 9766 9767 module.exports = ReactPerf; 9768 9769 },{"./ExecutionEnvironment":20}],56:[function(require,module,exports){ 9770 /** 9771 * Copyright 2013 Facebook, Inc. 9772 * 9773 * Licensed under the Apache License, Version 2.0 (the "License"); 9774 * you may not use this file except in compliance with the License. 9775 * You may obtain a copy of the License at 9776 * 9777 * http://www.apache.org/licenses/LICENSE-2.0 9778 * 9779 * Unless required by applicable law or agreed to in writing, software 9780 * distributed under the License is distributed on an "AS IS" BASIS, 9781 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9782 * See the License for the specific language governing permissions and 9783 * limitations under the License. 9784 * 9785 * @providesModule ReactPropTransferer 9786 */ 9787 9788 "use strict"; 9789 9790 var emptyFunction = require("./emptyFunction"); 9791 var invariant = require("./invariant"); 9792 var joinClasses = require("./joinClasses"); 9793 var merge = require("./merge"); 9794 9795 /** 9796 * Creates a transfer strategy that will merge prop values using the supplied 9797 * `mergeStrategy`. If a prop was previously unset, this just sets it. 9798 * 9799 * @param {function} mergeStrategy 9800 * @return {function} 9801 */ 9802 function createTransferStrategy(mergeStrategy) { 9803 return function(props, key, value) { 9804 if (!props.hasOwnProperty(key)) { 9805 props[key] = value; 9806 } else { 9807 props[key] = mergeStrategy(props[key], value); 9808 } 9809 }; 9810 } 9811 9812 /** 9813 * Transfer strategies dictate how props are transferred by `transferPropsTo`. 9814 */ 9815 var TransferStrategies = { 9816 /** 9817 * Never transfer `children`. 9818 */ 9819 children: emptyFunction, 9820 /** 9821 * Transfer the `className` prop by merging them. 9822 */ 9823 className: createTransferStrategy(joinClasses), 9824 /** 9825 * Never transfer the `ref` prop. 9826 */ 9827 ref: emptyFunction, 9828 /** 9829 * Transfer the `style` prop (which is an object) by merging them. 9830 */ 9831 style: createTransferStrategy(merge) 9832 }; 9833 9834 /** 9835 * ReactPropTransferer are capable of transferring props to another component 9836 * using a `transferPropsTo` method. 9837 * 9838 * @class ReactPropTransferer 9839 */ 9840 var ReactPropTransferer = { 9841 9842 TransferStrategies: TransferStrategies, 9843 9844 /** 9845 * @lends {ReactPropTransferer.prototype} 9846 */ 9847 Mixin: { 9848 9849 /** 9850 * Transfer props from this component to a target component. 9851 * 9852 * Props that do not have an explicit transfer strategy will be transferred 9853 * only if the target component does not already have the prop set. 9854 * 9855 * This is usually used to pass down props to a returned root component. 9856 * 9857 * @param {ReactComponent} component Component receiving the properties. 9858 * @return {ReactComponent} The supplied `component`. 9859 * @final 9860 * @protected 9861 */ 9862 transferPropsTo: function(component) { 9863 ("production" !== "development" ? invariant( 9864 component.props.__owner__ === this, 9865 '%s: You can\'t call transferPropsTo() on a component that you ' + 9866 'don\'t own, %s. This usually means you are calling ' + 9867 'transferPropsTo() on a component passed in as props or children.', 9868 this.constructor.displayName, 9869 component.constructor.displayName 9870 ) : invariant(component.props.__owner__ === this)); 9871 9872 var props = {}; 9873 for (var thatKey in component.props) { 9874 if (component.props.hasOwnProperty(thatKey)) { 9875 props[thatKey] = component.props[thatKey]; 9876 } 9877 } 9878 for (var thisKey in this.props) { 9879 if (!this.props.hasOwnProperty(thisKey)) { 9880 continue; 9881 } 9882 var transferStrategy = TransferStrategies[thisKey]; 9883 if (transferStrategy) { 9884 transferStrategy(props, thisKey, this.props[thisKey]); 9885 } else if (!props.hasOwnProperty(thisKey)) { 9886 props[thisKey] = this.props[thisKey]; 9887 } 9888 } 9889 component.props = props; 9890 return component; 9891 } 9892 9893 } 9894 9895 }; 9896 9897 module.exports = ReactPropTransferer; 9898 9899 },{"./emptyFunction":83,"./invariant":98,"./joinClasses":103,"./merge":107}],57:[function(require,module,exports){ 9900 /** 9901 * Copyright 2013 Facebook, Inc. 9902 * 9903 * Licensed under the Apache License, Version 2.0 (the "License"); 9904 * you may not use this file except in compliance with the License. 9905 * You may obtain a copy of the License at 9906 * 9907 * http://www.apache.org/licenses/LICENSE-2.0 9908 * 9909 * Unless required by applicable law or agreed to in writing, software 9910 * distributed under the License is distributed on an "AS IS" BASIS, 9911 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9912 * See the License for the specific language governing permissions and 9913 * limitations under the License. 9914 * 9915 * @providesModule ReactPropTypes 9916 */ 9917 9918 "use strict"; 9919 9920 var createObjectFrom = require("./createObjectFrom"); 9921 var invariant = require("./invariant"); 9922 9923 /** 9924 * Collection of methods that allow declaration and validation of props that are 9925 * supplied to React components. Example usage: 9926 * 9927 * var Props = require('ReactPropTypes'); 9928 * var MyArticle = React.createClass({ 9929 * propTypes: { 9930 * // An optional string prop named "description". 9931 * description: Props.string, 9932 * 9933 * // A required enum prop named "category". 9934 * category: Props.oneOf(['News','Photos']).isRequired, 9935 * 9936 * // A prop named "dialog" that requires an instance of Dialog. 9937 * dialog: Props.instanceOf(Dialog).isRequired 9938 * }, 9939 * render: function() { ... } 9940 * }); 9941 * 9942 * A more formal specification of how these methods are used: 9943 * 9944 * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) 9945 * decl := ReactPropTypes.{type}(.isRequired)? 9946 * 9947 * Each and every declaration produces a function with the same signature. This 9948 * allows the creation of custom validation functions. For example: 9949 * 9950 * var Props = require('ReactPropTypes'); 9951 * var MyLink = React.createClass({ 9952 * propTypes: { 9953 * // An optional string or URI prop named "href". 9954 * href: function(props, propName, componentName) { 9955 * var propValue = props[propName]; 9956 * invariant( 9957 * propValue == null || 9958 * typeof propValue === 'string' || 9959 * propValue instanceof URI, 9960 * 'Invalid `%s` supplied to `%s`, expected string or URI.', 9961 * propName, 9962 * componentName 9963 * ); 9964 * } 9965 * }, 9966 * render: function() { ... } 9967 * }); 9968 * 9969 * @internal 9970 */ 9971 var Props = { 9972 9973 array: createPrimitiveTypeChecker('array'), 9974 bool: createPrimitiveTypeChecker('boolean'), 9975 func: createPrimitiveTypeChecker('function'), 9976 number: createPrimitiveTypeChecker('number'), 9977 object: createPrimitiveTypeChecker('object'), 9978 string: createPrimitiveTypeChecker('string'), 9979 9980 oneOf: createEnumTypeChecker, 9981 9982 instanceOf: createInstanceTypeChecker 9983 9984 }; 9985 9986 var ANONYMOUS = '<<anonymous>>'; 9987 9988 function createPrimitiveTypeChecker(expectedType) { 9989 function validatePrimitiveType(propValue, propName, componentName) { 9990 var propType = typeof propValue; 9991 if (propType === 'object' && Array.isArray(propValue)) { 9992 propType = 'array'; 9993 } 9994 ("production" !== "development" ? invariant( 9995 propType === expectedType, 9996 'Invalid prop `%s` of type `%s` supplied to `%s`, expected `%s`.', 9997 propName, 9998 propType, 9999 componentName, 10000 expectedType 10001 ) : invariant(propType === expectedType)); 10002 } 10003 return createChainableTypeChecker(validatePrimitiveType); 10004 } 10005 10006 function createEnumTypeChecker(expectedValues) { 10007 var expectedEnum = createObjectFrom(expectedValues); 10008 function validateEnumType(propValue, propName, componentName) { 10009 ("production" !== "development" ? invariant( 10010 expectedEnum[propValue], 10011 'Invalid prop `%s` supplied to `%s`, expected one of %s.', 10012 propName, 10013 componentName, 10014 JSON.stringify(Object.keys(expectedEnum)) 10015 ) : invariant(expectedEnum[propValue])); 10016 } 10017 return createChainableTypeChecker(validateEnumType); 10018 } 10019 10020 function createInstanceTypeChecker(expectedClass) { 10021 function validateInstanceType(propValue, propName, componentName) { 10022 ("production" !== "development" ? invariant( 10023 propValue instanceof expectedClass, 10024 'Invalid prop `%s` supplied to `%s`, expected instance of `%s`.', 10025 propName, 10026 componentName, 10027 expectedClass.name || ANONYMOUS 10028 ) : invariant(propValue instanceof expectedClass)); 10029 } 10030 return createChainableTypeChecker(validateInstanceType); 10031 } 10032 10033 function createChainableTypeChecker(validate) { 10034 function createTypeChecker(isRequired) { 10035 function checkType(props, propName, componentName) { 10036 var propValue = props[propName]; 10037 if (propValue != null) { 10038 // Only validate if there is a value to check. 10039 validate(propValue, propName, componentName || ANONYMOUS); 10040 } else { 10041 ("production" !== "development" ? invariant( 10042 !isRequired, 10043 'Required prop `%s` was not specified in `%s`.', 10044 propName, 10045 componentName || ANONYMOUS 10046 ) : invariant(!isRequired)); 10047 } 10048 } 10049 if (!isRequired) { 10050 checkType.isRequired = createTypeChecker(true); 10051 } 10052 return checkType; 10053 } 10054 return createTypeChecker(false); 10055 } 10056 10057 module.exports = Props; 10058 10059 },{"./createObjectFrom":81,"./invariant":98}],58:[function(require,module,exports){ 10060 /** 10061 * Copyright 2013 Facebook, Inc. 10062 * 10063 * Licensed under the Apache License, Version 2.0 (the "License"); 10064 * you may not use this file except in compliance with the License. 10065 * You may obtain a copy of the License at 10066 * 10067 * http://www.apache.org/licenses/LICENSE-2.0 10068 * 10069 * Unless required by applicable law or agreed to in writing, software 10070 * distributed under the License is distributed on an "AS IS" BASIS, 10071 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10072 * See the License for the specific language governing permissions and 10073 * limitations under the License. 10074 * 10075 * @providesModule ReactReconcileTransaction 10076 * @typechecks static-only 10077 */ 10078 10079 "use strict"; 10080 10081 var ExecutionEnvironment = require("./ExecutionEnvironment"); 10082 var PooledClass = require("./PooledClass"); 10083 var ReactEventEmitter = require("./ReactEventEmitter"); 10084 var ReactInputSelection = require("./ReactInputSelection"); 10085 var ReactMountReady = require("./ReactMountReady"); 10086 var Transaction = require("./Transaction"); 10087 10088 var mixInto = require("./mixInto"); 10089 10090 /** 10091 * Ensures that, when possible, the selection range (currently selected text 10092 * input) is not disturbed by performing the transaction. 10093 */ 10094 var SELECTION_RESTORATION = { 10095 /** 10096 * @return {Selection} Selection information. 10097 */ 10098 initialize: ReactInputSelection.getSelectionInformation, 10099 /** 10100 * @param {Selection} sel Selection information returned from `initialize`. 10101 */ 10102 close: ReactInputSelection.restoreSelection 10103 }; 10104 10105 /** 10106 * Suppresses events (blur/focus) that could be inadvertently dispatched due to 10107 * high level DOM manipulations (like temporarily removing a text input from the 10108 * DOM). 10109 */ 10110 var EVENT_SUPPRESSION = { 10111 /** 10112 * @return {boolean} The enabled status of `ReactEventEmitter` before the 10113 * reconciliation. 10114 */ 10115 initialize: function() { 10116 var currentlyEnabled = ReactEventEmitter.isEnabled(); 10117 ReactEventEmitter.setEnabled(false); 10118 return currentlyEnabled; 10119 }, 10120 10121 /** 10122 * @param {boolean} previouslyEnabled Enabled status of `ReactEventEmitter` 10123 * before the reconciliation occured. `close` restores the previous value. 10124 */ 10125 close: function(previouslyEnabled) { 10126 ReactEventEmitter.setEnabled(previouslyEnabled); 10127 } 10128 }; 10129 10130 /** 10131 * Provides a `ReactMountReady` queue for collecting `onDOMReady` callbacks 10132 * during the performing of the transaction. 10133 */ 10134 var ON_DOM_READY_QUEUEING = { 10135 /** 10136 * Initializes the internal `onDOMReady` queue. 10137 */ 10138 initialize: function() { 10139 this.reactMountReady.reset(); 10140 }, 10141 10142 /** 10143 * After DOM is flushed, invoke all registered `onDOMReady` callbacks. 10144 */ 10145 close: function() { 10146 this.reactMountReady.notifyAll(); 10147 } 10148 }; 10149 10150 /** 10151 * Executed within the scope of the `Transaction` instance. Consider these as 10152 * being member methods, but with an implied ordering while being isolated from 10153 * each other. 10154 */ 10155 var TRANSACTION_WRAPPERS = [ 10156 SELECTION_RESTORATION, 10157 EVENT_SUPPRESSION, 10158 ON_DOM_READY_QUEUEING 10159 ]; 10160 10161 /** 10162 * Currently: 10163 * - The order that these are listed in the transaction is critical: 10164 * - Suppresses events. 10165 * - Restores selection range. 10166 * 10167 * Future: 10168 * - Restore document/overflow scroll positions that were unintentionally 10169 * modified via DOM insertions above the top viewport boundary. 10170 * - Implement/integrate with customized constraint based layout system and keep 10171 * track of which dimensions must be remeasured. 10172 * 10173 * @class ReactReconcileTransaction 10174 */ 10175 function ReactReconcileTransaction() { 10176 this.reinitializeTransaction(); 10177 this.reactMountReady = ReactMountReady.getPooled(null); 10178 } 10179 10180 var Mixin = { 10181 /** 10182 * @see Transaction 10183 * @abstract 10184 * @final 10185 * @return {array<object>} List of operation wrap proceedures. 10186 * TODO: convert to array<TransactionWrapper> 10187 */ 10188 getTransactionWrappers: function() { 10189 if (ExecutionEnvironment.canUseDOM) { 10190 return TRANSACTION_WRAPPERS; 10191 } else { 10192 return []; 10193 } 10194 }, 10195 10196 /** 10197 * @return {object} The queue to collect `onDOMReady` callbacks with. 10198 * TODO: convert to ReactMountReady 10199 */ 10200 getReactMountReady: function() { 10201 return this.reactMountReady; 10202 }, 10203 10204 /** 10205 * `PooledClass` looks for this, and will invoke this before allowing this 10206 * instance to be resused. 10207 */ 10208 destructor: function() { 10209 ReactMountReady.release(this.reactMountReady); 10210 this.reactMountReady = null; 10211 } 10212 }; 10213 10214 10215 mixInto(ReactReconcileTransaction, Transaction.Mixin); 10216 mixInto(ReactReconcileTransaction, Mixin); 10217 10218 PooledClass.addPoolingTo(ReactReconcileTransaction); 10219 10220 module.exports = ReactReconcileTransaction; 10221 10222 },{"./ExecutionEnvironment":20,"./PooledClass":23,"./ReactEventEmitter":44,"./ReactInputSelection":47,"./ReactMountReady":51,"./Transaction":73,"./mixInto":110}],59:[function(require,module,exports){ 10223 /** 10224 * Copyright 2013 Facebook, Inc. 10225 * 10226 * Licensed under the Apache License, Version 2.0 (the "License"); 10227 * you may not use this file except in compliance with the License. 10228 * You may obtain a copy of the License at 10229 * 10230 * http://www.apache.org/licenses/LICENSE-2.0 10231 * 10232 * Unless required by applicable law or agreed to in writing, software 10233 * distributed under the License is distributed on an "AS IS" BASIS, 10234 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10235 * See the License for the specific language governing permissions and 10236 * limitations under the License. 10237 * 10238 * @typechecks static-only 10239 * @providesModule ReactServerRendering 10240 */ 10241 "use strict"; 10242 10243 var ReactComponent = require("./ReactComponent"); 10244 var ReactInstanceHandles = require("./ReactInstanceHandles"); 10245 var ReactMarkupChecksum = require("./ReactMarkupChecksum"); 10246 var ReactReconcileTransaction = require("./ReactReconcileTransaction"); 10247 10248 var invariant = require("./invariant"); 10249 10250 /** 10251 * @param {ReactComponent} component 10252 * @param {function} callback 10253 */ 10254 function renderComponentToString(component, callback) { 10255 // We use a callback API to keep the API async in case in the future we ever 10256 // need it, but in reality this is a synchronous operation. 10257 10258 ("production" !== "development" ? invariant( 10259 ReactComponent.isValidComponent(component), 10260 'renderComponentToString(): You must pass a valid ReactComponent.' 10261 ) : invariant(ReactComponent.isValidComponent(component))); 10262 10263 ("production" !== "development" ? invariant( 10264 typeof callback === 'function', 10265 'renderComponentToString(): You must pass a function as a callback.' 10266 ) : invariant(typeof callback === 'function')); 10267 10268 var id = ReactInstanceHandles.createReactRootID(); 10269 var transaction = ReactReconcileTransaction.getPooled(); 10270 transaction.reinitializeTransaction(); 10271 try { 10272 transaction.perform(function() { 10273 var markup = component.mountComponent(id, transaction, 0); 10274 markup = ReactMarkupChecksum.addChecksumToMarkup(markup); 10275 callback(markup); 10276 }, null); 10277 } finally { 10278 ReactReconcileTransaction.release(transaction); 10279 } 10280 } 10281 10282 module.exports = { 10283 renderComponentToString: renderComponentToString 10284 }; 10285 10286 },{"./ReactComponent":25,"./ReactInstanceHandles":48,"./ReactMarkupChecksum":49,"./ReactReconcileTransaction":58,"./invariant":98}],60:[function(require,module,exports){ 10287 /** 10288 * Copyright 2013 Facebook, Inc. 10289 * 10290 * Licensed under the Apache License, Version 2.0 (the "License"); 10291 * you may not use this file except in compliance with the License. 10292 * You may obtain a copy of the License at 10293 * 10294 * http://www.apache.org/licenses/LICENSE-2.0 10295 * 10296 * Unless required by applicable law or agreed to in writing, software 10297 * distributed under the License is distributed on an "AS IS" BASIS, 10298 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10299 * See the License for the specific language governing permissions and 10300 * limitations under the License. 10301 * 10302 * @providesModule ReactTextComponent 10303 * @typechecks static-only 10304 */ 10305 10306 "use strict"; 10307 10308 var ReactComponent = require("./ReactComponent"); 10309 var ReactMount = require("./ReactMount"); 10310 10311 var escapeTextForBrowser = require("./escapeTextForBrowser"); 10312 var mixInto = require("./mixInto"); 10313 10314 /** 10315 * Text nodes violate a couple assumptions that React makes about components: 10316 * 10317 * - When mounting text into the DOM, adjacent text nodes are merged. 10318 * - Text nodes cannot be assigned a React root ID. 10319 * 10320 * This component is used to wrap strings in elements so that they can undergo 10321 * the same reconciliation that is applied to elements. 10322 * 10323 * TODO: Investigate representing React components in the DOM with text nodes. 10324 * 10325 * @class ReactTextComponent 10326 * @extends ReactComponent 10327 * @internal 10328 */ 10329 var ReactTextComponent = function(initialText) { 10330 this.construct({text: initialText}); 10331 }; 10332 10333 mixInto(ReactTextComponent, ReactComponent.Mixin); 10334 mixInto(ReactTextComponent, { 10335 10336 /** 10337 * Creates the markup for this text node. This node is not intended to have 10338 * any features besides containing text content. 10339 * 10340 * @param {string} rootID DOM ID of the root node. 10341 * @param {ReactReconcileTransaction} transaction 10342 * @param {number} mountDepth number of components in the owner hierarchy 10343 * @return {string} Markup for this text node. 10344 * @internal 10345 */ 10346 mountComponent: function(rootID, transaction, mountDepth) { 10347 ReactComponent.Mixin.mountComponent.call( 10348 this, 10349 rootID, 10350 transaction, 10351 mountDepth 10352 ); 10353 return ( 10354 '<span ' + ReactMount.ATTR_NAME + '="' + escapeTextForBrowser(rootID) + '">' + 10355 escapeTextForBrowser(this.props.text) + 10356 '</span>' 10357 ); 10358 }, 10359 10360 /** 10361 * Updates this component by updating the text content. 10362 * 10363 * @param {object} nextComponent Contains the next text content. 10364 * @param {ReactReconcileTransaction} transaction 10365 * @internal 10366 */ 10367 receiveComponent: function(nextComponent, transaction) { 10368 var nextProps = nextComponent.props; 10369 if (nextProps.text !== this.props.text) { 10370 this.props.text = nextProps.text; 10371 ReactComponent.DOMIDOperations.updateTextContentByID( 10372 this._rootNodeID, 10373 nextProps.text 10374 ); 10375 } 10376 } 10377 10378 }); 10379 10380 module.exports = ReactTextComponent; 10381 10382 },{"./ReactComponent":25,"./ReactMount":50,"./escapeTextForBrowser":84,"./mixInto":110}],61:[function(require,module,exports){ 10383 /** 10384 * Copyright 2013 Facebook, Inc. 10385 * 10386 * Licensed under the Apache License, Version 2.0 (the "License"); 10387 * you may not use this file except in compliance with the License. 10388 * You may obtain a copy of the License at 10389 * 10390 * http://www.apache.org/licenses/LICENSE-2.0 10391 * 10392 * Unless required by applicable law or agreed to in writing, software 10393 * distributed under the License is distributed on an "AS IS" BASIS, 10394 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10395 * See the License for the specific language governing permissions and 10396 * limitations under the License. 10397 * 10398 * @providesModule ReactUpdates 10399 */ 10400 10401 "use strict"; 10402 10403 var invariant = require("./invariant"); 10404 10405 var dirtyComponents = []; 10406 10407 var batchingStrategy = null; 10408 10409 function ensureBatchingStrategy() { 10410 ("production" !== "development" ? invariant(batchingStrategy, 'ReactUpdates: must inject a batching strategy') : invariant(batchingStrategy)); 10411 } 10412 10413 function batchedUpdates(callback, param) { 10414 ensureBatchingStrategy(); 10415 batchingStrategy.batchedUpdates(callback, param); 10416 } 10417 10418 /** 10419 * Array comparator for ReactComponents by owner depth 10420 * 10421 * @param {ReactComponent} c1 first component you're comparing 10422 * @param {ReactComponent} c2 second component you're comparing 10423 * @return {number} Return value usable by Array.prototype.sort(). 10424 */ 10425 function mountDepthComparator(c1, c2) { 10426 return c1._mountDepth - c2._mountDepth; 10427 } 10428 10429 function runBatchedUpdates() { 10430 // Since reconciling a component higher in the owner hierarchy usually (not 10431 // always -- see shouldComponentUpdate()) will reconcile children, reconcile 10432 // them before their children by sorting the array. 10433 10434 dirtyComponents.sort(mountDepthComparator); 10435 10436 for (var i = 0; i < dirtyComponents.length; i++) { 10437 // If a component is unmounted before pending changes apply, ignore them 10438 // TODO: Queue unmounts in the same list to avoid this happening at all 10439 var component = dirtyComponents[i]; 10440 if (component.isMounted()) { 10441 // If performUpdateIfNecessary happens to enqueue any new updates, we 10442 // shouldn't execute the callbacks until the next render happens, so 10443 // stash the callbacks first 10444 var callbacks = component._pendingCallbacks; 10445 component._pendingCallbacks = null; 10446 component.performUpdateIfNecessary(); 10447 if (callbacks) { 10448 for (var j = 0; j < callbacks.length; j++) { 10449 callbacks[j].call(component); 10450 } 10451 } 10452 } 10453 } 10454 } 10455 10456 function clearDirtyComponents() { 10457 dirtyComponents.length = 0; 10458 } 10459 10460 function flushBatchedUpdates() { 10461 // Run these in separate functions so the JIT can optimize 10462 try { 10463 runBatchedUpdates(); 10464 } catch (e) { 10465 // IE 8 requires catch to use finally. 10466 throw e; 10467 } finally { 10468 clearDirtyComponents(); 10469 } 10470 } 10471 10472 /** 10473 * Mark a component as needing a rerender, adding an optional callback to a 10474 * list of functions which will be executed once the rerender occurs. 10475 */ 10476 function enqueueUpdate(component, callback) { 10477 ("production" !== "development" ? invariant( 10478 !callback || typeof callback === "function", 10479 'enqueueUpdate(...): You called `setProps`, `replaceProps`, ' + 10480 '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 10481 'isn\'t callable.' 10482 ) : invariant(!callback || typeof callback === "function")); 10483 ensureBatchingStrategy(); 10484 10485 if (!batchingStrategy.isBatchingUpdates) { 10486 component.performUpdateIfNecessary(); 10487 callback && callback(); 10488 return; 10489 } 10490 10491 dirtyComponents.push(component); 10492 10493 if (callback) { 10494 if (component._pendingCallbacks) { 10495 component._pendingCallbacks.push(callback); 10496 } else { 10497 component._pendingCallbacks = [callback]; 10498 } 10499 } 10500 } 10501 10502 var ReactUpdatesInjection = { 10503 injectBatchingStrategy: function(_batchingStrategy) { 10504 ("production" !== "development" ? invariant( 10505 _batchingStrategy, 10506 'ReactUpdates: must provide a batching strategy' 10507 ) : invariant(_batchingStrategy)); 10508 ("production" !== "development" ? invariant( 10509 typeof _batchingStrategy.batchedUpdates === 'function', 10510 'ReactUpdates: must provide a batchedUpdates() function' 10511 ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function')); 10512 ("production" !== "development" ? invariant( 10513 typeof _batchingStrategy.isBatchingUpdates === 'boolean', 10514 'ReactUpdates: must provide an isBatchingUpdates boolean attribute' 10515 ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean')); 10516 batchingStrategy = _batchingStrategy; 10517 } 10518 }; 10519 10520 var ReactUpdates = { 10521 batchedUpdates: batchedUpdates, 10522 enqueueUpdate: enqueueUpdate, 10523 flushBatchedUpdates: flushBatchedUpdates, 10524 injection: ReactUpdatesInjection 10525 }; 10526 10527 module.exports = ReactUpdates; 10528 10529 },{"./invariant":98}],62:[function(require,module,exports){ 10530 /** 10531 * Copyright 2013 Facebook, Inc. 10532 * 10533 * Licensed under the Apache License, Version 2.0 (the "License"); 10534 * you may not use this file except in compliance with the License. 10535 * You may obtain a copy of the License at 10536 * 10537 * http://www.apache.org/licenses/LICENSE-2.0 10538 * 10539 * Unless required by applicable law or agreed to in writing, software 10540 * distributed under the License is distributed on an "AS IS" BASIS, 10541 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10542 * See the License for the specific language governing permissions and 10543 * limitations under the License. 10544 * 10545 * @providesModule SelectEventPlugin 10546 */ 10547 10548 "use strict"; 10549 10550 var EventConstants = require("./EventConstants"); 10551 var EventPluginHub = require("./EventPluginHub"); 10552 var EventPropagators = require("./EventPropagators"); 10553 var ExecutionEnvironment = require("./ExecutionEnvironment"); 10554 var ReactInputSelection = require("./ReactInputSelection"); 10555 var SyntheticEvent = require("./SyntheticEvent"); 10556 10557 var getActiveElement = require("./getActiveElement"); 10558 var isTextInputElement = require("./isTextInputElement"); 10559 var keyOf = require("./keyOf"); 10560 var shallowEqual = require("./shallowEqual"); 10561 10562 var topLevelTypes = EventConstants.topLevelTypes; 10563 10564 var eventTypes = { 10565 select: { 10566 phasedRegistrationNames: { 10567 bubbled: keyOf({onSelect: null}), 10568 captured: keyOf({onSelectCapture: null}) 10569 } 10570 } 10571 }; 10572 10573 var useSelectionChange = false; 10574 10575 if (ExecutionEnvironment.canUseDOM) { 10576 useSelectionChange = 'onselectionchange' in document; 10577 } 10578 10579 var activeElement = null; 10580 var activeElementID = null; 10581 var activeNativeEvent = null; 10582 var lastSelection = null; 10583 var mouseDown = false; 10584 10585 /** 10586 * Get an object which is a unique representation of the current selection. 10587 * 10588 * The return value will not be consistent across nodes or browsers, but 10589 * two identical selections on the same node will return identical objects. 10590 * 10591 * @param {DOMElement} node 10592 * @param {object} 10593 */ 10594 function getSelection(node) { 10595 if ('selectionStart' in node && 10596 ReactInputSelection.hasSelectionCapabilities(node)) { 10597 return { 10598 start: node.selectionStart, 10599 end: node.selectionEnd 10600 }; 10601 } else if (document.selection) { 10602 var range = document.selection.createRange(); 10603 return { 10604 parentElement: range.parentElement(), 10605 text: range.text, 10606 top: range.boundingTop, 10607 left: range.boundingLeft 10608 }; 10609 } else { 10610 var selection = window.getSelection(); 10611 return { 10612 anchorNode: selection.anchorNode, 10613 anchorOffset: selection.anchorOffset, 10614 focusNode: selection.focusNode, 10615 focusOffset: selection.focusOffset 10616 }; 10617 } 10618 } 10619 10620 /** 10621 * Poll selection to see whether it's changed. 10622 * 10623 * @param {object} nativeEvent 10624 * @return {?SyntheticEvent} 10625 */ 10626 function constructSelectEvent(nativeEvent) { 10627 // Ensure we have the right element, and that the user is not dragging a 10628 // selection (this matches native `select` event behavior). 10629 if (mouseDown || activeElement != getActiveElement()) { 10630 return; 10631 } 10632 10633 // Only fire when selection has actually changed. 10634 var currentSelection = getSelection(activeElement); 10635 if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { 10636 lastSelection = currentSelection; 10637 10638 var syntheticEvent = SyntheticEvent.getPooled( 10639 eventTypes.select, 10640 activeElementID, 10641 nativeEvent 10642 ); 10643 10644 syntheticEvent.type = 'select'; 10645 syntheticEvent.target = activeElement; 10646 10647 EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent); 10648 10649 return syntheticEvent; 10650 } 10651 } 10652 10653 /** 10654 * Handle deferred event. And manually dispatch synthetic events. 10655 */ 10656 function dispatchDeferredSelectEvent() { 10657 if (!activeNativeEvent) { 10658 return; 10659 } 10660 10661 var syntheticEvent = constructSelectEvent(activeNativeEvent); 10662 activeNativeEvent = null; 10663 10664 // Enqueue and process the abstract event manually. 10665 if (syntheticEvent) { 10666 EventPluginHub.enqueueEvents(syntheticEvent); 10667 EventPluginHub.processEventQueue(); 10668 } 10669 } 10670 10671 /** 10672 * This plugin creates an `onSelect` event that normalizes select events 10673 * across form elements. 10674 * 10675 * Supported elements are: 10676 * - input (see `isTextInputElement`) 10677 * - textarea 10678 * - contentEditable 10679 * 10680 * This differs from native browser implementations in the following ways: 10681 * - Fires on contentEditable fields as well as inputs. 10682 * - Fires for collapsed selection. 10683 * - Fires after user input. 10684 */ 10685 var SelectEventPlugin = { 10686 10687 eventTypes: eventTypes, 10688 10689 /** 10690 * @param {string} topLevelType Record from `EventConstants`. 10691 * @param {DOMEventTarget} topLevelTarget The listening component root node. 10692 * @param {string} topLevelTargetID ID of `topLevelTarget`. 10693 * @param {object} nativeEvent Native browser event. 10694 * @return {*} An accumulation of synthetic events. 10695 * @see {EventPluginHub.extractEvents} 10696 */ 10697 extractEvents: function( 10698 topLevelType, 10699 topLevelTarget, 10700 topLevelTargetID, 10701 nativeEvent) { 10702 10703 switch (topLevelType) { 10704 // Track the input node that has focus. 10705 case topLevelTypes.topFocus: 10706 if (isTextInputElement(topLevelTarget) || 10707 topLevelTarget.contentEditable === 'true') { 10708 activeElement = topLevelTarget; 10709 activeElementID = topLevelTargetID; 10710 lastSelection = null; 10711 } 10712 break; 10713 case topLevelTypes.topBlur: 10714 activeElement = null; 10715 activeElementID = null; 10716 lastSelection = null; 10717 break; 10718 10719 // Don't fire the event while the user is dragging. This matches the 10720 // semantics of the native select event. 10721 case topLevelTypes.topMouseDown: 10722 mouseDown = true; 10723 break; 10724 case topLevelTypes.topContextMenu: 10725 case topLevelTypes.topMouseUp: 10726 mouseDown = false; 10727 return constructSelectEvent(nativeEvent); 10728 10729 // Chrome and IE fire non-standard event when selection is changed (and 10730 // sometimes when it hasn't). 10731 case topLevelTypes.topSelectionChange: 10732 return constructSelectEvent(nativeEvent); 10733 10734 // Firefox doesn't support selectionchange, so check selection status 10735 // after each key entry. 10736 case topLevelTypes.topKeyDown: 10737 if (!useSelectionChange) { 10738 activeNativeEvent = nativeEvent; 10739 setTimeout(dispatchDeferredSelectEvent, 0); 10740 } 10741 break; 10742 } 10743 } 10744 }; 10745 10746 module.exports = SelectEventPlugin; 10747 10748 },{"./EventConstants":14,"./EventPluginHub":16,"./EventPropagators":19,"./ExecutionEnvironment":20,"./ReactInputSelection":47,"./SyntheticEvent":66,"./getActiveElement":90,"./isTextInputElement":101,"./keyOf":105,"./shallowEqual":115}],63:[function(require,module,exports){ 10749 /** 10750 * Copyright 2013 Facebook, Inc. 10751 * 10752 * Licensed under the Apache License, Version 2.0 (the "License"); 10753 * you may not use this file except in compliance with the License. 10754 * You may obtain a copy of the License at 10755 * 10756 * http://www.apache.org/licenses/LICENSE-2.0 10757 * 10758 * Unless required by applicable law or agreed to in writing, software 10759 * distributed under the License is distributed on an "AS IS" BASIS, 10760 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10761 * See the License for the specific language governing permissions and 10762 * limitations under the License. 10763 * 10764 * @providesModule SimpleEventPlugin 10765 */ 10766 10767 "use strict"; 10768 10769 var EventConstants = require("./EventConstants"); 10770 var EventPropagators = require("./EventPropagators"); 10771 var SyntheticClipboardEvent = require("./SyntheticClipboardEvent"); 10772 var SyntheticEvent = require("./SyntheticEvent"); 10773 var SyntheticFocusEvent = require("./SyntheticFocusEvent"); 10774 var SyntheticKeyboardEvent = require("./SyntheticKeyboardEvent"); 10775 var SyntheticMouseEvent = require("./SyntheticMouseEvent"); 10776 var SyntheticTouchEvent = require("./SyntheticTouchEvent"); 10777 var SyntheticUIEvent = require("./SyntheticUIEvent"); 10778 var SyntheticWheelEvent = require("./SyntheticWheelEvent"); 10779 10780 var invariant = require("./invariant"); 10781 var keyOf = require("./keyOf"); 10782 10783 var topLevelTypes = EventConstants.topLevelTypes; 10784 10785 var eventTypes = { 10786 blur: { 10787 phasedRegistrationNames: { 10788 bubbled: keyOf({onBlur: true}), 10789 captured: keyOf({onBlurCapture: true}) 10790 } 10791 }, 10792 click: { 10793 phasedRegistrationNames: { 10794 bubbled: keyOf({onClick: true}), 10795 captured: keyOf({onClickCapture: true}) 10796 } 10797 }, 10798 contextMenu: { 10799 phasedRegistrationNames: { 10800 bubbled: keyOf({onContextMenu: true}), 10801 captured: keyOf({onContextMenuCapture: true}) 10802 } 10803 }, 10804 copy: { 10805 phasedRegistrationNames: { 10806 bubbled: keyOf({onCopy: true}), 10807 captured: keyOf({onCopyCapture: true}) 10808 } 10809 }, 10810 cut: { 10811 phasedRegistrationNames: { 10812 bubbled: keyOf({onCut: true}), 10813 captured: keyOf({onCutCapture: true}) 10814 } 10815 }, 10816 doubleClick: { 10817 phasedRegistrationNames: { 10818 bubbled: keyOf({onDoubleClick: true}), 10819 captured: keyOf({onDoubleClickCapture: true}) 10820 } 10821 }, 10822 drag: { 10823 phasedRegistrationNames: { 10824 bubbled: keyOf({onDrag: true}), 10825 captured: keyOf({onDragCapture: true}) 10826 } 10827 }, 10828 dragEnd: { 10829 phasedRegistrationNames: { 10830 bubbled: keyOf({onDragEnd: true}), 10831 captured: keyOf({onDragEndCapture: true}) 10832 } 10833 }, 10834 dragEnter: { 10835 phasedRegistrationNames: { 10836 bubbled: keyOf({onDragEnter: true}), 10837 captured: keyOf({onDragEnterCapture: true}) 10838 } 10839 }, 10840 dragExit: { 10841 phasedRegistrationNames: { 10842 bubbled: keyOf({onDragExit: true}), 10843 captured: keyOf({onDragExitCapture: true}) 10844 } 10845 }, 10846 dragLeave: { 10847 phasedRegistrationNames: { 10848 bubbled: keyOf({onDragLeave: true}), 10849 captured: keyOf({onDragLeaveCapture: true}) 10850 } 10851 }, 10852 dragOver: { 10853 phasedRegistrationNames: { 10854 bubbled: keyOf({onDragOver: true}), 10855 captured: keyOf({onDragOverCapture: true}) 10856 } 10857 }, 10858 dragStart: { 10859 phasedRegistrationNames: { 10860 bubbled: keyOf({onDragStart: true}), 10861 captured: keyOf({onDragStartCapture: true}) 10862 } 10863 }, 10864 drop: { 10865 phasedRegistrationNames: { 10866 bubbled: keyOf({onDrop: true}), 10867 captured: keyOf({onDropCapture: true}) 10868 } 10869 }, 10870 focus: { 10871 phasedRegistrationNames: { 10872 bubbled: keyOf({onFocus: true}), 10873 captured: keyOf({onFocusCapture: true}) 10874 } 10875 }, 10876 input: { 10877 phasedRegistrationNames: { 10878 bubbled: keyOf({onInput: true}), 10879 captured: keyOf({onInputCapture: true}) 10880 } 10881 }, 10882 keyDown: { 10883 phasedRegistrationNames: { 10884 bubbled: keyOf({onKeyDown: true}), 10885 captured: keyOf({onKeyDownCapture: true}) 10886 } 10887 }, 10888 keyPress: { 10889 phasedRegistrationNames: { 10890 bubbled: keyOf({onKeyPress: true}), 10891 captured: keyOf({onKeyPressCapture: true}) 10892 } 10893 }, 10894 keyUp: { 10895 phasedRegistrationNames: { 10896 bubbled: keyOf({onKeyUp: true}), 10897 captured: keyOf({onKeyUpCapture: true}) 10898 } 10899 }, 10900 // Note: We do not allow listening to mouseOver events. Instead, use the 10901 // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`. 10902 mouseDown: { 10903 phasedRegistrationNames: { 10904 bubbled: keyOf({onMouseDown: true}), 10905 captured: keyOf({onMouseDownCapture: true}) 10906 } 10907 }, 10908 mouseMove: { 10909 phasedRegistrationNames: { 10910 bubbled: keyOf({onMouseMove: true}), 10911 captured: keyOf({onMouseMoveCapture: true}) 10912 } 10913 }, 10914 mouseUp: { 10915 phasedRegistrationNames: { 10916 bubbled: keyOf({onMouseUp: true}), 10917 captured: keyOf({onMouseUpCapture: true}) 10918 } 10919 }, 10920 paste: { 10921 phasedRegistrationNames: { 10922 bubbled: keyOf({onPaste: true}), 10923 captured: keyOf({onPasteCapture: true}) 10924 } 10925 }, 10926 scroll: { 10927 phasedRegistrationNames: { 10928 bubbled: keyOf({onScroll: true}), 10929 captured: keyOf({onScrollCapture: true}) 10930 } 10931 }, 10932 submit: { 10933 phasedRegistrationNames: { 10934 bubbled: keyOf({onSubmit: true}), 10935 captured: keyOf({onSubmitCapture: true}) 10936 } 10937 }, 10938 touchCancel: { 10939 phasedRegistrationNames: { 10940 bubbled: keyOf({onTouchCancel: true}), 10941 captured: keyOf({onTouchCancelCapture: true}) 10942 } 10943 }, 10944 touchEnd: { 10945 phasedRegistrationNames: { 10946 bubbled: keyOf({onTouchEnd: true}), 10947 captured: keyOf({onTouchEndCapture: true}) 10948 } 10949 }, 10950 touchMove: { 10951 phasedRegistrationNames: { 10952 bubbled: keyOf({onTouchMove: true}), 10953 captured: keyOf({onTouchMoveCapture: true}) 10954 } 10955 }, 10956 touchStart: { 10957 phasedRegistrationNames: { 10958 bubbled: keyOf({onTouchStart: true}), 10959 captured: keyOf({onTouchStartCapture: true}) 10960 } 10961 }, 10962 wheel: { 10963 phasedRegistrationNames: { 10964 bubbled: keyOf({onWheel: true}), 10965 captured: keyOf({onWheelCapture: true}) 10966 } 10967 } 10968 }; 10969 10970 var topLevelEventsToDispatchConfig = { 10971 topBlur: eventTypes.blur, 10972 topClick: eventTypes.click, 10973 topContextMenu: eventTypes.contextMenu, 10974 topCopy: eventTypes.copy, 10975 topCut: eventTypes.cut, 10976 topDoubleClick: eventTypes.doubleClick, 10977 topDrag: eventTypes.drag, 10978 topDragEnd: eventTypes.dragEnd, 10979 topDragEnter: eventTypes.dragEnter, 10980 topDragExit: eventTypes.dragExit, 10981 topDragLeave: eventTypes.dragLeave, 10982 topDragOver: eventTypes.dragOver, 10983 topDragStart: eventTypes.dragStart, 10984 topDrop: eventTypes.drop, 10985 topFocus: eventTypes.focus, 10986 topInput: eventTypes.input, 10987 topKeyDown: eventTypes.keyDown, 10988 topKeyPress: eventTypes.keyPress, 10989 topKeyUp: eventTypes.keyUp, 10990 topMouseDown: eventTypes.mouseDown, 10991 topMouseMove: eventTypes.mouseMove, 10992 topMouseUp: eventTypes.mouseUp, 10993 topPaste: eventTypes.paste, 10994 topScroll: eventTypes.scroll, 10995 topSubmit: eventTypes.submit, 10996 topTouchCancel: eventTypes.touchCancel, 10997 topTouchEnd: eventTypes.touchEnd, 10998 topTouchMove: eventTypes.touchMove, 10999 topTouchStart: eventTypes.touchStart, 11000 topWheel: eventTypes.wheel 11001 }; 11002 11003 var SimpleEventPlugin = { 11004 11005 eventTypes: eventTypes, 11006 11007 /** 11008 * Same as the default implementation, except cancels the event when return 11009 * value is false. 11010 * 11011 * @param {object} Event to be dispatched. 11012 * @param {function} Application-level callback. 11013 * @param {string} domID DOM ID to pass to the callback. 11014 */ 11015 executeDispatch: function(event, listener, domID) { 11016 var returnValue = listener(event, domID); 11017 if (returnValue === false) { 11018 event.stopPropagation(); 11019 event.preventDefault(); 11020 } 11021 }, 11022 11023 /** 11024 * @param {string} topLevelType Record from `EventConstants`. 11025 * @param {DOMEventTarget} topLevelTarget The listening component root node. 11026 * @param {string} topLevelTargetID ID of `topLevelTarget`. 11027 * @param {object} nativeEvent Native browser event. 11028 * @return {*} An accumulation of synthetic events. 11029 * @see {EventPluginHub.extractEvents} 11030 */ 11031 extractEvents: function( 11032 topLevelType, 11033 topLevelTarget, 11034 topLevelTargetID, 11035 nativeEvent) { 11036 var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; 11037 if (!dispatchConfig) { 11038 return null; 11039 } 11040 var EventConstructor; 11041 switch(topLevelType) { 11042 case topLevelTypes.topInput: 11043 case topLevelTypes.topSubmit: 11044 // HTML Events 11045 // @see http://www.w3.org/TR/html5/index.html#events-0 11046 EventConstructor = SyntheticEvent; 11047 break; 11048 case topLevelTypes.topKeyDown: 11049 case topLevelTypes.topKeyPress: 11050 case topLevelTypes.topKeyUp: 11051 EventConstructor = SyntheticKeyboardEvent; 11052 break; 11053 case topLevelTypes.topBlur: 11054 case topLevelTypes.topFocus: 11055 EventConstructor = SyntheticFocusEvent; 11056 break; 11057 case topLevelTypes.topClick: 11058 // Firefox creates a click event on right mouse clicks. This removes the 11059 // unwanted click events. 11060 if (nativeEvent.button === 2) { 11061 return null; 11062 } 11063 /* falls through */ 11064 case topLevelTypes.topContextMenu: 11065 case topLevelTypes.topDoubleClick: 11066 case topLevelTypes.topDrag: 11067 case topLevelTypes.topDragEnd: 11068 case topLevelTypes.topDragEnter: 11069 case topLevelTypes.topDragExit: 11070 case topLevelTypes.topDragLeave: 11071 case topLevelTypes.topDragOver: 11072 case topLevelTypes.topDragStart: 11073 case topLevelTypes.topDrop: 11074 case topLevelTypes.topMouseDown: 11075 case topLevelTypes.topMouseMove: 11076 case topLevelTypes.topMouseUp: 11077 EventConstructor = SyntheticMouseEvent; 11078 break; 11079 case topLevelTypes.topTouchCancel: 11080 case topLevelTypes.topTouchEnd: 11081 case topLevelTypes.topTouchMove: 11082 case topLevelTypes.topTouchStart: 11083 EventConstructor = SyntheticTouchEvent; 11084 break; 11085 case topLevelTypes.topScroll: 11086 EventConstructor = SyntheticUIEvent; 11087 break; 11088 case topLevelTypes.topWheel: 11089 EventConstructor = SyntheticWheelEvent; 11090 break; 11091 case topLevelTypes.topCopy: 11092 case topLevelTypes.topCut: 11093 case topLevelTypes.topPaste: 11094 EventConstructor = SyntheticClipboardEvent; 11095 break; 11096 } 11097 ("production" !== "development" ? invariant( 11098 EventConstructor, 11099 'SimpleEventPlugin: Unhandled event type, `%s`.', 11100 topLevelType 11101 ) : invariant(EventConstructor)); 11102 var event = EventConstructor.getPooled( 11103 dispatchConfig, 11104 topLevelTargetID, 11105 nativeEvent 11106 ); 11107 EventPropagators.accumulateTwoPhaseDispatches(event); 11108 return event; 11109 } 11110 11111 }; 11112 11113 module.exports = SimpleEventPlugin; 11114 11115 },{"./EventConstants":14,"./EventPropagators":19,"./SyntheticClipboardEvent":64,"./SyntheticEvent":66,"./SyntheticFocusEvent":67,"./SyntheticKeyboardEvent":68,"./SyntheticMouseEvent":69,"./SyntheticTouchEvent":70,"./SyntheticUIEvent":71,"./SyntheticWheelEvent":72,"./invariant":98,"./keyOf":105}],64:[function(require,module,exports){ 11116 /** 11117 * Copyright 2013 Facebook, Inc. 11118 * 11119 * Licensed under the Apache License, Version 2.0 (the "License"); 11120 * you may not use this file except in compliance with the License. 11121 * You may obtain a copy of the License at 11122 * 11123 * http://www.apache.org/licenses/LICENSE-2.0 11124 * 11125 * Unless required by applicable law or agreed to in writing, software 11126 * distributed under the License is distributed on an "AS IS" BASIS, 11127 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11128 * See the License for the specific language governing permissions and 11129 * limitations under the License. 11130 * 11131 * @providesModule SyntheticClipboardEvent 11132 * @typechecks static-only 11133 */ 11134 11135 "use strict"; 11136 11137 var SyntheticEvent = require("./SyntheticEvent"); 11138 11139 /** 11140 * @interface Event 11141 * @see http://www.w3.org/TR/clipboard-apis/ 11142 */ 11143 var ClipboardEventInterface = { 11144 clipboardData: null 11145 }; 11146 11147 /** 11148 * @param {object} dispatchConfig Configuration used to dispatch this event. 11149 * @param {string} dispatchMarker Marker identifying the event target. 11150 * @param {object} nativeEvent Native browser event. 11151 * @extends {SyntheticUIEvent} 11152 */ 11153 function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11154 SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11155 } 11156 11157 SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); 11158 11159 module.exports = SyntheticClipboardEvent; 11160 11161 11162 },{"./SyntheticEvent":66}],65:[function(require,module,exports){ 11163 /** 11164 * Copyright 2013 Facebook, Inc. 11165 * 11166 * Licensed under the Apache License, Version 2.0 (the "License"); 11167 * you may not use this file except in compliance with the License. 11168 * You may obtain a copy of the License at 11169 * 11170 * http://www.apache.org/licenses/LICENSE-2.0 11171 * 11172 * Unless required by applicable law or agreed to in writing, software 11173 * distributed under the License is distributed on an "AS IS" BASIS, 11174 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11175 * See the License for the specific language governing permissions and 11176 * limitations under the License. 11177 * 11178 * @providesModule SyntheticCompositionEvent 11179 * @typechecks static-only 11180 */ 11181 11182 "use strict"; 11183 11184 var SyntheticEvent = require("./SyntheticEvent"); 11185 11186 /** 11187 * @interface Event 11188 * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents 11189 */ 11190 var CompositionEventInterface = { 11191 data: null 11192 }; 11193 11194 /** 11195 * @param {object} dispatchConfig Configuration used to dispatch this event. 11196 * @param {string} dispatchMarker Marker identifying the event target. 11197 * @param {object} nativeEvent Native browser event. 11198 * @extends {SyntheticUIEvent} 11199 */ 11200 function SyntheticCompositionEvent( 11201 dispatchConfig, 11202 dispatchMarker, 11203 nativeEvent) { 11204 SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11205 } 11206 11207 SyntheticEvent.augmentClass( 11208 SyntheticCompositionEvent, 11209 CompositionEventInterface 11210 ); 11211 11212 module.exports = SyntheticCompositionEvent; 11213 11214 11215 },{"./SyntheticEvent":66}],66:[function(require,module,exports){ 11216 /** 11217 * Copyright 2013 Facebook, Inc. 11218 * 11219 * Licensed under the Apache License, Version 2.0 (the "License"); 11220 * you may not use this file except in compliance with the License. 11221 * You may obtain a copy of the License at 11222 * 11223 * http://www.apache.org/licenses/LICENSE-2.0 11224 * 11225 * Unless required by applicable law or agreed to in writing, software 11226 * distributed under the License is distributed on an "AS IS" BASIS, 11227 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11228 * See the License for the specific language governing permissions and 11229 * limitations under the License. 11230 * 11231 * @providesModule SyntheticEvent 11232 * @typechecks static-only 11233 */ 11234 11235 "use strict"; 11236 11237 var PooledClass = require("./PooledClass"); 11238 11239 var emptyFunction = require("./emptyFunction"); 11240 var getEventTarget = require("./getEventTarget"); 11241 var merge = require("./merge"); 11242 var mergeInto = require("./mergeInto"); 11243 11244 /** 11245 * @interface Event 11246 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11247 */ 11248 var EventInterface = { 11249 type: null, 11250 target: getEventTarget, 11251 currentTarget: null, 11252 eventPhase: null, 11253 bubbles: null, 11254 cancelable: null, 11255 timeStamp: function(event) { 11256 return event.timeStamp || Date.now(); 11257 }, 11258 defaultPrevented: null, 11259 isTrusted: null 11260 }; 11261 11262 /** 11263 * Synthetic events are dispatched by event plugins, typically in response to a 11264 * top-level event delegation handler. 11265 * 11266 * These systems should generally use pooling to reduce the frequency of garbage 11267 * collection. The system should check `isPersistent` to determine whether the 11268 * event should be released into the pool after being dispatched. Users that 11269 * need a persisted event should invoke `persist`. 11270 * 11271 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by 11272 * normalizing browser quirks. Subclasses do not necessarily have to implement a 11273 * DOM interface; custom application-specific events can also subclass this. 11274 * 11275 * @param {object} dispatchConfig Configuration used to dispatch this event. 11276 * @param {string} dispatchMarker Marker identifying the event target. 11277 * @param {object} nativeEvent Native browser event. 11278 */ 11279 function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11280 this.dispatchConfig = dispatchConfig; 11281 this.dispatchMarker = dispatchMarker; 11282 this.nativeEvent = nativeEvent; 11283 11284 var Interface = this.constructor.Interface; 11285 for (var propName in Interface) { 11286 if (!Interface.hasOwnProperty(propName)) { 11287 continue; 11288 } 11289 var normalize = Interface[propName]; 11290 if (normalize) { 11291 this[propName] = normalize(nativeEvent); 11292 } else { 11293 this[propName] = nativeEvent[propName]; 11294 } 11295 } 11296 11297 var defaultPrevented = nativeEvent.defaultPrevented != null ? 11298 nativeEvent.defaultPrevented : 11299 nativeEvent.returnValue === false; 11300 if (defaultPrevented) { 11301 this.isDefaultPrevented = emptyFunction.thatReturnsTrue; 11302 } else { 11303 this.isDefaultPrevented = emptyFunction.thatReturnsFalse; 11304 } 11305 this.isPropagationStopped = emptyFunction.thatReturnsFalse; 11306 } 11307 11308 mergeInto(SyntheticEvent.prototype, { 11309 11310 preventDefault: function() { 11311 this.defaultPrevented = true; 11312 var event = this.nativeEvent; 11313 event.preventDefault ? event.preventDefault() : event.returnValue = false; 11314 this.isDefaultPrevented = emptyFunction.thatReturnsTrue; 11315 }, 11316 11317 stopPropagation: function() { 11318 var event = this.nativeEvent; 11319 event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; 11320 this.isPropagationStopped = emptyFunction.thatReturnsTrue; 11321 }, 11322 11323 /** 11324 * We release all dispatched `SyntheticEvent`s after each event loop, adding 11325 * them back into the pool. This allows a way to hold onto a reference that 11326 * won't be added back into the pool. 11327 */ 11328 persist: function() { 11329 this.isPersistent = emptyFunction.thatReturnsTrue; 11330 }, 11331 11332 /** 11333 * Checks if this event should be released back into the pool. 11334 * 11335 * @return {boolean} True if this should not be released, false otherwise. 11336 */ 11337 isPersistent: emptyFunction.thatReturnsFalse, 11338 11339 /** 11340 * `PooledClass` looks for `destructor` on each instance it releases. 11341 */ 11342 destructor: function() { 11343 var Interface = this.constructor.Interface; 11344 for (var propName in Interface) { 11345 this[propName] = null; 11346 } 11347 this.dispatchConfig = null; 11348 this.dispatchMarker = null; 11349 this.nativeEvent = null; 11350 } 11351 11352 }); 11353 11354 SyntheticEvent.Interface = EventInterface; 11355 11356 /** 11357 * Helper to reduce boilerplate when creating subclasses. 11358 * 11359 * @param {function} Class 11360 * @param {?object} Interface 11361 */ 11362 SyntheticEvent.augmentClass = function(Class, Interface) { 11363 var Super = this; 11364 11365 var prototype = Object.create(Super.prototype); 11366 mergeInto(prototype, Class.prototype); 11367 Class.prototype = prototype; 11368 Class.prototype.constructor = Class; 11369 11370 Class.Interface = merge(Super.Interface, Interface); 11371 Class.augmentClass = Super.augmentClass; 11372 11373 PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler); 11374 }; 11375 11376 PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler); 11377 11378 module.exports = SyntheticEvent; 11379 11380 },{"./PooledClass":23,"./emptyFunction":83,"./getEventTarget":91,"./merge":107,"./mergeInto":109}],67:[function(require,module,exports){ 11381 /** 11382 * Copyright 2013 Facebook, Inc. 11383 * 11384 * Licensed under the Apache License, Version 2.0 (the "License"); 11385 * you may not use this file except in compliance with the License. 11386 * You may obtain a copy of the License at 11387 * 11388 * http://www.apache.org/licenses/LICENSE-2.0 11389 * 11390 * Unless required by applicable law or agreed to in writing, software 11391 * distributed under the License is distributed on an "AS IS" BASIS, 11392 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11393 * See the License for the specific language governing permissions and 11394 * limitations under the License. 11395 * 11396 * @providesModule SyntheticFocusEvent 11397 * @typechecks static-only 11398 */ 11399 11400 "use strict"; 11401 11402 var SyntheticUIEvent = require("./SyntheticUIEvent"); 11403 11404 /** 11405 * @interface FocusEvent 11406 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11407 */ 11408 var FocusEventInterface = { 11409 relatedTarget: null 11410 }; 11411 11412 /** 11413 * @param {object} dispatchConfig Configuration used to dispatch this event. 11414 * @param {string} dispatchMarker Marker identifying the event target. 11415 * @param {object} nativeEvent Native browser event. 11416 * @extends {SyntheticUIEvent} 11417 */ 11418 function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11419 SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11420 } 11421 11422 SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface); 11423 11424 module.exports = SyntheticFocusEvent; 11425 11426 },{"./SyntheticUIEvent":71}],68:[function(require,module,exports){ 11427 /** 11428 * Copyright 2013 Facebook, Inc. 11429 * 11430 * Licensed under the Apache License, Version 2.0 (the "License"); 11431 * you may not use this file except in compliance with the License. 11432 * You may obtain a copy of the License at 11433 * 11434 * http://www.apache.org/licenses/LICENSE-2.0 11435 * 11436 * Unless required by applicable law or agreed to in writing, software 11437 * distributed under the License is distributed on an "AS IS" BASIS, 11438 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11439 * See the License for the specific language governing permissions and 11440 * limitations under the License. 11441 * 11442 * @providesModule SyntheticKeyboardEvent 11443 * @typechecks static-only 11444 */ 11445 11446 "use strict"; 11447 11448 var SyntheticUIEvent = require("./SyntheticUIEvent"); 11449 11450 /** 11451 * @interface KeyboardEvent 11452 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11453 */ 11454 var KeyboardEventInterface = { 11455 'char': null, 11456 key: null, 11457 location: null, 11458 ctrlKey: null, 11459 shiftKey: null, 11460 altKey: null, 11461 metaKey: null, 11462 repeat: null, 11463 locale: null, 11464 // Legacy Interface 11465 charCode: null, 11466 keyCode: null, 11467 which: null 11468 }; 11469 11470 /** 11471 * @param {object} dispatchConfig Configuration used to dispatch this event. 11472 * @param {string} dispatchMarker Marker identifying the event target. 11473 * @param {object} nativeEvent Native browser event. 11474 * @extends {SyntheticUIEvent} 11475 */ 11476 function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11477 SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11478 } 11479 11480 SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); 11481 11482 module.exports = SyntheticKeyboardEvent; 11483 11484 },{"./SyntheticUIEvent":71}],69:[function(require,module,exports){ 11485 /** 11486 * Copyright 2013 Facebook, Inc. 11487 * 11488 * Licensed under the Apache License, Version 2.0 (the "License"); 11489 * you may not use this file except in compliance with the License. 11490 * You may obtain a copy of the License at 11491 * 11492 * http://www.apache.org/licenses/LICENSE-2.0 11493 * 11494 * Unless required by applicable law or agreed to in writing, software 11495 * distributed under the License is distributed on an "AS IS" BASIS, 11496 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11497 * See the License for the specific language governing permissions and 11498 * limitations under the License. 11499 * 11500 * @providesModule SyntheticMouseEvent 11501 * @typechecks static-only 11502 */ 11503 11504 "use strict"; 11505 11506 var SyntheticUIEvent = require("./SyntheticUIEvent"); 11507 var ViewportMetrics = require("./ViewportMetrics"); 11508 11509 /** 11510 * @interface MouseEvent 11511 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11512 */ 11513 var MouseEventInterface = { 11514 screenX: null, 11515 screenY: null, 11516 clientX: null, 11517 clientY: null, 11518 ctrlKey: null, 11519 shiftKey: null, 11520 altKey: null, 11521 metaKey: null, 11522 button: function(event) { 11523 // Webkit, Firefox, IE9+ 11524 // which: 1 2 3 11525 // button: 0 1 2 (standard) 11526 var button = event.button; 11527 if ('which' in event) { 11528 return button; 11529 } 11530 // IE<9 11531 // which: undefined 11532 // button: 0 0 0 11533 // button: 1 4 2 (onmouseup) 11534 return button === 2 ? 2 : button === 4 ? 1 : 0; 11535 }, 11536 buttons: null, 11537 relatedTarget: function(event) { 11538 return event.relatedTarget || ( 11539 event.fromElement === event.srcElement ? 11540 event.toElement : 11541 event.fromElement 11542 ); 11543 }, 11544 // "Proprietary" Interface. 11545 pageX: function(event) { 11546 return 'pageX' in event ? 11547 event.pageX : 11548 event.clientX + ViewportMetrics.currentScrollLeft; 11549 }, 11550 pageY: function(event) { 11551 return 'pageY' in event ? 11552 event.pageY : 11553 event.clientY + ViewportMetrics.currentScrollTop; 11554 } 11555 }; 11556 11557 /** 11558 * @param {object} dispatchConfig Configuration used to dispatch this event. 11559 * @param {string} dispatchMarker Marker identifying the event target. 11560 * @param {object} nativeEvent Native browser event. 11561 * @extends {SyntheticUIEvent} 11562 */ 11563 function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11564 SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11565 } 11566 11567 SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface); 11568 11569 module.exports = SyntheticMouseEvent; 11570 11571 },{"./SyntheticUIEvent":71,"./ViewportMetrics":74}],70:[function(require,module,exports){ 11572 /** 11573 * Copyright 2013 Facebook, Inc. 11574 * 11575 * Licensed under the Apache License, Version 2.0 (the "License"); 11576 * you may not use this file except in compliance with the License. 11577 * You may obtain a copy of the License at 11578 * 11579 * http://www.apache.org/licenses/LICENSE-2.0 11580 * 11581 * Unless required by applicable law or agreed to in writing, software 11582 * distributed under the License is distributed on an "AS IS" BASIS, 11583 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11584 * See the License for the specific language governing permissions and 11585 * limitations under the License. 11586 * 11587 * @providesModule SyntheticTouchEvent 11588 * @typechecks static-only 11589 */ 11590 11591 "use strict"; 11592 11593 var SyntheticUIEvent = require("./SyntheticUIEvent"); 11594 11595 /** 11596 * @interface TouchEvent 11597 * @see http://www.w3.org/TR/touch-events/ 11598 */ 11599 var TouchEventInterface = { 11600 touches: null, 11601 targetTouches: null, 11602 changedTouches: null, 11603 altKey: null, 11604 metaKey: null, 11605 ctrlKey: null, 11606 shiftKey: null 11607 }; 11608 11609 /** 11610 * @param {object} dispatchConfig Configuration used to dispatch this event. 11611 * @param {string} dispatchMarker Marker identifying the event target. 11612 * @param {object} nativeEvent Native browser event. 11613 * @extends {SyntheticUIEvent} 11614 */ 11615 function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11616 SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11617 } 11618 11619 SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface); 11620 11621 module.exports = SyntheticTouchEvent; 11622 11623 },{"./SyntheticUIEvent":71}],71:[function(require,module,exports){ 11624 /** 11625 * Copyright 2013 Facebook, Inc. 11626 * 11627 * Licensed under the Apache License, Version 2.0 (the "License"); 11628 * you may not use this file except in compliance with the License. 11629 * You may obtain a copy of the License at 11630 * 11631 * http://www.apache.org/licenses/LICENSE-2.0 11632 * 11633 * Unless required by applicable law or agreed to in writing, software 11634 * distributed under the License is distributed on an "AS IS" BASIS, 11635 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11636 * See the License for the specific language governing permissions and 11637 * limitations under the License. 11638 * 11639 * @providesModule SyntheticUIEvent 11640 * @typechecks static-only 11641 */ 11642 11643 "use strict"; 11644 11645 var SyntheticEvent = require("./SyntheticEvent"); 11646 11647 /** 11648 * @interface UIEvent 11649 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11650 */ 11651 var UIEventInterface = { 11652 view: null, 11653 detail: null 11654 }; 11655 11656 /** 11657 * @param {object} dispatchConfig Configuration used to dispatch this event. 11658 * @param {string} dispatchMarker Marker identifying the event target. 11659 * @param {object} nativeEvent Native browser event. 11660 * @extends {SyntheticEvent} 11661 */ 11662 function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11663 SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11664 } 11665 11666 SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface); 11667 11668 module.exports = SyntheticUIEvent; 11669 11670 },{"./SyntheticEvent":66}],72:[function(require,module,exports){ 11671 /** 11672 * Copyright 2013 Facebook, Inc. 11673 * 11674 * Licensed under the Apache License, Version 2.0 (the "License"); 11675 * you may not use this file except in compliance with the License. 11676 * You may obtain a copy of the License at 11677 * 11678 * http://www.apache.org/licenses/LICENSE-2.0 11679 * 11680 * Unless required by applicable law or agreed to in writing, software 11681 * distributed under the License is distributed on an "AS IS" BASIS, 11682 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11683 * See the License for the specific language governing permissions and 11684 * limitations under the License. 11685 * 11686 * @providesModule SyntheticWheelEvent 11687 * @typechecks static-only 11688 */ 11689 11690 "use strict"; 11691 11692 var SyntheticMouseEvent = require("./SyntheticMouseEvent"); 11693 11694 /** 11695 * @interface WheelEvent 11696 * @see http://www.w3.org/TR/DOM-Level-3-Events/ 11697 */ 11698 var WheelEventInterface = { 11699 deltaX: function(event) { 11700 // NOTE: IE<9 does not support x-axis delta. 11701 return ( 11702 'deltaX' in event ? event.deltaX : 11703 // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). 11704 'wheelDeltaX' in event ? -event.wheelDeltaX : 0 11705 ); 11706 }, 11707 deltaY: function(event) { 11708 return ( 11709 // Normalize (up is positive). 11710 'deltaY' in event ? -event.deltaY : 11711 // Fallback to `wheelDeltaY` for Webkit. 11712 'wheelDeltaY' in event ? event.wheelDeltaY : 11713 // Fallback to `wheelDelta` for IE<9. 11714 'wheelDelta' in event ? event.wheelDelta : 0 11715 ); 11716 }, 11717 deltaZ: null, 11718 deltaMode: null 11719 }; 11720 11721 /** 11722 * @param {object} dispatchConfig Configuration used to dispatch this event. 11723 * @param {string} dispatchMarker Marker identifying the event target. 11724 * @param {object} nativeEvent Native browser event. 11725 * @extends {SyntheticMouseEvent} 11726 */ 11727 function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) { 11728 SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); 11729 } 11730 11731 SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface); 11732 11733 module.exports = SyntheticWheelEvent; 11734 11735 },{"./SyntheticMouseEvent":69}],73:[function(require,module,exports){ 11736 /** 11737 * Copyright 2013 Facebook, Inc. 11738 * 11739 * Licensed under the Apache License, Version 2.0 (the "License"); 11740 * you may not use this file except in compliance with the License. 11741 * You may obtain a copy of the License at 11742 * 11743 * http://www.apache.org/licenses/LICENSE-2.0 11744 * 11745 * Unless required by applicable law or agreed to in writing, software 11746 * distributed under the License is distributed on an "AS IS" BASIS, 11747 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11748 * See the License for the specific language governing permissions and 11749 * limitations under the License. 11750 * 11751 * @providesModule Transaction 11752 */ 11753 11754 "use strict"; 11755 11756 var invariant = require("./invariant"); 11757 11758 /** 11759 * `Transaction` creates a black box that is able to wrap any method such that 11760 * certain invariants are maintained before and after the method is invoked 11761 * (Even if an exception is thrown while invoking the wrapped method). Whoever 11762 * instantiates a transaction can provide enforcers of the invariants at 11763 * creation time. The `Transaction` class itself will supply one additional 11764 * automatic invariant for you - the invariant that any transaction instance 11765 * should not be ran while it is already being ran. You would typically create a 11766 * single instance of a `Transaction` for reuse multiple times, that potentially 11767 * is used to wrap several different methods. Wrappers are extremely simple - 11768 * they only require implementing two methods. 11769 * 11770 * <pre> 11771 * wrappers (injected at creation time) 11772 * + + 11773 * | | 11774 * +-----------------|--------|--------------+ 11775 * | v | | 11776 * | +---------------+ | | 11777 * | +--| wrapper1 |---|----+ | 11778 * | | +---------------+ v | | 11779 * | | +-------------+ | | 11780 * | | +----| wrapper2 |--------+ | 11781 * | | | +-------------+ | | | 11782 * | | | | | | 11783 * | v v v v | wrapper 11784 * | +---+ +---+ +---------+ +---+ +---+ | invariants 11785 * perform(anyMethod) | | | | | | | | | | | | maintained 11786 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|--------> 11787 * | | | | | | | | | | | | 11788 * | | | | | | | | | | | | 11789 * | | | | | | | | | | | | 11790 * | +---+ +---+ +---------+ +---+ +---+ | 11791 * | initialize close | 11792 * +-----------------------------------------+ 11793 * </pre> 11794 * 11795 * Bonus: 11796 * - Reports timing metrics by method name and wrapper index. 11797 * 11798 * Use cases: 11799 * - Preserving the input selection ranges before/after reconciliation. 11800 * Restoring selection even in the event of an unexpected error. 11801 * - Deactivating events while rearranging the DOM, preventing blurs/focuses, 11802 * while guaranteeing that afterwards, the event system is reactivated. 11803 * - Flushing a queue of collected DOM mutations to the main UI thread after a 11804 * reconciliation takes place in a worker thread. 11805 * - Invoking any collected `componentDidRender` callbacks after rendering new 11806 * content. 11807 * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue 11808 * to preserve the `scrollTop` (an automatic scroll aware DOM). 11809 * - (Future use case): Layout calculations before and after DOM upates. 11810 * 11811 * Transactional plugin API: 11812 * - A module that has an `initialize` method that returns any precomputation. 11813 * - and a `close` method that accepts the precomputation. `close` is invoked 11814 * when the wrapped process is completed, or has failed. 11815 * 11816 * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules 11817 * that implement `initialize` and `close`. 11818 * @return {Transaction} Single transaction for reuse in thread. 11819 * 11820 * @class Transaction 11821 */ 11822 var Mixin = { 11823 /** 11824 * Sets up this instance so that it is prepared for collecting metrics. Does 11825 * so such that this setup method may be used on an instance that is already 11826 * initialized, in a way that does not consume additional memory upon reuse. 11827 * That can be useful if you decide to make your subclass of this mixin a 11828 * "PooledClass". 11829 */ 11830 reinitializeTransaction: function() { 11831 this.transactionWrappers = this.getTransactionWrappers(); 11832 if (!this.wrapperInitData) { 11833 this.wrapperInitData = []; 11834 } else { 11835 this.wrapperInitData.length = 0; 11836 } 11837 if (!this.timingMetrics) { 11838 this.timingMetrics = {}; 11839 } 11840 this.timingMetrics.methodInvocationTime = 0; 11841 if (!this.timingMetrics.wrapperInitTimes) { 11842 this.timingMetrics.wrapperInitTimes = []; 11843 } else { 11844 this.timingMetrics.wrapperInitTimes.length = 0; 11845 } 11846 if (!this.timingMetrics.wrapperCloseTimes) { 11847 this.timingMetrics.wrapperCloseTimes = []; 11848 } else { 11849 this.timingMetrics.wrapperCloseTimes.length = 0; 11850 } 11851 this._isInTransaction = false; 11852 }, 11853 11854 _isInTransaction: false, 11855 11856 /** 11857 * @abstract 11858 * @return {Array<TransactionWrapper>} Array of transaction wrappers. 11859 */ 11860 getTransactionWrappers: null, 11861 11862 isInTransaction: function() { 11863 return !!this._isInTransaction; 11864 }, 11865 11866 /** 11867 * Executes the function within a safety window. Use this for the top level 11868 * methods that result in large amounts of computation/mutations that would 11869 * need to be safety checked. 11870 * 11871 * @param {function} method Member of scope to call. 11872 * @param {Object} scope Scope to invoke from. 11873 * @param {Object?=} args... Arguments to pass to the method (optional). 11874 * Helps prevent need to bind in many cases. 11875 * @return Return value from `method`. 11876 */ 11877 perform: function(method, scope, a, b, c, d, e, f) { 11878 ("production" !== "development" ? invariant( 11879 !this.isInTransaction(), 11880 'Transaction.perform(...): Cannot initialize a transaction when there ' + 11881 'is already an outstanding transaction.' 11882 ) : invariant(!this.isInTransaction())); 11883 var memberStart = Date.now(); 11884 var errorToThrow = null; 11885 var ret; 11886 try { 11887 this.initializeAll(); 11888 ret = method.call(scope, a, b, c, d, e, f); 11889 } catch (error) { 11890 // IE8 requires `catch` in order to use `finally`. 11891 errorToThrow = error; 11892 } finally { 11893 var memberEnd = Date.now(); 11894 this.methodInvocationTime += (memberEnd - memberStart); 11895 try { 11896 this.closeAll(); 11897 } catch (closeError) { 11898 // If `method` throws, prefer to show that stack trace over any thrown 11899 // by invoking `closeAll`. 11900 errorToThrow = errorToThrow || closeError; 11901 } 11902 } 11903 if (errorToThrow) { 11904 throw errorToThrow; 11905 } 11906 return ret; 11907 }, 11908 11909 initializeAll: function() { 11910 this._isInTransaction = true; 11911 var transactionWrappers = this.transactionWrappers; 11912 var wrapperInitTimes = this.timingMetrics.wrapperInitTimes; 11913 var errorToThrow = null; 11914 for (var i = 0; i < transactionWrappers.length; i++) { 11915 var initStart = Date.now(); 11916 var wrapper = transactionWrappers[i]; 11917 try { 11918 this.wrapperInitData[i] = wrapper.initialize ? 11919 wrapper.initialize.call(this) : 11920 null; 11921 } catch (initError) { 11922 // Prefer to show the stack trace of the first error. 11923 errorToThrow = errorToThrow || initError; 11924 this.wrapperInitData[i] = Transaction.OBSERVED_ERROR; 11925 } finally { 11926 var curInitTime = wrapperInitTimes[i]; 11927 var initEnd = Date.now(); 11928 wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart); 11929 } 11930 } 11931 if (errorToThrow) { 11932 throw errorToThrow; 11933 } 11934 }, 11935 11936 /** 11937 * Invokes each of `this.transactionWrappers.close[i]` functions, passing into 11938 * them the respective return values of `this.transactionWrappers.init[i]` 11939 * (`close`rs that correspond to initializers that failed will not be 11940 * invoked). 11941 */ 11942 closeAll: function() { 11943 ("production" !== "development" ? invariant( 11944 this.isInTransaction(), 11945 'Transaction.closeAll(): Cannot close transaction when none are open.' 11946 ) : invariant(this.isInTransaction())); 11947 var transactionWrappers = this.transactionWrappers; 11948 var wrapperCloseTimes = this.timingMetrics.wrapperCloseTimes; 11949 var errorToThrow = null; 11950 for (var i = 0; i < transactionWrappers.length; i++) { 11951 var wrapper = transactionWrappers[i]; 11952 var closeStart = Date.now(); 11953 var initData = this.wrapperInitData[i]; 11954 try { 11955 if (initData !== Transaction.OBSERVED_ERROR) { 11956 wrapper.close && wrapper.close.call(this, initData); 11957 } 11958 } catch (closeError) { 11959 // Prefer to show the stack trace of the first error. 11960 errorToThrow = errorToThrow || closeError; 11961 } finally { 11962 var closeEnd = Date.now(); 11963 var curCloseTime = wrapperCloseTimes[i]; 11964 wrapperCloseTimes[i] = (curCloseTime || 0) + (closeEnd - closeStart); 11965 } 11966 } 11967 this.wrapperInitData.length = 0; 11968 this._isInTransaction = false; 11969 if (errorToThrow) { 11970 throw errorToThrow; 11971 } 11972 } 11973 }; 11974 11975 var Transaction = { 11976 11977 Mixin: Mixin, 11978 11979 /** 11980 * Token to look for to determine if an error occured. 11981 */ 11982 OBSERVED_ERROR: {} 11983 11984 }; 11985 11986 module.exports = Transaction; 11987 11988 },{"./invariant":98}],74:[function(require,module,exports){ 11989 /** 11990 * Copyright 2013 Facebook, Inc. 11991 * 11992 * Licensed under the Apache License, Version 2.0 (the "License"); 11993 * you may not use this file except in compliance with the License. 11994 * You may obtain a copy of the License at 11995 * 11996 * http://www.apache.org/licenses/LICENSE-2.0 11997 * 11998 * Unless required by applicable law or agreed to in writing, software 11999 * distributed under the License is distributed on an "AS IS" BASIS, 12000 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12001 * See the License for the specific language governing permissions and 12002 * limitations under the License. 12003 * 12004 * @providesModule ViewportMetrics 12005 */ 12006 12007 "use strict"; 12008 12009 var getUnboundedScrollPosition = require("./getUnboundedScrollPosition"); 12010 12011 var ViewportMetrics = { 12012 12013 currentScrollLeft: 0, 12014 12015 currentScrollTop: 0, 12016 12017 refreshScrollValues: function() { 12018 var scrollPosition = getUnboundedScrollPosition(window); 12019 ViewportMetrics.currentScrollLeft = scrollPosition.x; 12020 ViewportMetrics.currentScrollTop = scrollPosition.y; 12021 } 12022 12023 }; 12024 12025 module.exports = ViewportMetrics; 12026 12027 },{"./getUnboundedScrollPosition":96}],75:[function(require,module,exports){ 12028 /** 12029 * Copyright 2013 Facebook, Inc. 12030 * 12031 * Licensed under the Apache License, Version 2.0 (the "License"); 12032 * you may not use this file except in compliance with the License. 12033 * You may obtain a copy of the License at 12034 * 12035 * http://www.apache.org/licenses/LICENSE-2.0 12036 * 12037 * Unless required by applicable law or agreed to in writing, software 12038 * distributed under the License is distributed on an "AS IS" BASIS, 12039 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12040 * See the License for the specific language governing permissions and 12041 * limitations under the License. 12042 * 12043 * @providesModule accumulate 12044 */ 12045 12046 "use strict"; 12047 12048 var invariant = require("./invariant"); 12049 12050 /** 12051 * Accumulates items that must not be null or undefined. 12052 * 12053 * This is used to conserve memory by avoiding array allocations. 12054 * 12055 * @return {*|array<*>} An accumulation of items. 12056 */ 12057 function accumulate(current, next) { 12058 ("production" !== "development" ? invariant( 12059 next != null, 12060 'accumulate(...): Accumulated items must be not be null or undefined.' 12061 ) : invariant(next != null)); 12062 if (current == null) { 12063 return next; 12064 } else { 12065 // Both are not empty. Warning: Never call x.concat(y) when you are not 12066 // certain that x is an Array (x could be a string with concat method). 12067 var currentIsArray = Array.isArray(current); 12068 var nextIsArray = Array.isArray(next); 12069 if (currentIsArray) { 12070 return current.concat(next); 12071 } else { 12072 if (nextIsArray) { 12073 return [current].concat(next); 12074 } else { 12075 return [current, next]; 12076 } 12077 } 12078 } 12079 } 12080 12081 module.exports = accumulate; 12082 12083 },{"./invariant":98}],76:[function(require,module,exports){ 12084 /** 12085 * Copyright 2013 Facebook, Inc. 12086 * 12087 * Licensed under the Apache License, Version 2.0 (the "License"); 12088 * you may not use this file except in compliance with the License. 12089 * You may obtain a copy of the License at 12090 * 12091 * http://www.apache.org/licenses/LICENSE-2.0 12092 * 12093 * Unless required by applicable law or agreed to in writing, software 12094 * distributed under the License is distributed on an "AS IS" BASIS, 12095 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12096 * See the License for the specific language governing permissions and 12097 * limitations under the License. 12098 * 12099 * @providesModule adler32 12100 */ 12101 12102 /* jslint bitwise:true */ 12103 12104 "use strict"; 12105 12106 var MOD = 65521; 12107 12108 // This is a clean-room implementation of adler32 designed for detecting 12109 // if markup is not what we expect it to be. It does not need to be 12110 // cryptographically strong, only reasonable good at detecting if markup 12111 // generated on the server is different than that on the client. 12112 function adler32(data) { 12113 var a = 1; 12114 var b = 0; 12115 for (var i = 0; i < data.length; i++) { 12116 a = (a + data.charCodeAt(i)) % MOD; 12117 b = (b + a) % MOD; 12118 } 12119 return a | (b << 16); 12120 } 12121 12122 module.exports = adler32; 12123 12124 },{}],77:[function(require,module,exports){ 12125 /** 12126 * Copyright 2013 Facebook, Inc. 12127 * 12128 * Licensed under the Apache License, Version 2.0 (the "License"); 12129 * you may not use this file except in compliance with the License. 12130 * You may obtain a copy of the License at 12131 * 12132 * http://www.apache.org/licenses/LICENSE-2.0 12133 * 12134 * Unless required by applicable law or agreed to in writing, software 12135 * distributed under the License is distributed on an "AS IS" BASIS, 12136 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12137 * See the License for the specific language governing permissions and 12138 * limitations under the License. 12139 * 12140 * @providesModule containsNode 12141 * @typechecks 12142 */ 12143 12144 var isTextNode = require("./isTextNode"); 12145 12146 /*jslint bitwise:true */ 12147 12148 /** 12149 * Checks if a given DOM node contains or is another DOM node. 12150 * 12151 * @param {?DOMNode} outerNode Outer DOM node. 12152 * @param {?DOMNode} innerNode Inner DOM node. 12153 * @return {boolean} True if `outerNode` contains or is `innerNode`. 12154 */ 12155 function containsNode(outerNode, innerNode) { 12156 if (!outerNode || !innerNode) { 12157 return false; 12158 } else if (outerNode === innerNode) { 12159 return true; 12160 } else if (isTextNode(outerNode)) { 12161 return false; 12162 } else if (isTextNode(innerNode)) { 12163 return containsNode(outerNode, innerNode.parentNode); 12164 } else if (outerNode.contains) { 12165 return outerNode.contains(innerNode); 12166 } else if (outerNode.compareDocumentPosition) { 12167 return !!(outerNode.compareDocumentPosition(innerNode) & 16); 12168 } else { 12169 return false; 12170 } 12171 } 12172 12173 module.exports = containsNode; 12174 12175 },{"./isTextNode":102}],78:[function(require,module,exports){ 12176 /** 12177 * Copyright 2013 Facebook, Inc. 12178 * 12179 * Licensed under the Apache License, Version 2.0 (the "License"); 12180 * you may not use this file except in compliance with the License. 12181 * You may obtain a copy of the License at 12182 * 12183 * http://www.apache.org/licenses/LICENSE-2.0 12184 * 12185 * Unless required by applicable law or agreed to in writing, software 12186 * distributed under the License is distributed on an "AS IS" BASIS, 12187 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12188 * See the License for the specific language governing permissions and 12189 * limitations under the License. 12190 * 12191 * @providesModule copyProperties 12192 */ 12193 12194 /** 12195 * Copy properties from one or more objects (up to 5) into the first object. 12196 * This is a shallow copy. It mutates the first object and also returns it. 12197 * 12198 * NOTE: `arguments` has a very significant performance penalty, which is why 12199 * we don't support unlimited arguments. 12200 */ 12201 function copyProperties(obj, a, b, c, d, e, f) { 12202 obj = obj || {}; 12203 12204 if ("production" !== "development") { 12205 if (f) { 12206 throw new Error('Too many arguments passed to copyProperties'); 12207 } 12208 } 12209 12210 var args = [a, b, c, d, e]; 12211 var ii = 0, v; 12212 while (args[ii]) { 12213 v = args[ii++]; 12214 for (var k in v) { 12215 obj[k] = v[k]; 12216 } 12217 12218 // IE ignores toString in object iteration.. See: 12219 // webreflection.blogspot.com/2007/07/quick-fix-internet-explorer-and.html 12220 if (v.hasOwnProperty && v.hasOwnProperty('toString') && 12221 (typeof v.toString != 'undefined') && (obj.toString !== v.toString)) { 12222 obj.toString = v.toString; 12223 } 12224 } 12225 12226 return obj; 12227 } 12228 12229 module.exports = copyProperties; 12230 12231 },{}],79:[function(require,module,exports){ 12232 /** 12233 * Copyright 2013 Facebook, Inc. 12234 * 12235 * Licensed under the Apache License, Version 2.0 (the "License"); 12236 * you may not use this file except in compliance with the License. 12237 * You may obtain a copy of the License at 12238 * 12239 * http://www.apache.org/licenses/LICENSE-2.0 12240 * 12241 * Unless required by applicable law or agreed to in writing, software 12242 * distributed under the License is distributed on an "AS IS" BASIS, 12243 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12244 * See the License for the specific language governing permissions and 12245 * limitations under the License. 12246 * 12247 * @providesModule createArrayFrom 12248 * @typechecks 12249 */ 12250 12251 /** 12252 * NOTE: if you are a previous user of this function, it has been considered 12253 * unsafe because it's inconsistent across browsers for some inputs. 12254 * Instead use `Array.isArray()`. 12255 * 12256 * Perform a heuristic test to determine if an object is "array-like". 12257 * 12258 * A monk asked Joshu, a Zen master, "Has a dog Buddha nature?" 12259 * Joshu replied: "Mu." 12260 * 12261 * This function determines if its argument has "array nature": it returns 12262 * true if the argument is an actual array, an `arguments' object, or an 12263 * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()). 12264 * 12265 * @param {*} obj 12266 * @return {boolean} 12267 */ 12268 function hasArrayNature(obj) { 12269 return ( 12270 // not null/false 12271 !!obj && 12272 // arrays are objects, NodeLists are functions in Safari 12273 (typeof obj == 'object' || typeof obj == 'function') && 12274 // quacks like an array 12275 ('length' in obj) && 12276 // not window 12277 !('setInterval' in obj) && 12278 // no DOM node should be considered an array-like 12279 // a 'select' element has 'length' and 'item' properties on IE8 12280 (typeof obj.nodeType != 'number') && 12281 ( 12282 // a real array 12283 (// HTMLCollection/NodeList 12284 (Array.isArray(obj) || 12285 // arguments 12286 ('callee' in obj) || 'item' in obj)) 12287 ) 12288 ); 12289 } 12290 12291 /** 12292 * Ensure that the argument is an array by wrapping it in an array if it is not. 12293 * Creates a copy of the argument if it is already an array. 12294 * 12295 * This is mostly useful idiomatically: 12296 * 12297 * var createArrayFrom = require('createArrayFrom'); 12298 * 12299 * function takesOneOrMoreThings(things) { 12300 * things = createArrayFrom(things); 12301 * ... 12302 * } 12303 * 12304 * This allows you to treat `things' as an array, but accept scalars in the API. 12305 * 12306 * This is also good for converting certain pseudo-arrays, like `arguments` or 12307 * HTMLCollections, into arrays. 12308 * 12309 * @param {*} obj 12310 * @return {array} 12311 */ 12312 function createArrayFrom(obj) { 12313 if (!hasArrayNature(obj)) { 12314 return [obj]; 12315 } 12316 if (obj.item) { 12317 // IE does not support Array#slice on HTMLCollections 12318 var l = obj.length, ret = new Array(l); 12319 while (l--) { ret[l] = obj[l]; } 12320 return ret; 12321 } 12322 return Array.prototype.slice.call(obj); 12323 } 12324 12325 module.exports = createArrayFrom; 12326 12327 },{}],80:[function(require,module,exports){ 12328 /** 12329 * Copyright 2013 Facebook, Inc. 12330 * 12331 * Licensed under the Apache License, Version 2.0 (the "License"); 12332 * you may not use this file except in compliance with the License. 12333 * You may obtain a copy of the License at 12334 * 12335 * http://www.apache.org/licenses/LICENSE-2.0 12336 * 12337 * Unless required by applicable law or agreed to in writing, software 12338 * distributed under the License is distributed on an "AS IS" BASIS, 12339 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12340 * See the License for the specific language governing permissions and 12341 * limitations under the License. 12342 * 12343 * @providesModule createNodesFromMarkup 12344 * @typechecks 12345 */ 12346 12347 /*jslint evil: true, sub: true */ 12348 12349 var ExecutionEnvironment = require("./ExecutionEnvironment"); 12350 12351 var createArrayFrom = require("./createArrayFrom"); 12352 var getMarkupWrap = require("./getMarkupWrap"); 12353 var invariant = require("./invariant"); 12354 12355 /** 12356 * Dummy container used to render all markup. 12357 */ 12358 var dummyNode = 12359 ExecutionEnvironment.canUseDOM ? document.createElement('div') : null; 12360 12361 /** 12362 * Pattern used by `getNodeName`. 12363 */ 12364 var nodeNamePattern = /^\s*<(\w+)/; 12365 12366 /** 12367 * Extracts the `nodeName` of the first element in a string of markup. 12368 * 12369 * @param {string} markup String of markup. 12370 * @return {?string} Node name of the supplied markup. 12371 */ 12372 function getNodeName(markup) { 12373 var nodeNameMatch = markup.match(nodeNamePattern); 12374 return nodeNameMatch && nodeNameMatch[1].toLowerCase(); 12375 } 12376 12377 /** 12378 * Creates an array containing the nodes rendered from the supplied markup. The 12379 * optionally supplied `handleScript` function will be invoked once for each 12380 * <script> element that is rendered. If no `handleScript` function is supplied, 12381 * an exception is thrown if any <script> elements are rendered. 12382 * 12383 * @param {string} markup A string of valid HTML markup. 12384 * @param {?function} handleScript Invoked once for each rendered <script>. 12385 * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes. 12386 */ 12387 function createNodesFromMarkup(markup, handleScript) { 12388 var node = dummyNode; 12389 ("production" !== "development" ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode)); 12390 var nodeName = getNodeName(markup); 12391 12392 var wrap = nodeName && getMarkupWrap(nodeName); 12393 if (wrap) { 12394 node.innerHTML = wrap[1] + markup + wrap[2]; 12395 12396 var wrapDepth = wrap[0]; 12397 while (wrapDepth--) { 12398 node = node.lastChild; 12399 } 12400 } else { 12401 node.innerHTML = markup; 12402 } 12403 12404 var scripts = node.getElementsByTagName('script'); 12405 if (scripts.length) { 12406 ("production" !== "development" ? invariant( 12407 handleScript, 12408 'createNodesFromMarkup(...): Unexpected <script> element rendered.' 12409 ) : invariant(handleScript)); 12410 createArrayFrom(scripts).forEach(handleScript); 12411 } 12412 12413 var nodes = createArrayFrom(node.childNodes); 12414 while (node.lastChild) { 12415 node.removeChild(node.lastChild); 12416 } 12417 return nodes; 12418 } 12419 12420 module.exports = createNodesFromMarkup; 12421 12422 },{"./ExecutionEnvironment":20,"./createArrayFrom":79,"./getMarkupWrap":92,"./invariant":98}],81:[function(require,module,exports){ 12423 /** 12424 * Copyright 2013 Facebook, Inc. 12425 * 12426 * Licensed under the Apache License, Version 2.0 (the "License"); 12427 * you may not use this file except in compliance with the License. 12428 * You may obtain a copy of the License at 12429 * 12430 * http://www.apache.org/licenses/LICENSE-2.0 12431 * 12432 * Unless required by applicable law or agreed to in writing, software 12433 * distributed under the License is distributed on an "AS IS" BASIS, 12434 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12435 * See the License for the specific language governing permissions and 12436 * limitations under the License. 12437 * 12438 * @providesModule createObjectFrom 12439 */ 12440 12441 /** 12442 * Construct an object from an array of keys 12443 * and optionally specified value or list of values. 12444 * 12445 * >>> createObjectFrom(['a','b','c']); 12446 * {a: true, b: true, c: true} 12447 * 12448 * >>> createObjectFrom(['a','b','c'], false); 12449 * {a: false, b: false, c: false} 12450 * 12451 * >>> createObjectFrom(['a','b','c'], 'monkey'); 12452 * {c:'monkey', b:'monkey' c:'monkey'} 12453 * 12454 * >>> createObjectFrom(['a','b','c'], [1,2,3]); 12455 * {a: 1, b: 2, c: 3} 12456 * 12457 * >>> createObjectFrom(['women', 'men'], [true, false]); 12458 * {women: true, men: false} 12459 * 12460 * @param Array list of keys 12461 * @param mixed optional value or value array. defaults true. 12462 * @returns object 12463 */ 12464 function createObjectFrom(keys, values /* = true */) { 12465 if ("production" !== "development") { 12466 if (!Array.isArray(keys)) { 12467 throw new TypeError('Must pass an array of keys.'); 12468 } 12469 } 12470 12471 var object = {}; 12472 var isArray = Array.isArray(values); 12473 if (typeof values == 'undefined') { 12474 values = true; 12475 } 12476 12477 for (var ii = keys.length; ii--;) { 12478 object[keys[ii]] = isArray ? values[ii] : values; 12479 } 12480 return object; 12481 } 12482 12483 module.exports = createObjectFrom; 12484 12485 },{}],82:[function(require,module,exports){ 12486 /** 12487 * Copyright 2013 Facebook, Inc. 12488 * 12489 * Licensed under the Apache License, Version 2.0 (the "License"); 12490 * you may not use this file except in compliance with the License. 12491 * You may obtain a copy of the License at 12492 * 12493 * http://www.apache.org/licenses/LICENSE-2.0 12494 * 12495 * Unless required by applicable law or agreed to in writing, software 12496 * distributed under the License is distributed on an "AS IS" BASIS, 12497 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12498 * See the License for the specific language governing permissions and 12499 * limitations under the License. 12500 * 12501 * @providesModule dangerousStyleValue 12502 * @typechecks static-only 12503 */ 12504 12505 "use strict"; 12506 12507 var CSSProperty = require("./CSSProperty"); 12508 12509 /** 12510 * Convert a value into the proper css writable value. The `styleName` name 12511 * name should be logical (no hyphens), as specified 12512 * in `CSSProperty.isUnitlessNumber`. 12513 * 12514 * @param {string} styleName CSS property name such as `topMargin`. 12515 * @param {*} value CSS property value such as `10px`. 12516 * @return {string} Normalized style value with dimensions applied. 12517 */ 12518 function dangerousStyleValue(styleName, value) { 12519 // Note that we've removed escapeTextForBrowser() calls here since the 12520 // whole string will be escaped when the attribute is injected into 12521 // the markup. If you provide unsafe user data here they can inject 12522 // arbitrary CSS which may be problematic (I couldn't repro this): 12523 // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet 12524 // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ 12525 // This is not an XSS hole but instead a potential CSS injection issue 12526 // which has lead to a greater discussion about how we're going to 12527 // trust URLs moving forward. See #2115901 12528 12529 var isEmpty = value == null || typeof value === 'boolean' || value === ''; 12530 if (isEmpty) { 12531 return ''; 12532 } 12533 12534 var isNonNumeric = isNaN(value); 12535 if (isNonNumeric || value === 0 || CSSProperty.isUnitlessNumber[styleName]) { 12536 return '' + value; // cast to string 12537 } 12538 12539 return value + 'px'; 12540 } 12541 12542 module.exports = dangerousStyleValue; 12543 12544 },{"./CSSProperty":2}],83:[function(require,module,exports){ 12545 /** 12546 * Copyright 2013 Facebook, Inc. 12547 * 12548 * Licensed under the Apache License, Version 2.0 (the "License"); 12549 * you may not use this file except in compliance with the License. 12550 * You may obtain a copy of the License at 12551 * 12552 * http://www.apache.org/licenses/LICENSE-2.0 12553 * 12554 * Unless required by applicable law or agreed to in writing, software 12555 * distributed under the License is distributed on an "AS IS" BASIS, 12556 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12557 * See the License for the specific language governing permissions and 12558 * limitations under the License. 12559 * 12560 * @providesModule emptyFunction 12561 */ 12562 12563 var copyProperties = require("./copyProperties"); 12564 12565 function makeEmptyFunction(arg) { 12566 return function() { 12567 return arg; 12568 }; 12569 } 12570 12571 /** 12572 * This function accepts and discards inputs; it has no side effects. This is 12573 * primarily useful idiomatically for overridable function endpoints which 12574 * always need to be callable, since JS lacks a null-call idiom ala Cocoa. 12575 */ 12576 function emptyFunction() {} 12577 12578 copyProperties(emptyFunction, { 12579 thatReturns: makeEmptyFunction, 12580 thatReturnsFalse: makeEmptyFunction(false), 12581 thatReturnsTrue: makeEmptyFunction(true), 12582 thatReturnsNull: makeEmptyFunction(null), 12583 thatReturnsThis: function() { return this; }, 12584 thatReturnsArgument: function(arg) { return arg; } 12585 }); 12586 12587 module.exports = emptyFunction; 12588 12589 },{"./copyProperties":78}],84:[function(require,module,exports){ 12590 /** 12591 * Copyright 2013 Facebook, Inc. 12592 * 12593 * Licensed under the Apache License, Version 2.0 (the "License"); 12594 * you may not use this file except in compliance with the License. 12595 * You may obtain a copy of the License at 12596 * 12597 * http://www.apache.org/licenses/LICENSE-2.0 12598 * 12599 * Unless required by applicable law or agreed to in writing, software 12600 * distributed under the License is distributed on an "AS IS" BASIS, 12601 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12602 * See the License for the specific language governing permissions and 12603 * limitations under the License. 12604 * 12605 * @providesModule escapeTextForBrowser 12606 * @typechecks static-only 12607 */ 12608 12609 "use strict"; 12610 12611 var ESCAPE_LOOKUP = { 12612 "&": "&", 12613 ">": ">", 12614 "<": "<", 12615 "\"": """, 12616 "'": "'", 12617 "/": "/" 12618 }; 12619 12620 var ESCAPE_REGEX = /[&><"'\/]/g; 12621 12622 function escaper(match) { 12623 return ESCAPE_LOOKUP[match]; 12624 } 12625 12626 /** 12627 * Escapes text to prevent scripting attacks. 12628 * 12629 * @param {*} text Text value to escape. 12630 * @return {string} An escaped string. 12631 */ 12632 function escapeTextForBrowser(text) { 12633 return ('' + text).replace(ESCAPE_REGEX, escaper); 12634 } 12635 12636 module.exports = escapeTextForBrowser; 12637 12638 },{}],85:[function(require,module,exports){ 12639 /** 12640 * Copyright 2013 Facebook, Inc. 12641 * 12642 * Licensed under the Apache License, Version 2.0 (the "License"); 12643 * you may not use this file except in compliance with the License. 12644 * You may obtain a copy of the License at 12645 * 12646 * http://www.apache.org/licenses/LICENSE-2.0 12647 * 12648 * Unless required by applicable law or agreed to in writing, software 12649 * distributed under the License is distributed on an "AS IS" BASIS, 12650 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12651 * See the License for the specific language governing permissions and 12652 * limitations under the License. 12653 * 12654 * @providesModule ex 12655 * @typechecks 12656 * @nostacktrace 12657 */ 12658 12659 /** 12660 * This function transforms error message with arguments into plain text error 12661 * message, so that it can be passed to window.onerror without losing anything. 12662 * It can then be transformed back by `erx()` function. 12663 * 12664 * Usage: 12665 * throw new Error(ex('Error %s from %s', errorCode, userID)); 12666 * 12667 * @param {string} errorMessage 12668 */ 12669 12670 var ex = function(errorMessage/*, arg1, arg2, ...*/) { 12671 var args = Array.prototype.slice.call(arguments).map(function(arg) { 12672 return String(arg); 12673 }); 12674 var expectedLength = errorMessage.split('%s').length - 1; 12675 12676 if (expectedLength !== args.length - 1) { 12677 // something wrong with the formatting string 12678 return ex('ex args number mismatch: %s', JSON.stringify(args)); 12679 } 12680 12681 return ex._prefix + JSON.stringify(args) + ex._suffix; 12682 }; 12683 12684 ex._prefix = '<![EX['; 12685 ex._suffix = ']]>'; 12686 12687 module.exports = ex; 12688 12689 },{}],86:[function(require,module,exports){ 12690 /** 12691 * Copyright 2013 Facebook, Inc. 12692 * 12693 * Licensed under the Apache License, Version 2.0 (the "License"); 12694 * you may not use this file except in compliance with the License. 12695 * You may obtain a copy of the License at 12696 * 12697 * http://www.apache.org/licenses/LICENSE-2.0 12698 * 12699 * Unless required by applicable law or agreed to in writing, software 12700 * distributed under the License is distributed on an "AS IS" BASIS, 12701 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12702 * See the License for the specific language governing permissions and 12703 * limitations under the License. 12704 * 12705 * @providesModule filterAttributes 12706 * @typechecks static-only 12707 */ 12708 12709 /*jslint evil: true */ 12710 12711 'use strict'; 12712 12713 /** 12714 * Like filter(), but for a DOM nodes attributes. Returns an array of 12715 * the filter DOMAttribute objects. Does some perf related this like 12716 * caching attributes.length. 12717 * 12718 * @param {DOMElement} node Node whose attributes you want to filter 12719 * @return {array} array of DOM attribute objects. 12720 */ 12721 function filterAttributes(node, func, context) { 12722 var attributes = node.attributes; 12723 var numAttributes = attributes.length; 12724 var accumulator = []; 12725 for (var i = 0; i < numAttributes; i++) { 12726 var attr = attributes.item(i); 12727 if (func.call(context, attr)) { 12728 accumulator.push(attr); 12729 } 12730 } 12731 return accumulator; 12732 } 12733 12734 module.exports = filterAttributes; 12735 12736 },{}],87:[function(require,module,exports){ 12737 /** 12738 * Copyright 2013 Facebook, Inc. 12739 * 12740 * Licensed under the Apache License, Version 2.0 (the "License"); 12741 * you may not use this file except in compliance with the License. 12742 * You may obtain a copy of the License at 12743 * 12744 * http://www.apache.org/licenses/LICENSE-2.0 12745 * 12746 * Unless required by applicable law or agreed to in writing, software 12747 * distributed under the License is distributed on an "AS IS" BASIS, 12748 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12749 * See the License for the specific language governing permissions and 12750 * limitations under the License. 12751 * 12752 * @providesModule flattenChildren 12753 */ 12754 12755 "use strict"; 12756 12757 var invariant = require("./invariant"); 12758 var traverseAllChildren = require("./traverseAllChildren"); 12759 12760 /** 12761 * @param {function} traverseContext Context passed through traversal. 12762 * @param {?ReactComponent} child React child component. 12763 * @param {!string} name String name of key path to child. 12764 */ 12765 function flattenSingleChildIntoContext(traverseContext, child, name) { 12766 // We found a component instance. 12767 var result = traverseContext; 12768 ("production" !== "development" ? invariant( 12769 !result.hasOwnProperty(name), 12770 'flattenChildren(...): Encountered two children with the same key, `%s`. ' + 12771 'Children keys must be unique.', 12772 name 12773 ) : invariant(!result.hasOwnProperty(name))); 12774 result[name] = child; 12775 } 12776 12777 /** 12778 * Flattens children that are typically specified as `props.children`. 12779 * @return {!object} flattened children keyed by name. 12780 */ 12781 function flattenChildren(children) { 12782 if (children == null) { 12783 return children; 12784 } 12785 var result = {}; 12786 traverseAllChildren(children, flattenSingleChildIntoContext, result); 12787 return result; 12788 } 12789 12790 module.exports = flattenChildren; 12791 12792 },{"./invariant":98,"./traverseAllChildren":116}],88:[function(require,module,exports){ 12793 /** 12794 * Copyright 2013 Facebook, Inc. 12795 * 12796 * Licensed under the Apache License, Version 2.0 (the "License"); 12797 * you may not use this file except in compliance with the License. 12798 * You may obtain a copy of the License at 12799 * 12800 * http://www.apache.org/licenses/LICENSE-2.0 12801 * 12802 * Unless required by applicable law or agreed to in writing, software 12803 * distributed under the License is distributed on an "AS IS" BASIS, 12804 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12805 * See the License for the specific language governing permissions and 12806 * limitations under the License. 12807 * 12808 * @providesModule forEachAccumulated 12809 */ 12810 12811 "use strict"; 12812 12813 /** 12814 * @param {array} an "accumulation" of items which is either an Array or 12815 * a single item. Useful when paired with the `accumulate` module. This is a 12816 * simple utility that allows us to reason about a collection of items, but 12817 * handling the case when there is exactly one item (and we do not need to 12818 * allocate an array). 12819 */ 12820 var forEachAccumulated = function(arr, cb, scope) { 12821 if (Array.isArray(arr)) { 12822 arr.forEach(cb, scope); 12823 } else if (arr) { 12824 cb.call(scope, arr); 12825 } 12826 }; 12827 12828 module.exports = forEachAccumulated; 12829 12830 },{}],89:[function(require,module,exports){ 12831 /** 12832 * Copyright 2013 Facebook, Inc. 12833 * 12834 * Licensed under the Apache License, Version 2.0 (the "License"); 12835 * you may not use this file except in compliance with the License. 12836 * You may obtain a copy of the License at 12837 * 12838 * http://www.apache.org/licenses/LICENSE-2.0 12839 * 12840 * Unless required by applicable law or agreed to in writing, software 12841 * distributed under the License is distributed on an "AS IS" BASIS, 12842 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12843 * See the License for the specific language governing permissions and 12844 * limitations under the License. 12845 * 12846 * @providesModule ge 12847 */ 12848 12849 /** 12850 * Find a node by ID. Optionally search a sub-tree outside of the document 12851 * 12852 * Use ge if you're not sure whether or not the element exists. You can test 12853 * for existence yourself in your application code. 12854 * 12855 * If your application code depends on the existence of the element, use $ 12856 * instead, which will throw in DEV if the element doesn't exist. 12857 */ 12858 function ge(arg, root, tag) { 12859 return typeof arg != 'string' ? arg : 12860 !root ? document.getElementById(arg) : 12861 _geFromSubtree(arg, root, tag); 12862 } 12863 12864 function _geFromSubtree(id, root, tag) { 12865 var elem, children, ii; 12866 12867 if (_getNodeID(root) == id) { 12868 return root; 12869 } else if (root.getElementsByTagName) { 12870 // All Elements implement this, which does an iterative DFS, which is 12871 // faster than recursion and doesn't run into stack depth issues. 12872 children = root.getElementsByTagName(tag || '*'); 12873 for (ii = 0; ii < children.length; ii++) { 12874 if (_getNodeID(children[ii]) == id) { 12875 return children[ii]; 12876 } 12877 } 12878 } else { 12879 // DocumentFragment does not implement getElementsByTagName, so 12880 // recurse over its children. Its children must be Elements, so 12881 // each child will use the getElementsByTagName case instead. 12882 children = root.childNodes; 12883 for (ii = 0; ii < children.length; ii++) { 12884 elem = _geFromSubtree(id, children[ii]); 12885 if (elem) { 12886 return elem; 12887 } 12888 } 12889 } 12890 12891 return null; 12892 } 12893 12894 /** 12895 * Return the ID value for a given node. This allows us to avoid issues 12896 * with forms that contain inputs with name="id". 12897 * 12898 * @return string (null if attribute not set) 12899 */ 12900 function _getNodeID(node) { 12901 // #document and #document-fragment do not have getAttributeNode. 12902 var id = node.getAttributeNode && node.getAttributeNode('id'); 12903 return id ? id.value : null; 12904 } 12905 12906 module.exports = ge; 12907 12908 },{}],90:[function(require,module,exports){ 12909 /** 12910 * Copyright 2013 Facebook, Inc. 12911 * 12912 * Licensed under the Apache License, Version 2.0 (the "License"); 12913 * you may not use this file except in compliance with the License. 12914 * You may obtain a copy of the License at 12915 * 12916 * http://www.apache.org/licenses/LICENSE-2.0 12917 * 12918 * Unless required by applicable law or agreed to in writing, software 12919 * distributed under the License is distributed on an "AS IS" BASIS, 12920 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12921 * See the License for the specific language governing permissions and 12922 * limitations under the License. 12923 * 12924 * @providesModule getActiveElement 12925 * @typechecks 12926 */ 12927 12928 /** 12929 * Same as document.activeElement but wraps in a try-catch block. In IE it is 12930 * not safe to call document.activeElement if there is nothing focused. 12931 */ 12932 function getActiveElement() /*?DOMElement*/ { 12933 try { 12934 return document.activeElement; 12935 } catch (e) { 12936 return null; 12937 } 12938 } 12939 12940 module.exports = getActiveElement; 12941 12942 12943 },{}],91:[function(require,module,exports){ 12944 /** 12945 * Copyright 2013 Facebook, Inc. 12946 * 12947 * Licensed under the Apache License, Version 2.0 (the "License"); 12948 * you may not use this file except in compliance with the License. 12949 * You may obtain a copy of the License at 12950 * 12951 * http://www.apache.org/licenses/LICENSE-2.0 12952 * 12953 * Unless required by applicable law or agreed to in writing, software 12954 * distributed under the License is distributed on an "AS IS" BASIS, 12955 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12956 * See the License for the specific language governing permissions and 12957 * limitations under the License. 12958 * 12959 * @providesModule getEventTarget 12960 * @typechecks static-only 12961 */ 12962 12963 "use strict"; 12964 12965 /** 12966 * Gets the target node from a native browser event by accounting for 12967 * inconsistencies in browser DOM APIs. 12968 * 12969 * @param {object} nativeEvent Native browser event. 12970 * @return {DOMEventTarget} Target node. 12971 */ 12972 function getEventTarget(nativeEvent) { 12973 var target = nativeEvent.target || nativeEvent.srcElement || window; 12974 // Safari may fire events on text nodes (Node.TEXT_NODE is 3). 12975 // @see http://www.quirksmode.org/js/events_properties.html 12976 return target.nodeType === 3 ? target.parentNode : target; 12977 } 12978 12979 module.exports = getEventTarget; 12980 12981 },{}],92:[function(require,module,exports){ 12982 /** 12983 * Copyright 2013 Facebook, Inc. 12984 * 12985 * Licensed under the Apache License, Version 2.0 (the "License"); 12986 * you may not use this file except in compliance with the License. 12987 * You may obtain a copy of the License at 12988 * 12989 * http://www.apache.org/licenses/LICENSE-2.0 12990 * 12991 * Unless required by applicable law or agreed to in writing, software 12992 * distributed under the License is distributed on an "AS IS" BASIS, 12993 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12994 * See the License for the specific language governing permissions and 12995 * limitations under the License. 12996 * 12997 * @providesModule getMarkupWrap 12998 */ 12999 13000 var ExecutionEnvironment = require("./ExecutionEnvironment"); 13001 13002 var invariant = require("./invariant"); 13003 13004 /** 13005 * Dummy container used to detect which wraps are necessary. 13006 */ 13007 var dummyNode = 13008 ExecutionEnvironment.canUseDOM ? document.createElement('div') : null; 13009 13010 /** 13011 * Some browsers cannot use `innerHTML` to render certain elements standalone, 13012 * so we wrap them, render the wrapped nodes, then extract the desired node. 13013 * 13014 * In IE8, certain elements cannot render alone, so wrap all elements ('*'). 13015 */ 13016 var shouldWrap = { 13017 // Force wrapping for SVG elements because if they get created inside a <div>, 13018 // they will be initialized in the wrong namespace (and will not display). 13019 'circle': true, 13020 'g': true, 13021 'line': true, 13022 'path': true, 13023 'polyline': true, 13024 'rect': true, 13025 'text': true 13026 }; 13027 13028 var selectWrap = [1, '<select multiple="true">', '</select>']; 13029 var tableWrap = [1, '<table>', '</table>']; 13030 var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>']; 13031 13032 var svgWrap = [1, '<svg>', '</svg>']; 13033 13034 var markupWrap = { 13035 '*': [1, '?<div>', '</div>'], 13036 13037 'area': [1, '<map>', '</map>'], 13038 'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], 13039 'legend': [1, '<fieldset>', '</fieldset>'], 13040 'param': [1, '<object>', '</object>'], 13041 'tr': [2, '<table><tbody>', '</tbody></table>'], 13042 13043 'optgroup': selectWrap, 13044 'option': selectWrap, 13045 13046 'caption': tableWrap, 13047 'colgroup': tableWrap, 13048 'tbody': tableWrap, 13049 'tfoot': tableWrap, 13050 'thead': tableWrap, 13051 13052 'td': trWrap, 13053 'th': trWrap, 13054 13055 'circle': svgWrap, 13056 'g': svgWrap, 13057 'line': svgWrap, 13058 'path': svgWrap, 13059 'polyline': svgWrap, 13060 'rect': svgWrap, 13061 'text': svgWrap 13062 }; 13063 13064 /** 13065 * Gets the markup wrap configuration for the supplied `nodeName`. 13066 * 13067 * NOTE: This lazily detects which wraps are necessary for the current browser. 13068 * 13069 * @param {string} nodeName Lowercase `nodeName`. 13070 * @return {?array} Markup wrap configuration, if applicable. 13071 */ 13072 function getMarkupWrap(nodeName) { 13073 ("production" !== "development" ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode)); 13074 if (!markupWrap.hasOwnProperty(nodeName)) { 13075 nodeName = '*'; 13076 } 13077 if (!shouldWrap.hasOwnProperty(nodeName)) { 13078 if (nodeName === '*') { 13079 dummyNode.innerHTML = '<link />'; 13080 } else { 13081 dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>'; 13082 } 13083 shouldWrap[nodeName] = !dummyNode.firstChild; 13084 } 13085 return shouldWrap[nodeName] ? markupWrap[nodeName] : null; 13086 } 13087 13088 13089 module.exports = getMarkupWrap; 13090 13091 },{"./ExecutionEnvironment":20,"./invariant":98}],93:[function(require,module,exports){ 13092 /** 13093 * Copyright 2013 Facebook, Inc. 13094 * 13095 * Licensed under the Apache License, Version 2.0 (the "License"); 13096 * you may not use this file except in compliance with the License. 13097 * You may obtain a copy of the License at 13098 * 13099 * http://www.apache.org/licenses/LICENSE-2.0 13100 * 13101 * Unless required by applicable law or agreed to in writing, software 13102 * distributed under the License is distributed on an "AS IS" BASIS, 13103 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13104 * See the License for the specific language governing permissions and 13105 * limitations under the License. 13106 * 13107 * @providesModule getNodeForCharacterOffset 13108 */ 13109 13110 "use strict"; 13111 13112 /** 13113 * Given any node return the first leaf node without children. 13114 * 13115 * @param {DOMElement|DOMTextNode} node 13116 * @return {DOMElement|DOMTextNode} 13117 */ 13118 function getLeafNode(node) { 13119 while (node && node.firstChild) { 13120 node = node.firstChild; 13121 } 13122 return node; 13123 } 13124 13125 /** 13126 * Get the next sibling within a container. This will walk up the 13127 * DOM if a node's siblings have been exhausted. 13128 * 13129 * @param {DOMElement|DOMTextNode} node 13130 * @return {?DOMElement|DOMTextNode} 13131 */ 13132 function getSiblingNode(node) { 13133 while (node) { 13134 if (node.nextSibling) { 13135 return node.nextSibling; 13136 } 13137 node = node.parentNode; 13138 } 13139 } 13140 13141 /** 13142 * Get object describing the nodes which contain characters at offset. 13143 * 13144 * @param {DOMElement|DOMTextNode} root 13145 * @param {number} offset 13146 * @return {?object} 13147 */ 13148 function getNodeForCharacterOffset(root, offset) { 13149 var node = getLeafNode(root); 13150 var nodeStart = 0; 13151 var nodeEnd = 0; 13152 13153 while (node) { 13154 if (node.nodeType == 3) { 13155 nodeEnd = nodeStart + node.textContent.length; 13156 13157 if (nodeStart <= offset && nodeEnd >= offset) { 13158 return { 13159 node: node, 13160 offset: offset - nodeStart 13161 }; 13162 } 13163 13164 nodeStart = nodeEnd; 13165 } 13166 13167 node = getLeafNode(getSiblingNode(node)); 13168 } 13169 } 13170 13171 module.exports = getNodeForCharacterOffset; 13172 13173 },{}],94:[function(require,module,exports){ 13174 /** 13175 * Copyright 2013 Facebook, Inc. 13176 * 13177 * Licensed under the Apache License, Version 2.0 (the "License"); 13178 * you may not use this file except in compliance with the License. 13179 * You may obtain a copy of the License at 13180 * 13181 * http://www.apache.org/licenses/LICENSE-2.0 13182 * 13183 * Unless required by applicable law or agreed to in writing, software 13184 * distributed under the License is distributed on an "AS IS" BASIS, 13185 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13186 * See the License for the specific language governing permissions and 13187 * limitations under the License. 13188 * 13189 * @providesModule getReactRootElementInContainer 13190 */ 13191 13192 "use strict"; 13193 13194 var DOC_NODE_TYPE = 9; 13195 13196 /** 13197 * @param {DOMElement|DOMDocument} container DOM element that may contain 13198 * a React component 13199 * @return {?*} DOM element that may have the reactRoot ID, or null. 13200 */ 13201 function getReactRootElementInContainer(container) { 13202 if (!container) { 13203 return null; 13204 } 13205 13206 if (container.nodeType === DOC_NODE_TYPE) { 13207 return container.documentElement; 13208 } else { 13209 return container.firstChild; 13210 } 13211 } 13212 13213 module.exports = getReactRootElementInContainer; 13214 13215 },{}],95:[function(require,module,exports){ 13216 /** 13217 * Copyright 2013 Facebook, Inc. 13218 * 13219 * Licensed under the Apache License, Version 2.0 (the "License"); 13220 * you may not use this file except in compliance with the License. 13221 * You may obtain a copy of the License at 13222 * 13223 * http://www.apache.org/licenses/LICENSE-2.0 13224 * 13225 * Unless required by applicable law or agreed to in writing, software 13226 * distributed under the License is distributed on an "AS IS" BASIS, 13227 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13228 * See the License for the specific language governing permissions and 13229 * limitations under the License. 13230 * 13231 * @providesModule getTextContentAccessor 13232 */ 13233 13234 "use strict"; 13235 13236 var ExecutionEnvironment = require("./ExecutionEnvironment"); 13237 13238 var contentKey = null; 13239 13240 /** 13241 * Gets the key used to access text content on a DOM node. 13242 * 13243 * @return {?string} Key used to access text content. 13244 * @internal 13245 */ 13246 function getTextContentAccessor() { 13247 if (!contentKey && ExecutionEnvironment.canUseDOM) { 13248 contentKey = 'innerText' in document.createElement('div') ? 13249 'innerText' : 13250 'textContent'; 13251 } 13252 return contentKey; 13253 } 13254 13255 module.exports = getTextContentAccessor; 13256 13257 },{"./ExecutionEnvironment":20}],96:[function(require,module,exports){ 13258 /** 13259 * Copyright 2013 Facebook, Inc. 13260 * 13261 * Licensed under the Apache License, Version 2.0 (the "License"); 13262 * you may not use this file except in compliance with the License. 13263 * You may obtain a copy of the License at 13264 * 13265 * http://www.apache.org/licenses/LICENSE-2.0 13266 * 13267 * Unless required by applicable law or agreed to in writing, software 13268 * distributed under the License is distributed on an "AS IS" BASIS, 13269 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13270 * See the License for the specific language governing permissions and 13271 * limitations under the License. 13272 * 13273 * @providesModule getUnboundedScrollPosition 13274 * @typechecks 13275 */ 13276 13277 "use strict"; 13278 13279 /** 13280 * Gets the scroll position of the supplied element or window. 13281 * 13282 * The return values are unbounded, unlike `getScrollPosition`. This means they 13283 * may be negative or exceed the element boundaries (which is possible using 13284 * inertial scrolling). 13285 * 13286 * @param {DOMWindow|DOMElement} scrollable 13287 * @return {object} Map with `x` and `y` keys. 13288 */ 13289 function getUnboundedScrollPosition(scrollable) { 13290 if (scrollable === window) { 13291 return { 13292 x: document.documentElement.scrollLeft || document.body.scrollLeft, 13293 y: document.documentElement.scrollTop || document.body.scrollTop 13294 }; 13295 } 13296 return { 13297 x: scrollable.scrollLeft, 13298 y: scrollable.scrollTop 13299 }; 13300 } 13301 13302 module.exports = getUnboundedScrollPosition; 13303 13304 },{}],97:[function(require,module,exports){ 13305 /** 13306 * Copyright 2013 Facebook, Inc. 13307 * 13308 * Licensed under the Apache License, Version 2.0 (the "License"); 13309 * you may not use this file except in compliance with the License. 13310 * You may obtain a copy of the License at 13311 * 13312 * http://www.apache.org/licenses/LICENSE-2.0 13313 * 13314 * Unless required by applicable law or agreed to in writing, software 13315 * distributed under the License is distributed on an "AS IS" BASIS, 13316 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13317 * See the License for the specific language governing permissions and 13318 * limitations under the License. 13319 * 13320 * @providesModule hyphenate 13321 * @typechecks 13322 */ 13323 13324 var _uppercasePattern = /([A-Z])/g; 13325 13326 /** 13327 * Hyphenates a camelcased string, for example: 13328 * 13329 * > hyphenate('backgroundColor') 13330 * < "background-color" 13331 * 13332 * @param {string} string 13333 * @return {string} 13334 */ 13335 function hyphenate(string) { 13336 return string.replace(_uppercasePattern, '-$1').toLowerCase(); 13337 } 13338 13339 module.exports = hyphenate; 13340 13341 },{}],98:[function(require,module,exports){ 13342 /** 13343 * Copyright 2013 Facebook, Inc. 13344 * 13345 * Licensed under the Apache License, Version 2.0 (the "License"); 13346 * you may not use this file except in compliance with the License. 13347 * You may obtain a copy of the License at 13348 * 13349 * http://www.apache.org/licenses/LICENSE-2.0 13350 * 13351 * Unless required by applicable law or agreed to in writing, software 13352 * distributed under the License is distributed on an "AS IS" BASIS, 13353 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13354 * See the License for the specific language governing permissions and 13355 * limitations under the License. 13356 * 13357 * @providesModule invariant 13358 */ 13359 13360 /** 13361 * Use invariant() to assert state which your program assumes to be true. 13362 * 13363 * Provide sprintf style format and arguments to provide information about 13364 * what broke and what you were expecting. 13365 * 13366 * The invariant message will be stripped in production, but the invariant 13367 * will remain to ensure logic does not differ in production. 13368 */ 13369 13370 function invariant(condition) { 13371 if (!condition) { 13372 throw new Error('Invariant Violation'); 13373 } 13374 } 13375 13376 module.exports = invariant; 13377 13378 if ("production" !== "development") { 13379 var invariantDev = function(condition, format, a, b, c, d, e, f) { 13380 if (format === undefined) { 13381 throw new Error('invariant requires an error message argument'); 13382 } 13383 13384 if (!condition) { 13385 var args = [a, b, c, d, e, f]; 13386 var argIndex = 0; 13387 throw new Error( 13388 'Invariant Violation: ' + 13389 format.replace(/%s/g, function() { return args[argIndex++]; }) 13390 ); 13391 } 13392 }; 13393 13394 module.exports = invariantDev; 13395 } 13396 13397 },{}],99:[function(require,module,exports){ 13398 /** 13399 * Copyright 2013 Facebook, Inc. 13400 * 13401 * Licensed under the Apache License, Version 2.0 (the "License"); 13402 * you may not use this file except in compliance with the License. 13403 * You may obtain a copy of the License at 13404 * 13405 * http://www.apache.org/licenses/LICENSE-2.0 13406 * 13407 * Unless required by applicable law or agreed to in writing, software 13408 * distributed under the License is distributed on an "AS IS" BASIS, 13409 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13410 * See the License for the specific language governing permissions and 13411 * limitations under the License. 13412 * 13413 * @providesModule isEventSupported 13414 */ 13415 13416 "use strict"; 13417 13418 var ExecutionEnvironment = require("./ExecutionEnvironment"); 13419 13420 var testNode, useHasFeature; 13421 if (ExecutionEnvironment.canUseDOM) { 13422 testNode = document.createElement('div'); 13423 useHasFeature = 13424 document.implementation && 13425 document.implementation.hasFeature && 13426 // `hasFeature` always returns true in Firefox 19+. 13427 document.implementation.hasFeature('', '') !== true; 13428 } 13429 13430 /** 13431 * Checks if an event is supported in the current execution environment. 13432 * 13433 * NOTE: This will not work correctly for non-generic events such as `change`, 13434 * `reset`, `load`, `error`, and `select`. 13435 * 13436 * Borrows from Modernizr. 13437 * 13438 * @param {string} eventNameSuffix Event name, e.g. "click". 13439 * @param {?boolean} capture Check if the capture phase is supported. 13440 * @return {boolean} True if the event is supported. 13441 * @internal 13442 * @license Modernizr 3.0.0pre (Custom Build) | MIT 13443 */ 13444 function isEventSupported(eventNameSuffix, capture) { 13445 if (!testNode || (capture && !testNode.addEventListener)) { 13446 return false; 13447 } 13448 var element = document.createElement('div'); 13449 13450 var eventName = 'on' + eventNameSuffix; 13451 var isSupported = eventName in element; 13452 13453 if (!isSupported) { 13454 element.setAttribute(eventName, 'return;'); 13455 isSupported = typeof element[eventName] === 'function'; 13456 if (typeof element[eventName] !== 'undefined') { 13457 element[eventName] = undefined; 13458 } 13459 element.removeAttribute(eventName); 13460 } 13461 13462 if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { 13463 // This is the only way to test support for the `wheel` event in IE9+. 13464 isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); 13465 } 13466 13467 element = null; 13468 return isSupported; 13469 } 13470 13471 module.exports = isEventSupported; 13472 13473 },{"./ExecutionEnvironment":20}],100:[function(require,module,exports){ 13474 /** 13475 * Copyright 2013 Facebook, Inc. 13476 * 13477 * Licensed under the Apache License, Version 2.0 (the "License"); 13478 * you may not use this file except in compliance with the License. 13479 * You may obtain a copy of the License at 13480 * 13481 * http://www.apache.org/licenses/LICENSE-2.0 13482 * 13483 * Unless required by applicable law or agreed to in writing, software 13484 * distributed under the License is distributed on an "AS IS" BASIS, 13485 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13486 * See the License for the specific language governing permissions and 13487 * limitations under the License. 13488 * 13489 * @providesModule isNode 13490 * @typechecks 13491 */ 13492 13493 /** 13494 * @param {*} object The object to check. 13495 * @return {boolean} Whether or not the object is a DOM node. 13496 */ 13497 function isNode(object) { 13498 return !!(object && ( 13499 typeof Node !== 'undefined' ? object instanceof Node : 13500 typeof object === 'object' && 13501 typeof object.nodeType === 'number' && 13502 typeof object.nodeName === 'string' 13503 )); 13504 } 13505 13506 module.exports = isNode; 13507 13508 },{}],101:[function(require,module,exports){ 13509 /** 13510 * Copyright 2013 Facebook, Inc. 13511 * 13512 * Licensed under the Apache License, Version 2.0 (the "License"); 13513 * you may not use this file except in compliance with the License. 13514 * You may obtain a copy of the License at 13515 * 13516 * http://www.apache.org/licenses/LICENSE-2.0 13517 * 13518 * Unless required by applicable law or agreed to in writing, software 13519 * distributed under the License is distributed on an "AS IS" BASIS, 13520 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13521 * See the License for the specific language governing permissions and 13522 * limitations under the License. 13523 * 13524 * @providesModule isTextInputElement 13525 */ 13526 13527 "use strict"; 13528 13529 /** 13530 * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary 13531 */ 13532 var supportedInputTypes = { 13533 'color': true, 13534 'date': true, 13535 'datetime': true, 13536 'datetime-local': true, 13537 'email': true, 13538 'month': true, 13539 'number': true, 13540 'password': true, 13541 'range': true, 13542 'search': true, 13543 'tel': true, 13544 'text': true, 13545 'time': true, 13546 'url': true, 13547 'week': true 13548 }; 13549 13550 function isTextInputElement(elem) { 13551 return elem && ( 13552 (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) || 13553 elem.nodeName === 'TEXTAREA' 13554 ); 13555 } 13556 13557 module.exports = isTextInputElement; 13558 13559 },{}],102:[function(require,module,exports){ 13560 /** 13561 * Copyright 2013 Facebook, Inc. 13562 * 13563 * Licensed under the Apache License, Version 2.0 (the "License"); 13564 * you may not use this file except in compliance with the License. 13565 * You may obtain a copy of the License at 13566 * 13567 * http://www.apache.org/licenses/LICENSE-2.0 13568 * 13569 * Unless required by applicable law or agreed to in writing, software 13570 * distributed under the License is distributed on an "AS IS" BASIS, 13571 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13572 * See the License for the specific language governing permissions and 13573 * limitations under the License. 13574 * 13575 * @providesModule isTextNode 13576 * @typechecks 13577 */ 13578 13579 var isNode = require("./isNode"); 13580 13581 /** 13582 * @param {*} object The object to check. 13583 * @return {boolean} Whether or not the object is a DOM text node. 13584 */ 13585 function isTextNode(object) { 13586 return isNode(object) && object.nodeType == 3; 13587 } 13588 13589 module.exports = isTextNode; 13590 13591 },{"./isNode":100}],103:[function(require,module,exports){ 13592 /** 13593 * Copyright 2013 Facebook, Inc. 13594 * 13595 * Licensed under the Apache License, Version 2.0 (the "License"); 13596 * you may not use this file except in compliance with the License. 13597 * You may obtain a copy of the License at 13598 * 13599 * http://www.apache.org/licenses/LICENSE-2.0 13600 * 13601 * Unless required by applicable law or agreed to in writing, software 13602 * distributed under the License is distributed on an "AS IS" BASIS, 13603 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13604 * See the License for the specific language governing permissions and 13605 * limitations under the License. 13606 * 13607 * @providesModule joinClasses 13608 * @typechecks static-only 13609 */ 13610 13611 "use strict"; 13612 13613 /** 13614 * Combines multiple className strings into one. 13615 * http://jsperf.com/joinclasses-args-vs-array 13616 * 13617 * @param {...?string} classes 13618 * @return {string} 13619 */ 13620 function joinClasses(className/*, ... */) { 13621 if (!className) { 13622 className = ''; 13623 } 13624 var nextClass; 13625 var argLength = arguments.length; 13626 if (argLength > 1) { 13627 for (var ii = 1; ii < argLength; ii++) { 13628 nextClass = arguments[ii]; 13629 nextClass && (className += ' ' + nextClass); 13630 } 13631 } 13632 return className; 13633 } 13634 13635 module.exports = joinClasses; 13636 13637 },{}],104:[function(require,module,exports){ 13638 /** 13639 * Copyright 2013 Facebook, Inc. 13640 * 13641 * Licensed under the Apache License, Version 2.0 (the "License"); 13642 * you may not use this file except in compliance with the License. 13643 * You may obtain a copy of the License at 13644 * 13645 * http://www.apache.org/licenses/LICENSE-2.0 13646 * 13647 * Unless required by applicable law or agreed to in writing, software 13648 * distributed under the License is distributed on an "AS IS" BASIS, 13649 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13650 * See the License for the specific language governing permissions and 13651 * limitations under the License. 13652 * 13653 * @providesModule keyMirror 13654 * @typechecks static-only 13655 */ 13656 13657 "use strict"; 13658 13659 var invariant = require("./invariant"); 13660 13661 /** 13662 * Constructs an enumeration with keys equal to their value. 13663 * 13664 * For example: 13665 * 13666 * var COLORS = keyMirror({blue: null, red: null}); 13667 * var myColor = COLORS.blue; 13668 * var isColorValid = !!COLORS[myColor]; 13669 * 13670 * The last line could not be performed if the values of the generated enum were 13671 * not equal to their keys. 13672 * 13673 * Input: {key1: val1, key2: val2} 13674 * Output: {key1: key1, key2: key2} 13675 * 13676 * @param {object} obj 13677 * @return {object} 13678 */ 13679 var keyMirror = function(obj) { 13680 var ret = {}; 13681 var key; 13682 ("production" !== "development" ? invariant( 13683 obj instanceof Object && !Array.isArray(obj), 13684 'keyMirror(...): Argument must be an object.' 13685 ) : invariant(obj instanceof Object && !Array.isArray(obj))); 13686 for (key in obj) { 13687 if (!obj.hasOwnProperty(key)) { 13688 continue; 13689 } 13690 ret[key] = key; 13691 } 13692 return ret; 13693 }; 13694 13695 module.exports = keyMirror; 13696 13697 },{"./invariant":98}],105:[function(require,module,exports){ 13698 /** 13699 * Copyright 2013 Facebook, Inc. 13700 * 13701 * Licensed under the Apache License, Version 2.0 (the "License"); 13702 * you may not use this file except in compliance with the License. 13703 * You may obtain a copy of the License at 13704 * 13705 * http://www.apache.org/licenses/LICENSE-2.0 13706 * 13707 * Unless required by applicable law or agreed to in writing, software 13708 * distributed under the License is distributed on an "AS IS" BASIS, 13709 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13710 * See the License for the specific language governing permissions and 13711 * limitations under the License. 13712 * 13713 * @providesModule keyOf 13714 */ 13715 13716 /** 13717 * Allows extraction of a minified key. Let's the build system minify keys 13718 * without loosing the ability to dynamically use key strings as values 13719 * themselves. Pass in an object with a single key/val pair and it will return 13720 * you the string key of that single record. Suppose you want to grab the 13721 * value for a key 'className' inside of an object. Key/val minification may 13722 * have aliased that key to be 'xa12'. keyOf({className: null}) will return 13723 * 'xa12' in that case. Resolve keys you want to use once at startup time, then 13724 * reuse those resolutions. 13725 */ 13726 var keyOf = function(oneKeyObj) { 13727 var key; 13728 for (key in oneKeyObj) { 13729 if (!oneKeyObj.hasOwnProperty(key)) { 13730 continue; 13731 } 13732 return key; 13733 } 13734 return null; 13735 }; 13736 13737 13738 module.exports = keyOf; 13739 13740 },{}],106:[function(require,module,exports){ 13741 /** 13742 * Copyright 2013 Facebook, Inc. 13743 * 13744 * Licensed under the Apache License, Version 2.0 (the "License"); 13745 * you may not use this file except in compliance with the License. 13746 * You may obtain a copy of the License at 13747 * 13748 * http://www.apache.org/licenses/LICENSE-2.0 13749 * 13750 * Unless required by applicable law or agreed to in writing, software 13751 * distributed under the License is distributed on an "AS IS" BASIS, 13752 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13753 * See the License for the specific language governing permissions and 13754 * limitations under the License. 13755 * 13756 * @providesModule memoizeStringOnly 13757 * @typechecks static-only 13758 */ 13759 13760 "use strict"; 13761 13762 /** 13763 * Memoizes the return value of a function that accepts one string argument. 13764 * 13765 * @param {function} callback 13766 * @return {function} 13767 */ 13768 function memoizeStringOnly(callback) { 13769 var cache = {}; 13770 return function(string) { 13771 if (cache.hasOwnProperty(string)) { 13772 return cache[string]; 13773 } else { 13774 return cache[string] = callback.call(this, string); 13775 } 13776 }; 13777 } 13778 13779 module.exports = memoizeStringOnly; 13780 13781 },{}],107:[function(require,module,exports){ 13782 /** 13783 * Copyright 2013 Facebook, Inc. 13784 * 13785 * Licensed under the Apache License, Version 2.0 (the "License"); 13786 * you may not use this file except in compliance with the License. 13787 * You may obtain a copy of the License at 13788 * 13789 * http://www.apache.org/licenses/LICENSE-2.0 13790 * 13791 * Unless required by applicable law or agreed to in writing, software 13792 * distributed under the License is distributed on an "AS IS" BASIS, 13793 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13794 * See the License for the specific language governing permissions and 13795 * limitations under the License. 13796 * 13797 * @providesModule merge 13798 */ 13799 13800 "use strict"; 13801 13802 var mergeInto = require("./mergeInto"); 13803 13804 /** 13805 * Shallow merges two structures into a return value, without mutating either. 13806 * 13807 * @param {?object} one Optional object with properties to merge from. 13808 * @param {?object} two Optional object with properties to merge from. 13809 * @return {object} The shallow extension of one by two. 13810 */ 13811 var merge = function(one, two) { 13812 var result = {}; 13813 mergeInto(result, one); 13814 mergeInto(result, two); 13815 return result; 13816 }; 13817 13818 module.exports = merge; 13819 13820 },{"./mergeInto":109}],108:[function(require,module,exports){ 13821 /** 13822 * Copyright 2013 Facebook, Inc. 13823 * 13824 * Licensed under the Apache License, Version 2.0 (the "License"); 13825 * you may not use this file except in compliance with the License. 13826 * You may obtain a copy of the License at 13827 * 13828 * http://www.apache.org/licenses/LICENSE-2.0 13829 * 13830 * Unless required by applicable law or agreed to in writing, software 13831 * distributed under the License is distributed on an "AS IS" BASIS, 13832 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13833 * See the License for the specific language governing permissions and 13834 * limitations under the License. 13835 * 13836 * @providesModule mergeHelpers 13837 * 13838 * requiresPolyfills: Array.isArray 13839 */ 13840 13841 "use strict"; 13842 13843 var invariant = require("./invariant"); 13844 var keyMirror = require("./keyMirror"); 13845 13846 /** 13847 * Maximum number of levels to traverse. Will catch circular structures. 13848 * @const 13849 */ 13850 var MAX_MERGE_DEPTH = 36; 13851 13852 /** 13853 * We won't worry about edge cases like new String('x') or new Boolean(true). 13854 * Functions are considered terminals, and arrays are not. 13855 * @param {*} o The item/object/value to test. 13856 * @return {boolean} true iff the argument is a terminal. 13857 */ 13858 var isTerminal = function(o) { 13859 return typeof o !== 'object' || o === null; 13860 }; 13861 13862 var mergeHelpers = { 13863 13864 MAX_MERGE_DEPTH: MAX_MERGE_DEPTH, 13865 13866 isTerminal: isTerminal, 13867 13868 /** 13869 * Converts null/undefined values into empty object. 13870 * 13871 * @param {?Object=} arg Argument to be normalized (nullable optional) 13872 * @return {!Object} 13873 */ 13874 normalizeMergeArg: function(arg) { 13875 return arg === undefined || arg === null ? {} : arg; 13876 }, 13877 13878 /** 13879 * If merging Arrays, a merge strategy *must* be supplied. If not, it is 13880 * likely the caller's fault. If this function is ever called with anything 13881 * but `one` and `two` being `Array`s, it is the fault of the merge utilities. 13882 * 13883 * @param {*} one Array to merge into. 13884 * @param {*} two Array to merge from. 13885 */ 13886 checkMergeArrayArgs: function(one, two) { 13887 ("production" !== "development" ? invariant( 13888 Array.isArray(one) && Array.isArray(two), 13889 'Critical assumptions about the merge functions have been violated. ' + 13890 'This is the fault of the merge functions themselves, not necessarily ' + 13891 'the callers.' 13892 ) : invariant(Array.isArray(one) && Array.isArray(two))); 13893 }, 13894 13895 /** 13896 * @param {*} one Object to merge into. 13897 * @param {*} two Object to merge from. 13898 */ 13899 checkMergeObjectArgs: function(one, two) { 13900 mergeHelpers.checkMergeObjectArg(one); 13901 mergeHelpers.checkMergeObjectArg(two); 13902 }, 13903 13904 /** 13905 * @param {*} arg 13906 */ 13907 checkMergeObjectArg: function(arg) { 13908 ("production" !== "development" ? invariant( 13909 !isTerminal(arg) && !Array.isArray(arg), 13910 'Critical assumptions about the merge functions have been violated. ' + 13911 'This is the fault of the merge functions themselves, not necessarily ' + 13912 'the callers.' 13913 ) : invariant(!isTerminal(arg) && !Array.isArray(arg))); 13914 }, 13915 13916 /** 13917 * Checks that a merge was not given a circular object or an object that had 13918 * too great of depth. 13919 * 13920 * @param {number} Level of recursion to validate against maximum. 13921 */ 13922 checkMergeLevel: function(level) { 13923 ("production" !== "development" ? invariant( 13924 level < MAX_MERGE_DEPTH, 13925 'Maximum deep merge depth exceeded. You may be attempting to merge ' + 13926 'circular structures in an unsupported way.' 13927 ) : invariant(level < MAX_MERGE_DEPTH)); 13928 }, 13929 13930 /** 13931 * Checks that the supplied merge strategy is valid. 13932 * 13933 * @param {string} Array merge strategy. 13934 */ 13935 checkArrayStrategy: function(strategy) { 13936 ("production" !== "development" ? invariant( 13937 strategy === undefined || strategy in mergeHelpers.ArrayStrategies, 13938 'You must provide an array strategy to deep merge functions to ' + 13939 'instruct the deep merge how to resolve merging two arrays.' 13940 ) : invariant(strategy === undefined || strategy in mergeHelpers.ArrayStrategies)); 13941 }, 13942 13943 /** 13944 * Set of possible behaviors of merge algorithms when encountering two Arrays 13945 * that must be merged together. 13946 * - `clobber`: The left `Array` is ignored. 13947 * - `indexByIndex`: The result is achieved by recursively deep merging at 13948 * each index. (not yet supported.) 13949 */ 13950 ArrayStrategies: keyMirror({ 13951 Clobber: true, 13952 IndexByIndex: true 13953 }) 13954 13955 }; 13956 13957 module.exports = mergeHelpers; 13958 13959 },{"./invariant":98,"./keyMirror":104}],109:[function(require,module,exports){ 13960 /** 13961 * Copyright 2013 Facebook, Inc. 13962 * 13963 * Licensed under the Apache License, Version 2.0 (the "License"); 13964 * you may not use this file except in compliance with the License. 13965 * You may obtain a copy of the License at 13966 * 13967 * http://www.apache.org/licenses/LICENSE-2.0 13968 * 13969 * Unless required by applicable law or agreed to in writing, software 13970 * distributed under the License is distributed on an "AS IS" BASIS, 13971 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13972 * See the License for the specific language governing permissions and 13973 * limitations under the License. 13974 * 13975 * @providesModule mergeInto 13976 * @typechecks static-only 13977 */ 13978 13979 "use strict"; 13980 13981 var mergeHelpers = require("./mergeHelpers"); 13982 13983 var checkMergeObjectArg = mergeHelpers.checkMergeObjectArg; 13984 13985 /** 13986 * Shallow merges two structures by mutating the first parameter. 13987 * 13988 * @param {object} one Object to be merged into. 13989 * @param {?object} two Optional object with properties to merge from. 13990 */ 13991 function mergeInto(one, two) { 13992 checkMergeObjectArg(one); 13993 if (two != null) { 13994 checkMergeObjectArg(two); 13995 for (var key in two) { 13996 if (!two.hasOwnProperty(key)) { 13997 continue; 13998 } 13999 one[key] = two[key]; 14000 } 14001 } 14002 } 14003 14004 module.exports = mergeInto; 14005 14006 },{"./mergeHelpers":108}],110:[function(require,module,exports){ 14007 /** 14008 * Copyright 2013 Facebook, Inc. 14009 * 14010 * Licensed under the Apache License, Version 2.0 (the "License"); 14011 * you may not use this file except in compliance with the License. 14012 * You may obtain a copy of the License at 14013 * 14014 * http://www.apache.org/licenses/LICENSE-2.0 14015 * 14016 * Unless required by applicable law or agreed to in writing, software 14017 * distributed under the License is distributed on an "AS IS" BASIS, 14018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14019 * See the License for the specific language governing permissions and 14020 * limitations under the License. 14021 * 14022 * @providesModule mixInto 14023 */ 14024 14025 "use strict"; 14026 14027 /** 14028 * Simply copies properties to the prototype. 14029 */ 14030 var mixInto = function(constructor, methodBag) { 14031 var methodName; 14032 for (methodName in methodBag) { 14033 if (!methodBag.hasOwnProperty(methodName)) { 14034 continue; 14035 } 14036 constructor.prototype[methodName] = methodBag[methodName]; 14037 } 14038 }; 14039 14040 module.exports = mixInto; 14041 14042 },{}],111:[function(require,module,exports){ 14043 /** 14044 * Copyright 2013 Facebook, Inc. 14045 * 14046 * Licensed under the Apache License, Version 2.0 (the "License"); 14047 * you may not use this file except in compliance with the License. 14048 * You may obtain a copy of the License at 14049 * 14050 * http://www.apache.org/licenses/LICENSE-2.0 14051 * 14052 * Unless required by applicable law or agreed to in writing, software 14053 * distributed under the License is distributed on an "AS IS" BASIS, 14054 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14055 * See the License for the specific language governing permissions and 14056 * limitations under the License. 14057 * 14058 * @providesModule mutateHTMLNodeWithMarkup 14059 * @typechecks static-only 14060 */ 14061 14062 /*jslint evil: true */ 14063 14064 'use strict'; 14065 14066 var createNodesFromMarkup = require("./createNodesFromMarkup"); 14067 var filterAttributes = require("./filterAttributes"); 14068 var invariant = require("./invariant"); 14069 14070 /** 14071 * You can't set the innerHTML of a document. Unless you have 14072 * this function. 14073 * 14074 * @param {DOMElement} node with tagName == 'html' 14075 * @param {string} markup markup string including <html>. 14076 */ 14077 function mutateHTMLNodeWithMarkup(node, markup) { 14078 ("production" !== "development" ? invariant( 14079 node.tagName.toLowerCase() === 'html', 14080 'mutateHTMLNodeWithMarkup(): node must have tagName of "html", got %s', 14081 node.tagName 14082 ) : invariant(node.tagName.toLowerCase() === 'html')); 14083 14084 markup = markup.trim(); 14085 ("production" !== "development" ? invariant( 14086 markup.toLowerCase().indexOf('<html') === 0, 14087 'mutateHTMLNodeWithMarkup(): markup must start with <html' 14088 ) : invariant(markup.toLowerCase().indexOf('<html') === 0)); 14089 14090 // First let's extract the various pieces of markup. 14091 var htmlOpenTagEnd = markup.indexOf('>') + 1; 14092 var htmlCloseTagStart = markup.lastIndexOf('<'); 14093 var htmlOpenTag = markup.substring(0, htmlOpenTagEnd); 14094 var innerHTML = markup.substring(htmlOpenTagEnd, htmlCloseTagStart); 14095 14096 // Now for the fun stuff. Pass through both sets of attributes and 14097 // bring them up-to-date. We get the new set by creating a markup 14098 // fragment. 14099 var shouldExtractAttributes = htmlOpenTag.indexOf(' ') > -1; 14100 var attributeHolder = null; 14101 14102 if (shouldExtractAttributes) { 14103 // We extract the attributes by creating a <span> and evaluating 14104 // the node. 14105 attributeHolder = createNodesFromMarkup( 14106 htmlOpenTag.replace('html ', 'span ') + '</span>' 14107 )[0]; 14108 14109 // Add all attributes present in attributeHolder 14110 var attributesToSet = filterAttributes( 14111 attributeHolder, 14112 function(attr) { 14113 return node.getAttributeNS(attr.namespaceURI, attr.name) !== attr.value; 14114 } 14115 ); 14116 attributesToSet.forEach(function(attr) { 14117 node.setAttributeNS(attr.namespaceURI, attr.name, attr.value); 14118 }); 14119 } 14120 14121 // Remove all attributes not present in attributeHolder 14122 var attributesToRemove = filterAttributes( 14123 node, 14124 function(attr) { 14125 // Remove all attributes if attributeHolder is null or if it does not have 14126 // the desired attribute. 14127 return !( 14128 attributeHolder && 14129 attributeHolder.hasAttributeNS(attr.namespaceURI, attr.name) 14130 ); 14131 } 14132 ); 14133 attributesToRemove.forEach(function(attr) { 14134 node.removeAttributeNS(attr.namespaceURI, attr.name); 14135 }); 14136 14137 // Finally, set the inner HTML. No tricks needed. Do this last to 14138 // minimize likelihood of triggering reflows. 14139 node.innerHTML = innerHTML; 14140 } 14141 14142 module.exports = mutateHTMLNodeWithMarkup; 14143 14144 },{"./createNodesFromMarkup":80,"./filterAttributes":86,"./invariant":98}],112:[function(require,module,exports){ 14145 /** 14146 * Copyright 2013 Facebook, Inc. 14147 * 14148 * Licensed under the Apache License, Version 2.0 (the "License"); 14149 * you may not use this file except in compliance with the License. 14150 * You may obtain a copy of the License at 14151 * 14152 * http://www.apache.org/licenses/LICENSE-2.0 14153 * 14154 * Unless required by applicable law or agreed to in writing, software 14155 * distributed under the License is distributed on an "AS IS" BASIS, 14156 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14157 * See the License for the specific language governing permissions and 14158 * limitations under the License. 14159 * 14160 * @providesModule objMap 14161 */ 14162 14163 "use strict"; 14164 14165 /** 14166 * For each key/value pair, invokes callback func and constructs a resulting 14167 * object which contains, for every key in obj, values that are the result of 14168 * of invoking the function: 14169 * 14170 * func(value, key, iteration) 14171 * 14172 * @param {?object} obj Object to map keys over 14173 * @param {function} func Invoked for each key/val pair. 14174 * @param {?*} context 14175 * @return {?object} Result of mapping or null if obj is falsey 14176 */ 14177 function objMap(obj, func, context) { 14178 if (!obj) { 14179 return null; 14180 } 14181 var i = 0; 14182 var ret = {}; 14183 for (var key in obj) { 14184 if (obj.hasOwnProperty(key)) { 14185 ret[key] = func.call(context, obj[key], key, i++); 14186 } 14187 } 14188 return ret; 14189 } 14190 14191 module.exports = objMap; 14192 14193 },{}],113:[function(require,module,exports){ 14194 /** 14195 * Copyright 2013 Facebook, Inc. 14196 * 14197 * Licensed under the Apache License, Version 2.0 (the "License"); 14198 * you may not use this file except in compliance with the License. 14199 * You may obtain a copy of the License at 14200 * 14201 * http://www.apache.org/licenses/LICENSE-2.0 14202 * 14203 * Unless required by applicable law or agreed to in writing, software 14204 * distributed under the License is distributed on an "AS IS" BASIS, 14205 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14206 * See the License for the specific language governing permissions and 14207 * limitations under the License. 14208 * 14209 * @providesModule objMapKeyVal 14210 */ 14211 14212 "use strict"; 14213 14214 /** 14215 * Behaves the same as `objMap` but invokes func with the key first, and value 14216 * second. Use `objMap` unless you need this special case. 14217 * Invokes func as: 14218 * 14219 * func(key, value, iteration) 14220 * 14221 * @param {?object} obj Object to map keys over 14222 * @param {!function} func Invoked for each key/val pair. 14223 * @param {?*} context 14224 * @return {?object} Result of mapping or null if obj is falsey 14225 */ 14226 function objMapKeyVal(obj, func, context) { 14227 if (!obj) { 14228 return null; 14229 } 14230 var i = 0; 14231 var ret = {}; 14232 for (var key in obj) { 14233 if (obj.hasOwnProperty(key)) { 14234 ret[key] = func.call(context, key, obj[key], i++); 14235 } 14236 } 14237 return ret; 14238 } 14239 14240 module.exports = objMapKeyVal; 14241 14242 },{}],114:[function(require,module,exports){ 14243 /** 14244 * Copyright 2013 Facebook, Inc. 14245 * 14246 * Licensed under the Apache License, Version 2.0 (the "License"); 14247 * you may not use this file except in compliance with the License. 14248 * You may obtain a copy of the License at 14249 * 14250 * http://www.apache.org/licenses/LICENSE-2.0 14251 * 14252 * Unless required by applicable law or agreed to in writing, software 14253 * distributed under the License is distributed on an "AS IS" BASIS, 14254 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14255 * See the License for the specific language governing permissions and 14256 * limitations under the License. 14257 * 14258 * @providesModule performanceNow 14259 * @typechecks static-only 14260 */ 14261 14262 "use strict"; 14263 14264 var ExecutionEnvironment = require("./ExecutionEnvironment"); 14265 14266 /** 14267 * Detect if we can use window.performance.now() and gracefully 14268 * fallback to Date.now() if it doesn't exist. 14269 * We need to support Firefox < 15 for now due to Facebook's webdriver 14270 * infrastructure. 14271 */ 14272 var performance = null; 14273 14274 if (ExecutionEnvironment.canUseDOM) { 14275 performance = window.performance || window.webkitPerformance; 14276 } 14277 14278 if (!performance || !performance.now) { 14279 performance = Date; 14280 } 14281 14282 var performanceNow = performance.now.bind(performance); 14283 14284 module.exports = performanceNow; 14285 14286 },{"./ExecutionEnvironment":20}],115:[function(require,module,exports){ 14287 /** 14288 * Copyright 2013 Facebook, Inc. 14289 * 14290 * Licensed under the Apache License, Version 2.0 (the "License"); 14291 * you may not use this file except in compliance with the License. 14292 * You may obtain a copy of the License at 14293 * 14294 * http://www.apache.org/licenses/LICENSE-2.0 14295 * 14296 * Unless required by applicable law or agreed to in writing, software 14297 * distributed under the License is distributed on an "AS IS" BASIS, 14298 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14299 * See the License for the specific language governing permissions and 14300 * limitations under the License. 14301 * 14302 * @providesModule shallowEqual 14303 */ 14304 14305 "use strict"; 14306 14307 /** 14308 * Performs equality by iterating through keys on an object and returning 14309 * false when any key has values which are not strictly equal between 14310 * objA and objB. Returns true when the values of all keys are strictly equal. 14311 * 14312 * @return {boolean} 14313 */ 14314 function shallowEqual(objA, objB) { 14315 if (objA === objB) { 14316 return true; 14317 } 14318 var key; 14319 // Test for A's keys different from B. 14320 for (key in objA) { 14321 if (objA.hasOwnProperty(key) && 14322 (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) { 14323 return false; 14324 } 14325 } 14326 // Test for B'a keys missing from A. 14327 for (key in objB) { 14328 if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) { 14329 return false; 14330 } 14331 } 14332 return true; 14333 } 14334 14335 module.exports = shallowEqual; 14336 14337 },{}],116:[function(require,module,exports){ 14338 /** 14339 * Copyright 2013 Facebook, Inc. 14340 * 14341 * Licensed under the Apache License, Version 2.0 (the "License"); 14342 * you may not use this file except in compliance with the License. 14343 * You may obtain a copy of the License at 14344 * 14345 * http://www.apache.org/licenses/LICENSE-2.0 14346 * 14347 * Unless required by applicable law or agreed to in writing, software 14348 * distributed under the License is distributed on an "AS IS" BASIS, 14349 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14350 * See the License for the specific language governing permissions and 14351 * limitations under the License. 14352 * 14353 * @providesModule traverseAllChildren 14354 */ 14355 14356 "use strict"; 14357 14358 var ReactComponent = require("./ReactComponent"); 14359 var ReactTextComponent = require("./ReactTextComponent"); 14360 14361 var invariant = require("./invariant"); 14362 14363 /** 14364 * TODO: Test that: 14365 * 1. `mapChildren` transforms strings and numbers into `ReactTextComponent`. 14366 * 2. it('should fail when supplied duplicate key', function() { 14367 * 3. That a single child and an array with one item have the same key pattern. 14368 * }); 14369 */ 14370 14371 /** 14372 * @param {?*} children Children tree container. 14373 * @param {!string} nameSoFar Name of the key path so far. 14374 * @param {!number} indexSoFar Number of children encountered until this point. 14375 * @param {!function} callback Callback to invoke with each child found. 14376 * @param {?*} traverseContext Used to pass information throughout the traversal 14377 * process. 14378 * @return {!number} The number of children in this subtree. 14379 */ 14380 var traverseAllChildrenImpl = 14381 function(children, nameSoFar, indexSoFar, callback, traverseContext) { 14382 var subtreeCount = 0; // Count of children found in the current subtree. 14383 if (Array.isArray(children)) { 14384 for (var i = 0; i < children.length; i++) { 14385 var child = children[i]; 14386 var nextName = nameSoFar + ReactComponent.getKey(child, i); 14387 var nextIndex = indexSoFar + subtreeCount; 14388 subtreeCount += traverseAllChildrenImpl( 14389 child, 14390 nextName, 14391 nextIndex, 14392 callback, 14393 traverseContext 14394 ); 14395 } 14396 } else { 14397 var type = typeof children; 14398 var isOnlyChild = nameSoFar === ''; 14399 // If it's the only child, treat the name as if it was wrapped in an array 14400 // so that it's consistent if the number of children grows 14401 var storageName = isOnlyChild ? 14402 ReactComponent.getKey(children, 0): 14403 nameSoFar; 14404 if (children === null || children === undefined || type === 'boolean') { 14405 // All of the above are perceived as null. 14406 callback(traverseContext, null, storageName, indexSoFar); 14407 subtreeCount = 1; 14408 } else if (children.mountComponentIntoNode) { 14409 callback(traverseContext, children, storageName, indexSoFar); 14410 subtreeCount = 1; 14411 } else { 14412 if (type === 'object') { 14413 ("production" !== "development" ? invariant( 14414 !children || children.nodeType !== 1, 14415 'traverseAllChildren(...): Encountered an invalid child; DOM ' + 14416 'elements are not valid children of React components.' 14417 ) : invariant(!children || children.nodeType !== 1)); 14418 for (var key in children) { 14419 if (children.hasOwnProperty(key)) { 14420 subtreeCount += traverseAllChildrenImpl( 14421 children[key], 14422 nameSoFar + '{' + key + '}', 14423 indexSoFar + subtreeCount, 14424 callback, 14425 traverseContext 14426 ); 14427 } 14428 } 14429 } else if (type === 'string') { 14430 var normalizedText = new ReactTextComponent(children); 14431 callback(traverseContext, normalizedText, storageName, indexSoFar); 14432 subtreeCount += 1; 14433 } else if (type === 'number') { 14434 var normalizedNumber = new ReactTextComponent('' + children); 14435 callback(traverseContext, normalizedNumber, storageName, indexSoFar); 14436 subtreeCount += 1; 14437 } 14438 } 14439 } 14440 return subtreeCount; 14441 }; 14442 14443 /** 14444 * Traverses children that are typically specified as `props.children`, but 14445 * might also be specified through attributes: 14446 * 14447 * - `traverseAllChildren(this.props.children, ...)` 14448 * - `traverseAllChildren(this.props.leftPanelChildren, ...)` 14449 * 14450 * The `traverseContext` is an optional argument that is passed through the 14451 * entire traversal. It can be used to store accumulations or anything else that 14452 * the callback might find relevant. 14453 * 14454 * @param {?*} children Children tree object. 14455 * @param {!function} callback To invoke upon traversing each child. 14456 * @param {?*} traverseContext Context for traversal. 14457 */ 14458 function traverseAllChildren(children, callback, traverseContext) { 14459 if (children !== null && children !== undefined) { 14460 traverseAllChildrenImpl(children, '', 0, callback, traverseContext); 14461 } 14462 } 14463 14464 module.exports = traverseAllChildren; 14465 14466 },{"./ReactComponent":25,"./ReactTextComponent":60,"./invariant":98}]},{},[24]) 14467 (24) 14468 }); 14469 ;