author | Brian R. Bondy <netzen@gmail.com> |
Thu, 16 Oct 2014 14:10:17 -0400 | |
changeset 491331 | d61f80a32dc158f9ce0c254921006675614f54a8 |
parent 491330 | 9ebe995cd8c354e49a795b4771415b96e0ec8b7e (current diff) |
parent 210706 | 77f3ca1fe052ca3eced92af99221e29a7fc6c36b (diff) |
child 491332 | 18dc1708c1b78859af183b7ab891b517a5699cf0 |
push id | 47343 |
push user | bmo:dothayer@mozilla.com |
push date | Wed, 01 Mar 2017 22:58:58 +0000 |
milestone | 36.0a1 |
--- a/.hgtags +++ b/.hgtags @@ -99,8 +99,9 @@ 2520866d58740851d862c7c59246a4e3f8b4a176 05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE 9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE ba2cc1eda988a1614d8986ae145d28e1268409b9 FIREFOX_AURORA_29_BASE 83c9853e136451474dfa6d1aaa60a7fca7d2d83a FIREFOX_AURORA_30_BASE cfde3603b0206e119abea76fdd6e134b634348f1 FIREFOX_AURORA_31_BASE 16f3cac5e8fe471e12f76d6a94a477b14e78df7c FIREFOX_AURORA_32_BASE dc23164ba2a289a8b22902e30990c77d9677c214 FIREFOX_AURORA_33_BASE c360f3d1c00d73b0c1fb0a2c0da525cb55e58b83 FIREFOX_AURORA_34_BASE +cec1a116c4f9a3e887d52e9a26e8bbec200fe162 FIREFOX_AURORA_35_BASE
--- a/CLOBBER +++ b/CLOBBER @@ -17,9 +17,9 @@ # # Modifying this file will now automatically clobber the buildbot machines \o/ # # Are you updating CLOBBER because you think it's needed for your WebIDL # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1069071: IPDL changes require CLOBBER (second time around) +Bug 1061335 - CLOBBER for Win32 compiler update.
--- a/accessible/base/nsCoreUtils.cpp +++ b/accessible/base/nsCoreUtils.cpp @@ -52,17 +52,17 @@ nsCoreUtils::HasClickListener(nsIContent (listenerManager->HasListenersFor(nsGkAtoms::onclick) || listenerManager->HasListenersFor(nsGkAtoms::onmousedown) || listenerManager->HasListenersFor(nsGkAtoms::onmouseup)); } void nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj, int32_t aRowIndex, nsITreeColumn *aColumn, - const nsCString& aPseudoElt) + const nsAString& aPseudoElt) { nsCOMPtr<nsIDOMElement> tcElm; aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm)); if (!tcElm) return; nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm)); nsIDocument *document = tcContent->GetCurrentDoc();
--- a/accessible/base/nsCoreUtils.h +++ b/accessible/base/nsCoreUtils.h @@ -39,17 +39,17 @@ public: * @param aTreeBoxObj [in] tree box object * @param aRowIndex [in] row index * @param aColumn [in] column object * @param aPseudoElm [in] pseudo elemenet inside the cell, see * nsITreeBoxObject for available values */ static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj, int32_t aRowIndex, nsITreeColumn *aColumn, - const nsCString& aPseudoElt = EmptyCString()); + const nsAString& aPseudoElt = EmptyString()); /** * Send mouse event to the given element. * * @param aEventType [in] an event type (see BasicEvents.h for constants) * @param aX [in] x coordinate in dev pixels * @param aY [in] y coordinate in dev pixels * @param aContent [in] the element @@ -309,9 +309,8 @@ public: static bool IsWhitespace(char16_t aChar) { return aChar == ' ' || aChar == '\n' || aChar == '\r' || aChar == '\t' || aChar == 0xa0; } }; #endif -
--- a/accessible/interfaces/nsIAccessiblePivot.idl +++ b/accessible/interfaces/nsIAccessiblePivot.idl @@ -186,17 +186,17 @@ interface nsIAccessiblePivot : nsISuppor * @param aObserver [in] the observer object to remove from being notified. */ void removeObserver(in nsIAccessiblePivotObserver aObserver); }; /** * An observer interface for pivot changes. */ -[scriptable, uuid(b6508c5e-c081-467d-835c-613eedf9ee9b)] +[scriptable, uuid(6006e502-3861-49bd-aba1-fa6d2e74e237)] interface nsIAccessiblePivotObserver : nsISupports { /** * Called when the pivot changes. * * @param aPivot [in] the pivot that has changed. * @param aOldAccessible [in] the old pivot position before the change, * or null.
--- a/accessible/jsat/AccessFu.jsm +++ b/accessible/jsat/AccessFu.jsm @@ -15,16 +15,18 @@ this.EXPORTED_SYMBOLS = ['AccessFu']; // Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/accessibility/Utils.jsm'); const ACCESSFU_DISABLE = 0; // jshint ignore:line const ACCESSFU_ENABLE = 1; const ACCESSFU_AUTO = 2; const SCREENREADER_SETTING = 'accessibility.screenreader'; +const QUICKNAV_MODES_PREF = 'accessibility.accessfu.quicknav_modes'; +const QUICKNAV_INDEX_PREF = 'accessibility.accessfu.quicknav_index'; this.AccessFu = { // jshint ignore:line /** * Initialize chrome-layer accessibility functionality. * If accessibility is enabled on the platform, then a special accessibility * mode is started. */ attach: function attach(aWindow) { @@ -98,21 +100,28 @@ this.AccessFu = { // jshint ignore:line let stylesheet = Utils.win.document.createProcessingInstruction( 'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"'); Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild); this.stylesheet = Cu.getWeakReference(stylesheet); // Populate quicknav modes this._quicknavModesPref = - new PrefCache( - 'accessibility.accessfu.quicknav_modes', - (aName, aValue) => { - this.Input.quickNavMode.updateModes(aValue); - }, true); + new PrefCache(QUICKNAV_MODES_PREF, (aName, aValue, aFirstRun) => { + this.Input.quickNavMode.updateModes(aValue); + if (!aFirstRun) { + // If the modes change, reset the current mode index to 0. + Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, 0); + } + }, true); + + this._quicknavCurrentModePref = + new PrefCache(QUICKNAV_INDEX_PREF, (aName, aValue) => { + this.Input.quickNavMode.updateCurrentMode(Number(aValue)); + }, true); // Check for output notification this._notifyOutputPref = new PrefCache('accessibility.accessfu.notify_output'); this.Input.start(); Output.start(); @@ -662,27 +671,31 @@ var Input = { aGesture.touches[0].y); break; case 'doubletap1': this.activateCurrent(); break; case 'taphold1': this.sendContextMenuMessage(); break; + case 'doubletaphold1': + Utils.dispatchChromeEvent('accessibility-control', 'quicknav-menu'); + break; case 'swiperight1': this.moveCursor('moveNext', 'Simple', 'gestures'); break; case 'swipeleft1': this.moveCursor('movePrevious', 'Simple', 'gesture'); break; case 'swipeup1': - this.contextAction('backward'); + this.moveCursor( + 'movePrevious', this.quickNavMode.current, 'gesture', true); break; case 'swipedown1': - this.contextAction('forward'); + this.moveCursor('moveNext', this.quickNavMode.current, 'gesture', true); break; case 'exploreend1': case 'dwellend1': this.activateCurrent(null, true); break; case 'swiperight2': if (aGesture.edge) { Utils.dispatchChromeEvent('accessibility-control', @@ -824,27 +837,22 @@ var Input = { {rule: aRule, x: aX, y: aY, origin: 'top'}); } else { let win = Utils.win; Utils.winUtils.sendMouseEvent('mousemove', aX - win.mozInnerScreenX, aY - win.mozInnerScreenY, 0, 0, 0); } }, - moveCursor: function moveCursor(aAction, aRule, aInputType) { + moveCursor: function moveCursor(aAction, aRule, aInputType, aAdjustRange) { let mm = Utils.getMessageManager(Utils.CurrentBrowser); mm.sendAsyncMessage('AccessFu:MoveCursor', - {action: aAction, rule: aRule, - origin: 'top', inputType: aInputType}); - }, - - contextAction: function contextAction(aDirection) { - // XXX: For now, the only supported context action is adjusting a range. - let mm = Utils.getMessageManager(Utils.CurrentBrowser); - mm.sendAsyncMessage('AccessFu:AdjustRange', {direction: aDirection}); + { action: aAction, rule: aRule, + origin: 'top', inputType: aInputType, + adjustRange: aAdjustRange }); }, moveByGranularity: function moveByGranularity(aDetails) { const MOVEMENT_GRANULARITY_PARAGRAPH = 8; if (!this.editState.editing) { if (aDetails.granularity === MOVEMENT_GRANULARITY_PARAGRAPH) { this.moveCursor('move' + aDetails.direction, 'Paragraph', 'gesture'); @@ -952,31 +960,34 @@ var Input = { }, quickNavMode: { get current() { return this.modes[this._currentIndex]; }, previous: function quickNavMode_previous() { - if (--this._currentIndex < 0) { - this._currentIndex = this.modes.length - 1; - } + Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, + this._currentIndex > 0 ? + this._currentIndex - 1 : this.modes.length - 1); }, next: function quickNavMode_next() { - if (++this._currentIndex >= this.modes.length) { - this._currentIndex = 0; - } + Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, + this._currentIndex + 1 >= this.modes.length ? + 0 : this._currentIndex + 1); }, updateModes: function updateModes(aModes) { if (aModes) { this.modes = aModes.split(','); } else { this.modes = []; } }, - _currentIndex: -1 + updateCurrentMode: function updateCurrentMode(aModeIndex) { + Logger.debug('Quicknav mode:', this.modes[aModeIndex]); + this._currentIndex = aModeIndex; + } } }; AccessFu.Input = Input;
--- a/accessible/jsat/ContentControl.jsm +++ b/accessible/jsat/ContentControl.jsm @@ -89,23 +89,28 @@ this.ContentControl.prototype = { Logger.logException( x, 'Error handling message: ' + JSON.stringify(aMessage.json)); } }, handleMoveCursor: function cc_handleMoveCursor(aMessage) { let origin = aMessage.json.origin; let action = aMessage.json.action; + let adjustRange = aMessage.json.adjustRange; let vc = this.vc; if (origin != 'child' && this.sendToChild(vc, aMessage)) { // Forwarded succesfully to child cursor. return; } + if (adjustRange && this.adjustRange(vc.position, action === 'moveNext')) { + return; + } + let moved = vc[action](TraversalRules[aMessage.json.rule]); if (moved) { if (origin === 'child') { // We just stepped out of a child, clear child cursor. Utils.getMessageManager(aMessage.target).sendAsyncMessage( 'AccessFu:ClearCursor', {}); } else { @@ -117,20 +122,24 @@ this.ContentControl.prototype = { } else if (action === 'movePrevious') { childAction = 'moveLast'; } // Attempt to forward move to a potential child cursor in our // new position. this.sendToChild(vc, aMessage, { action: childAction }, true); } - } else if (!this._childMessageSenders.has(aMessage.target)) { - // We failed to move, and the message is not from a child, so forward - // to parent. + } else if (!this._childMessageSenders.has(aMessage.target) && + origin !== 'top') { + // We failed to move, and the message is not from a parent, so forward + // to it. this.sendToParent(aMessage); + } else { + this._contentScope.get().sendAsyncMessage('AccessFu:Present', + Presentation.noMove(action)); } }, handleEvent: function cc_handleEvent(aEvent) { if (aEvent.type === 'mousemove') { this.handleMoveToPoint( { json: { x: aEvent.screenX, y: aEvent.screenY, rule: 'Simple' } }); } @@ -164,17 +173,17 @@ this.ContentControl.prototype = { handleActivate: function cc_handleActivate(aMessage) { let activateAccessible = (aAccessible) => { Logger.debug(() => { return ['activateAccessible', Logger.accessibleToString(aAccessible)]; }); try { if (aMessage.json.activateIfKey && - aAccessible.role != Roles.KEY) { + !Utils.isActivatableOnFingerUp(aAccessible)) { // Only activate keys, don't do anything on other objects. return; } } catch (e) { // accessible is invalid. Silently fail. return; } @@ -205,17 +214,17 @@ this.ContentControl.prototype = { for (let eventType of ['mousedown', 'mouseup']) { let evt = this.document.createEvent('MouseEvents'); evt.initMouseEvent(eventType, true, true, this.window, x, y, 0, 0, 0, false, false, false, false, 0, null); node.dispatchEvent(evt); } } - if (aAccessible.role !== Roles.KEY) { + if (!Utils.isActivatableOnFingerUp(aAccessible)) { // Keys will typically have a sound of their own. this._contentScope.get().sendAsyncMessage('AccessFu:Present', Presentation.actionInvoked(aAccessible, 'click')); } }; let focusedAcc = Utils.AccRetrieval.getAccessibleFor( this.document.activeElement); @@ -252,16 +261,47 @@ this.ContentControl.prototype = { let vc = this.vc; if (!this.sendToChild(vc, aMessage, null, true)) { let position = vc.position; activateAccessible(getActivatableDescendant(position) || position); } }, + adjustRange: function cc_adjustRange(aAccessible, aStepUp) { + let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible; + try { + acc.QueryInterface(Ci.nsIAccessibleValue); + } catch (x) { + // This is not an adjustable, return false. + return false; + } + + let elem = acc.DOMNode; + if (!elem) { + return false; + } + + if (elem.tagName === 'INPUT' && elem.type === 'range') { + elem[aStepUp ? 'stepDown' : 'stepUp'](); + let evt = this.document.createEvent('UIEvent'); + evt.initEvent('change', true, true); + elem.dispatchEvent(evt); + } else { + let evt = this.document.createEvent('KeyboardEvent'); + let keycode = aStepUp ? content.KeyEvent.DOM_VK_DOWN : + content.KeyEvent.DOM_VK_UP; + evt.initKeyEvent( + "keypress", false, true, null, false, false, false, false, keycode, 0); + elem.dispatchEvent(evt); + } + + return true; + }, + handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) { // XXX: Add sendToChild. Right now this is only used in Android, so no need. let direction = aMessage.json.direction; let granularity; switch(aMessage.json.granularity) { case MOVEMENT_GRANULARITY_CHARACTER: granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
--- a/accessible/jsat/EventManager.jsm +++ b/accessible/jsat/EventManager.jsm @@ -56,16 +56,17 @@ this.EventManager.prototype = { AccessibilityEventObserver.addListener(this); this.webProgress.addProgressListener(this, (Ci.nsIWebProgress.NOTIFY_STATE_ALL | Ci.nsIWebProgress.NOTIFY_LOCATION)); this.addEventListener('wheel', this, true); this.addEventListener('scroll', this, true); this.addEventListener('resize', this, true); + this._preDialogPosition = new WeakMap(); } this.present(Presentation.tabStateChanged(null, 'newtab')); } catch (x) { Logger.logException(x, 'Failed to start EventManager'); } }, @@ -73,16 +74,17 @@ this.EventManager.prototype = { // late). It is only called when the AccessFu is disabled explicitly. stop: function stop() { if (!this._started) { return; } Logger.debug('EventManager.stop'); AccessibilityEventObserver.removeListener(this); try { + this._preDialogPosition.clear(); this.webProgress.removeProgressListener(this); this.removeEventListener('wheel', this, true); this.removeEventListener('scroll', this, true); this.removeEventListener('resize', this, true); } catch (x) { // contentScope is dead. } finally { this._started = false; @@ -267,18 +269,18 @@ this.EventManager.prototype = { { let position = this.contentControl.vc.position; if (aEvent.accessible === aEvent.accessibleDocument || (position && Utils.isInSubtree(position, aEvent.accessible))) { // Do not automove into the document if the virtual cursor is already // positioned inside it. break; } - this.contentControl.autoMove( - aEvent.accessible, { delay: 500 }); + this._preDialogPosition.set(aEvent.accessible.DOMNode, position); + this.contentControl.autoMove(aEvent.accessible, { delay: 500 }); break; } case Events.VALUE_CHANGE: { let position = this.contentControl.vc.position; let target = aEvent.accessible; if (position === target || Utils.getEmbeddedControl(position) === target) { @@ -361,17 +363,18 @@ this.EventManager.prototype = { return; } this._queueLiveEvent(Events.HIDE, liveRegion, isPolite); } else { let vc = Utils.getVirtualCursor(this.contentScope.content.document); if (vc.position && (Utils.getState(vc.position).contains(States.DEFUNCT) || Utils.isInSubtree(vc.position, acc))) { - let position = aEvent.targetPrevSibling || aEvent.targetParent; + let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) || + aEvent.targetPrevSibling || aEvent.targetParent; if (!position) { try { position = acc.previousSibling; } catch (x) { // Accessible is unattached from the accessible tree. position = acc.parent; } }
--- a/accessible/jsat/Presentation.jsm +++ b/accessible/jsat/Presentation.jsm @@ -112,16 +112,21 @@ Presenter.prototype = { editingModeChanged: function editingModeChanged(aIsEditing) {}, // jshint ignore:line /** * Announce something. Typically an app state change. */ announce: function announce(aAnnouncement) {}, // jshint ignore:line + /** + * User tried to move cursor forward or backward with no success. + * @param {string} aMoveMethod move method that was used (eg. 'moveNext'). + */ + noMove: function noMove(aMoveMethod) {}, /** * Announce a live region. * @param {PivotContext} aContext context object for an accessible. * @param {boolean} aIsPolite A politeness level for a live region. * @param {boolean} aIsHide An indicator of hide/remove event. * @param {string} aModifiedText Optional modified text. */ @@ -477,17 +482,17 @@ B2GPresenter.prototype.pivotChanged = return { type: this.type, details: { eventType: 'vc-change', data: UtteranceGenerator.genForContext(aContext), options: { pattern: this.PIVOT_CHANGE_HAPTIC_PATTERN, - isKey: aContext.accessible.role === Roles.KEY, + isKey: Utils.isActivatableOnFingerUp(aContext.accessible), reason: this.pivotChangedReasons[aReason], isUserInput: aIsUserInput } } }; }; B2GPresenter.prototype.valueChanged = @@ -531,16 +536,27 @@ B2GPresenter.prototype.announce = type: this.type, details: { eventType: 'announcement', data: aAnnouncement } }; }; +B2GPresenter.prototype.noMove = + function B2GPresenter_noMove(aMoveMethod) { + return { + type: this.type, + details: { + eventType: 'no-move', + data: aMoveMethod + } + }; + }; + /** * A braille presenter */ function BraillePresenter() {} BraillePresenter.prototype = Object.create(Presenter.prototype); BraillePresenter.prototype.type = 'Braille'; @@ -631,16 +647,20 @@ this.Presentation = { // jshint ignore:l announce: function Presentation_announce(aAnnouncement) { // XXX: Typically each presenter uses the UtteranceGenerator, // but there really isn't a point here. return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)) // jshint ignore:line for each (p in this.presenters)]; // jshint ignore:line }, + noMove: function Presentation_noMove(aMoveMethod) { + return [p.noMove(aMoveMethod) for each (p in this.presenters)]; // jshint ignore:line + }, + liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide, aModifiedText) { let context; if (!aModifiedText) { context = new PivotContext(aAccessible, null, -1, -1, true, aIsHide ? true : false); } return [p.liveRegion(context, aIsPolite, aIsHide, aModifiedText) // jshint ignore:line
--- a/accessible/jsat/TraversalRules.jsm +++ b/accessible/jsat/TraversalRules.jsm @@ -29,16 +29,20 @@ XPCOMUtils.defineLazyModuleGetter(this, let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images'); function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) { this._explicitMatchRoles = new Set(aRoles); this._matchRoles = aRoles; if (aRoles.indexOf(Roles.LABEL) < 0) { this._matchRoles.push(Roles.LABEL); } + if (aRoles.indexOf(Roles.INTERNAL_FRAME) < 0) { + // Used for traversing in to child OOP frames. + this._matchRoles.push(Roles.INTERNAL_FRAME); + } this._matchFunc = aMatchFunc || function() { return Filters.MATCH; }; this.preFilter = aPreFilter || gSimplePreFilter; } BaseTraversalRule.prototype = { getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) { aRules.value = this._matchRoles; return aRules.value.length; @@ -93,19 +97,17 @@ var gSimpleTraversalRoles = Roles.HEADER, Roles.HEADING, Roles.SLIDER, Roles.SPINBUTTON, Roles.OPTION, Roles.LISTITEM, Roles.GRID_CELL, Roles.COLUMNHEADER, - Roles.ROWHEADER, - // Used for traversing in to child OOP frames. - Roles.INTERNAL_FRAME]; + Roles.ROWHEADER]; var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) { // An object is simple, if it either has a single child lineage, // or has a flat subtree. function isSingleLineage(acc) { for (let child = acc; child; child = child.firstChild) { if (Utils.visibleChildCount(child) > 1) { return false;
--- a/accessible/jsat/Utils.jsm +++ b/accessible/jsat/Utils.jsm @@ -465,16 +465,24 @@ this.Utils = { // jshint ignore:line // emulator add-on. window.dispatchEvent(new window.CustomEvent(aType, { bubbles: true, cancelable: true, detail: details })); } + }, + + isActivatableOnFingerUp: function isActivatableOnFingerUp(aAccessible) { + if (aAccessible.role === Roles.KEY) { + return true; + } + let quick_activate = this.getAttributes(aAccessible)['moz-quick-activate']; + return quick_activate && JSON.parse(quick_activate); } }; /** * State object used internally to process accessible's states. * @param {Number} aBase Base state. * @param {Number} aExtended Extended state. */ @@ -944,17 +952,17 @@ this.PrefCache = function PrefCache(aNam this.name = aName; this.callback = aCallback; let branch = Services.prefs; this.value = this._getValue(branch); if (this.callback && aRunCallbackNow) { try { - this.callback(this.name, this.value); + this.callback(this.name, this.value, true); } catch (x) { Logger.logException(x); } } branch.addObserver(aName, this, true); }; @@ -977,19 +985,20 @@ PrefCache.prototype = { } catch (x) { // Pref does not exist. return null; } }, observe: function observe(aSubject) { this.value = this._getValue(aSubject.QueryInterface(Ci.nsIPrefBranch)); + Logger.info('pref changed', this.name, this.value); if (this.callback) { try { - this.callback(this.name, this.value); + this.callback(this.name, this.value, false); } catch (x) { Logger.logException(x); } } }, QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference])
--- a/accessible/jsat/content-script.js +++ b/accessible/jsat/content-script.js @@ -87,56 +87,29 @@ function scroll(aMessage) { if (!forwardToChild(aMessage, scroll, position)) { sendAsyncMessage('AccessFu:DoScroll', { bounds: Utils.getBounds(position, true), page: aMessage.json.page, horizontal: aMessage.json.horizontal }); } } -function adjustRange(aMessage) { - function sendUpDownKey(aAccessible) { - let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible; - let elem = acc.DOMNode; - if (elem) { - if (elem.tagName === 'INPUT' && elem.type === 'range') { - elem[aMessage.json.direction === 'forward' ? 'stepDown' : 'stepUp'](); - let changeEvent = content.document.createEvent('UIEvent'); - changeEvent.initEvent('change', true, true); - elem.dispatchEvent(changeEvent); - } else { - let evt = content.document.createEvent('KeyboardEvent'); - let keycode = aMessage.json.direction == 'forward' ? - content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP; - evt.initKeyEvent( - "keypress", false, true, null, false, false, false, false, keycode, 0); - elem.dispatchEvent(evt); - } - } - } - - let position = Utils.getVirtualCursor(content.document).position; - if (!forwardToChild(aMessage, adjustRange, position)) { - sendUpDownKey(position); - } -} addMessageListener( 'AccessFu:Start', function(m) { if (m.json.logLevel) { Logger.logLevel = Logger[m.json.logLevel]; } Logger.debug('AccessFu:Start'); if (m.json.buildApp) Utils.MozBuildApp = m.json.buildApp; addMessageListener('AccessFu:ContextMenu', activateContextMenu); addMessageListener('AccessFu:Scroll', scroll); - addMessageListener('AccessFu:AdjustRange', adjustRange); if (!contentControl) { contentControl = new ContentControl(this); } contentControl.start(); if (!eventManager) { eventManager = new EventManager(this, contentControl);
--- a/accessible/tests/mochitest/actions/test_treegrid.xul +++ b/accessible/tests/mochitest/actions/test_treegrid.xul @@ -150,18 +150,17 @@ { var treeNode = getNode("tabletree"); waitForEvent(EVENT_REORDER, treeNode, doTestActions); treeNode.view = new nsTreeTreeView(); } function test1() { - var boxObj = getNode("tabletree").treeBoxObject; - boxObj.view.setCellValue(0, boxObj.columns.firstColumn, "false"); + getNode("tabletree").view.setCellValue(0, boxObj.columns.firstColumn, "false"); } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTest); ]]> </script> <hbox flex="1" style="overflow: auto;"> @@ -191,9 +190,8 @@ </tree> <vbox id="debug"/> <button oncommand="test1();" label="uncheck"/> </vbox> </hbox> </window> -
--- a/accessible/tests/mochitest/hittest/test_zoom_tree.xul +++ b/accessible/tests/mochitest/hittest/test_zoom_tree.xul @@ -35,26 +35,24 @@ var treecol1 = tabDocument.getElementById("treecol1"); // tree columns hitTest(tree, treecols, treecol1); // tree rows and cells var treeBoxObject = tree.treeBoxObject; var treeBodyBoxObj = tree.treeBoxObject.treeBody.boxObject; - var xObj = {}, yObj = {}, widthObj = {}, heightObj = {}; - treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell", - xObj, yObj, widthObj, heightObj); + var rect = treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell"); var treeAcc = getAccessible(tree, [nsIAccessibleTable]); var cellAcc = treeAcc.getCellAt(1, 0); var rowAcc = cellAcc.parent; - var cssX = xObj.value + treeBodyBoxObj.x; - var cssY = yObj.value + treeBodyBoxObj.y; + var cssX = rect.x + treeBodyBoxObj.x; + var cssY = rect.y + treeBodyBoxObj.y; var [x, y] = CSSToDevicePixels(tabWindow, cssX, cssY); testChildAtPoint(treeAcc, x, y, rowAcc, cellAcc); testChildAtPoint(rowAcc, x, y, cellAcc, cellAcc); // do zoom zoomDocument(tabDocument, 1.5); @@ -95,9 +93,8 @@ <div id="content" style="display: none"> </div> <pre id="test"> </pre> </body> </hbox> </window> -
--- a/accessible/tests/mochitest/jsat/a11y.ini +++ b/accessible/tests/mochitest/jsat/a11y.ini @@ -13,11 +13,12 @@ support-files = skip-if = buildapp == 'mulet' [test_content_text.html] skip-if = buildapp == 'mulet' [test_explicit_names.html] [test_gesture_tracker.html] [test_landmarks.html] [test_live_regions.html] [test_output.html] +[test_quicknav_modes.html] [test_tables.html] [test_pointer_relay.html] [test_traversal.html]
--- a/accessible/tests/mochitest/jsat/doc_content_integration.html +++ b/accessible/tests/mochitest/jsat/doc_content_integration.html @@ -70,19 +70,19 @@ </style> </head> <body> <div>Phone status bar</div> <div id="windows"> <button id="back">Back</button> - <div id="appframe"></div> <div role="dialog" id="alert" hidden> <h1>This is an alert!</h1> <p>Do you agree?</p> - <button onclick="hideAlert()">Yes</button> + <button onclick="setTimeout(hideAlert, 500)">Yes</button> <button onclick="hideAlert()">No</button> </div> + <div id="appframe"></div> </div> <button id="home">Home</button> </body> </html>
--- a/accessible/tests/mochitest/jsat/jsatcommon.js +++ b/accessible/tests/mochitest/jsat/jsatcommon.js @@ -130,17 +130,17 @@ var AccessFuTest = { } catch (ex) { // StopIteration exception. this.finish(); return; } testFunc(); }, - runTests: function AccessFuTest_runTests() { + runTests: function AccessFuTest_runTests(aAdditionalPrefs) { if (gTestFuncs.length === 0) { ok(false, "No tests specified!"); SimpleTest.finish(); return; } // Create an Iterator for gTestFuncs array. gIterator = Iterator(gTestFuncs); // jshint ignore:line @@ -151,20 +151,21 @@ var AccessFuTest = { AccessFu.attach(getMainChromeWindow(window)); AccessFu.readyCallback = function readyCallback() { // Enable logging to the console service. Logger.test = true; Logger.logLevel = Logger.DEBUG; }; - SpecialPowers.pushPrefEnv({ - 'set': [['accessibility.accessfu.notify_output', 1], - ['dom.mozSettings.enabled', true]] - }, function () { + var prefs = [['accessibility.accessfu.notify_output', 1], + ['dom.mozSettings.enabled', true]]; + prefs.push.apply(prefs, aAdditionalPrefs); + + SpecialPowers.pushPrefEnv({ 'set': prefs }, function () { if (AccessFuTest._waitForExplicitFinish) { // Run all test functions asynchronously. AccessFuTest.nextTest(); } else { // Run all test functions synchronously. [testFunc() for (testFunc of gTestFuncs)]; // jshint ignore:line AccessFuTest.finish(); } @@ -359,29 +360,39 @@ var ContentMessages = { clearCursor: { name: 'AccessFu:ClearCursor', json: { origin: 'top' } }, - adjustRangeUp: { - name: 'AccessFu:AdjustRange', - json: { - origin: 'top', - direction: 'backward' + moveOrAdjustUp: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'movePrevious', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } } }, - adjustRangeDown: { - name: 'AccessFu:AdjustRange', - json: { - origin: 'top', - direction: 'forward' + moveOrAdjustDown: function moveOrAdjustUp(aRule) { + return { + name: 'AccessFu:MoveCursor', + json: { + origin: 'top', + action: 'moveNext', + inputType: 'gesture', + rule: (aRule || 'Simple'), + adjustRange: true + } } }, focusSelector: function focusSelector(aSelector, aBlur) { return { name: 'AccessFuTest:Focus', json: { selector: aSelector, @@ -649,16 +660,22 @@ function ExpectedAnnouncement(aAnnouncem eventType: AndroidEvent.ANNOUNCEMENT, text: [ aAnnouncement], addedCount: aAnnouncement.length }], aOptions); } ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype); +function ExpectedNoMove(aOptions) { + ExpectedPresent.call(this, {eventType: 'no-move' }, null, aOptions); +} + +ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype); + var AndroidEvent = { VIEW_CLICKED: 0x01, VIEW_LONG_CLICKED: 0x02, VIEW_SELECTED: 0x04, VIEW_FOCUSED: 0x08, VIEW_TEXT_CHANGED: 0x10, WINDOW_STATE_CHANGED: 0x20, VIEW_HOVER_ENTER: 0x80,
--- a/accessible/tests/mochitest/jsat/test_content_integration.html +++ b/accessible/tests/mochitest/jsat/test_content_integration.html @@ -29,16 +29,17 @@ iframe.addEventListener('mozbrowserloadend', function () { var contentTest = new AccessFuContentTest( [ // Simple traversal forward [ContentMessages.simpleMoveNext, new ExpectedCursorChange( ['Phone status bar', 'Traversal Rule test document'], { focused: 'body' })], + [ContentMessages.simpleMovePrevious, new ExpectedNoMove()], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange( ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'], { focused: 'iframe' })], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'}, {'string': 'checkbutton'}, {'string': 'listStart'}, @@ -47,24 +48,24 @@ // check checkbox [ContentMessages.activateCurrent(), new ExpectedClickAction({ no_android: true }), new ExpectedCheckAction(true, { android_todo: true })], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['much range', {'string': 'label'}])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])], - [ContentMessages.adjustRangeUp, new ExpectedValueChange('6')], + [ContentMessages.moveOrAdjustUp(), new ExpectedValueChange('6')], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], // Simple traversal backward [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', '6', {'string': 'slider'}, 'such app'])], - [ContentMessages.adjustRangeDown, new ExpectedValueChange('5')], + [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')], [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['much range', {'string': 'label'}])], [ContentMessages.simpleMovePrevious, new ExpectedCursorChange(['many option', {'string': 'stateChecked'}, {'string': 'checkbutton'}, {'string': 'listStart'}, {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], // uncheck checkbox [ContentMessages.activateCurrent(), @@ -86,16 +87,42 @@ ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])], // Move from an inner frame to the last element in the parent doc [ContentMessages.simpleMoveLast, new ExpectedCursorChange( ['Home', {'string': 'pushbutton'}], { b2g_todo: true })], [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['Back', {"string": "pushbutton"}])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}, 'such app'])], + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])], + // Calling AdjustOrMove should adjust the range. + [ContentMessages.moveOrAdjustDown('FormElement'), + new ExpectedValueChange('4')], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedValueChange('5')], + [ContentMessages.simpleMovePrevious, + new ExpectedCursorChange(['much range', {'string': 'label'}])], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'}, + {'string': 'checkbutton'}, {'string': 'listStart'}, + {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])], + [ContentMessages.moveOrAdjustUp('FormElement'), + new ExpectedCursorChange(['Back', {"string": "pushbutton"}])], + + [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], + // Moving to the absolute first item from an embedded document // fails. Bug 972035. [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])], @@ -174,60 +201,64 @@ // Must not speak Back button as it is aria-hidden new ExpectedCursorChange( ["wow", {"string": "headingLevel","args": [1]}, "such app"])], [doc.defaultView.ariaShowBack], [ContentMessages.focusSelector('button#back', true), null], [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], // Open dialog in outer doc, while cursor is also in outer doc - [ContentMessages.simpleMoveNext, - new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])], + [ContentMessages.simpleMoveLast, + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!', {'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])], [doc.defaultView.hideAlert, - new ExpectedCursorChange(["wow", - {"string": "headingLevel", "args": [1]}, "such app"])], + new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])], [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], // Open dialog in outer doc, while cursor is in inner frame [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange(["Back", {"string": "pushbutton"}])], [ContentMessages.simpleMoveNext, new ExpectedCursorChange( ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])], [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!', {'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])], - // XXX: Place cursor back where it was. - [doc.defaultView.hideAlert, + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Do you agree?'])], + [ContentMessages.simpleMoveNext, + new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])], + [ContentMessages.activateCurrent(), + new ExpectedClickAction(), new ExpectedCursorChange( ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])], [ContentMessages.clearCursor, 'AccessFu:CursorCleared'], // Open dialog, then focus on something when closing [ContentMessages.simpleMoveNext, new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])], [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!', {'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])], [function hideAlertAndFocusHomeButton() { doc.defaultView.hideAlert(); doc.querySelector('button#home').focus(); }, new ExpectedCursorChange(['Home', {'string': 'pushbutton'}, - 'Traversal Rule test document'])] + 'Traversal Rule test document'])], + [ContentMessages.simpleMoveNext, new ExpectedNoMove()] ]); addA11yLoadEvent(function() { contentTest.start(function () { closeBrowserWindow(); SimpleTest.finish(); }); }, doc.defaultView)
new file mode 100644 --- /dev/null +++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html @@ -0,0 +1,103 @@ +<html> + +<head> + <title>AccessFu test for enabling</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="./jsatcommon.js"></script> + <script type="application/javascript"> + + function prefStart() { + // Start AccessFu via pref. + SpecialPowers.setIntPref("accessibility.accessfu.activate", 1); + AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest); + } + + function nextMode(aCurrentMode, aNextMode) { + return function() { + is(AccessFu.Input.quickNavMode.current, aCurrentMode, + 'initial current mode is correct'); + AccessFu.Input.quickNavMode.next(); + _expectMode(aNextMode, AccessFuTest.nextTest); + } + } + + function prevMode(aCurrentMode, aNextMode) { + return function() { + is(AccessFu.Input.quickNavMode.current, aCurrentMode, + 'initial current mode is correct'); + AccessFu.Input.quickNavMode.previous(); + _expectMode(aNextMode, AccessFuTest.nextTest); + } + } + + function setMode(aModeIndex, aExpectedMode) { + return function() { + SpecialPowers.setIntPref( + 'accessibility.accessfu.quicknav_index', aModeIndex); + _expectMode(aExpectedMode, AccessFuTest.nextTest); + } + } + + function reconfigureModes() { + SpecialPowers.setCharPref('accessibility.accessfu.quicknav_modes', + 'Landmark,Button,Entry,Graphic'); + // When the modes are reconfigured, the current mode should + // be set to the first in the new list. + _expectMode('Landmark', AccessFuTest.nextTest); + } + + function _expectMode(aExpectedMode, aCallback) { + if (AccessFu.Input.quickNavMode.current === aExpectedMode) { + ok(true, 'correct mode'); + aCallback(); + } else { + AccessFuTest.once_log('Quicknav mode: ' + aExpectedMode, function() { + ok(true, 'correct mode'); + aCallback(); + }); + } + } + + // Listen for initial 'EventManager.start' and disable AccessFu. + function prefStop() { + ok(AccessFu._enabled, "AccessFu was started via preference."); + AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish); + SpecialPowers.setIntPref("accessibility.accessfu.activate", 0); + } + + function doTest() { + AccessFuTest.addFunc(prefStart); + AccessFuTest.addFunc(nextMode('Link', 'Heading')); + AccessFuTest.addFunc(nextMode('Heading', 'FormElement')); + AccessFuTest.addFunc(nextMode('FormElement', 'Link')); + AccessFuTest.addFunc(nextMode('Link', 'Heading')); + AccessFuTest.addFunc(prevMode('Heading', 'Link')); + AccessFuTest.addFunc(prevMode('Link', 'FormElement')); + AccessFuTest.addFunc(setMode(1, 'Heading')); + AccessFuTest.addFunc(reconfigureModes); + AccessFuTest.addFunc(prefStop); + AccessFuTest.waitForExplicitFinish(); + AccessFuTest.runTests([ // Will call SimpleTest.finish(); + ['accessibility.accessfu.quicknav_modes', 'Link,Heading,FormElement']]); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> + +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307" + title="[AccessFu] Add mochitest for enabling"> + Mozilla Bug 811307 + </a> +</body> +</html> \ No newline at end of file
--- a/accessible/tests/mochitest/name/test_tree.xul +++ b/accessible/tests/mochitest/name/test_tree.xul @@ -27,17 +27,17 @@ <script type="application/javascript"> <![CDATA[ function treeTester(aID) { this.DOMNode = getNode(aID); this.invoke = function treeTester_invoke() { - this.DOMNode.treeBoxObject.view = new nsTreeTreeView(); + this.DOMNode.view = new nsTreeTreeView(); } this.check = function treeTester_check(aEvent) { var tree = { role: ROLE_OUTLINE, children: [ { @@ -85,17 +85,17 @@ } function tableTester(aID, aIsTable, aCol1ID, aCol2ID) { this.DOMNode = getNode(aID); this.invoke = function tableTester_invoke() { - this.DOMNode.treeBoxObject.view = new nsTableTreeView(2); + this.DOMNode.view = new nsTableTreeView(2); } this.check = function tableTester_check(aEvent) { var tree = { role: aIsTable ? ROLE_TABLE : ROLE_TREE_TABLE, children: [ { @@ -204,9 +204,8 @@ <treecol id="tt_col2" flex="1" label="column 2"/> </treecols> <treechildren/> </tree> </vbox> <!-- close tests area --> </hbox> <!-- close main area --> </window> -
--- a/accessible/tests/mochitest/selectable/test_tree.xul +++ b/accessible/tests/mochitest/selectable/test_tree.xul @@ -37,17 +37,17 @@ * accessible. */ function statesChecker(aTreeID, aView) { this.DOMNode = getNode(aTreeID); this.invoke = function invoke() { - this.DOMNode.treeBoxObject.view = aView; + this.DOMNode.view = aView; } this.check = function check() { var tree = getAccessible(this.DOMNode); var isTreeMultiSelectable = false; var seltype = this.DOMNode.getAttribute("seltype"); if (seltype != "single" && seltype != "cell" && seltype != "text") @@ -181,9 +181,8 @@ <treechildren/> </tree> <vbox id="debug"/> </vbox> </hbox> </window> -
--- a/accessible/tests/mochitest/states/test_tree.xul +++ b/accessible/tests/mochitest/states/test_tree.xul @@ -33,17 +33,17 @@ * accessible. */ function statesChecker(aTreeID, aView) { this.DOMNode = getNode(aTreeID); this.invoke = function statesChecker_invoke() { - this.DOMNode.treeBoxObject.view = aView; + this.DOMNode.view = aView; } this.check = function statesChecker_check() { var tree = getAccessible(this.DOMNode); // tree states testStates(tree, STATE_READONLY); @@ -145,9 +145,8 @@ <treechildren/> </tree> <vbox id="debug"/> </vbox> </hbox> </window> -
--- a/accessible/tests/mochitest/tree/test_tree.xul +++ b/accessible/tests/mochitest/tree/test_tree.xul @@ -67,17 +67,17 @@ var accTreeForTree = { role: aRole, children: [ accTreeForColumns ] }; var treeBoxObject = aTree.treeBoxObject; - var view = treeBoxObject.view; + var view = aTree.view; var columnCount = treeBoxObject.columns.count; for (var idx = 0; idx < columnCount; idx++) accTreeForColumns.children.push({ COLUMNHEADER: [ ] }); if (!aTree.hasAttribute("hidecolumnpicker")) accTreeForColumns.children.push({ PUSHBUTTON: [ { MENUPOPUP: [] } ] }); for (var idx = 0; idx < view.rowCount; idx++) @@ -90,17 +90,17 @@ * Event queue invoker object to test accessible tree for XUL tree element. */ function treeChecker(aID, aView, aRole) { this.DOMNode = getNode(aID); this.invoke = function invoke() { - this.DOMNode.treeBoxObject.view = aView; + this.DOMNode.view = aView; } this.check = function check(aEvent) { testAccessibleTreeFor(this.DOMNode, aRole); } this.getID = function getID() { return "Tree testing of " + aID; @@ -175,9 +175,8 @@ <treechildren/> </tree> <vbox id="debug"/> </vbox> </hbox> </window> -
--- a/accessible/tests/mochitest/treeview.js +++ b/accessible/tests/mochitest/treeview.js @@ -12,17 +12,17 @@ function loadXULTreeAndDoTest(aDoTestFun this.treeNode = getNode(aTreeID); this.eventSeq = [ new invokerChecker(EVENT_REORDER, this.treeNode) ]; this.invoke = function loadXULTree_invoke() { - this.treeNode.treeBoxObject.view = aTreeView; + this.treeNode.view = aTreeView; } this.getID = function loadXULTree_getID() { return "Load XUL tree " + prettyName(aTreeID); } }
--- a/accessible/xul/XULTreeAccessible.cpp +++ b/accessible/xul/XULTreeAccessible.cpp @@ -194,17 +194,17 @@ XULTreeAccessible::ChildAtPoint(int32_t nsIntRect rootRect = rootFrame->GetScreenRect(); int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x; int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y; int32_t row = -1; nsCOMPtr<nsITreeColumn> column; - nsAutoCString childEltUnused; + nsAutoString childEltUnused; mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), childEltUnused); // If we failed to find tree cell for the given point then it might be // tree columns. if (row == -1 || !column) return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild); @@ -741,17 +741,17 @@ XULTreeItemAccessibleBase::Bounds() cons nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); if (!boxObj) return nsIntRect(); nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree); int32_t x = 0, y = 0, width = 0, height = 0; - nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(), + nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(), &x, &y, &width, &height); if (NS_FAILED(rv)) return nsIntRect(); boxObj->GetWidth(&width); int32_t tcX = 0, tcY = 0; boxObj->GetScreenX(&tcX); @@ -991,25 +991,25 @@ XULTreeItemAccessibleBase::DispatchClick nsCOMPtr<nsITreeColumns> columns; mTree->GetColumns(getter_AddRefs(columns)); if (!columns) return; // Get column and pseudo element. nsCOMPtr<nsITreeColumn> column; - nsAutoCString pseudoElm; + nsAutoString pseudoElm; if (aActionIndex == eAction_Click) { // Key column is visible and clickable. columns->GetKeyColumn(getter_AddRefs(column)); } else { // Primary column contains a twisty we should click on. columns->GetPrimaryColumn(getter_AddRefs(column)); - pseudoElm = NS_LITERAL_CSTRING("twisty"); + pseudoElm = NS_LITERAL_STRING("twisty"); } if (column) nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm); } Accessible* XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset, @@ -1191,9 +1191,8 @@ XULTreeColumAccessible::GetSiblingAtOffs if (treeAcc) return treeAcc->GetTreeItemAccessible(aOffset - 1); } } } return nullptr; } -
--- a/accessible/xul/XULTreeGridAccessible.cpp +++ b/accessible/xul/XULTreeGridAccessible.cpp @@ -336,17 +336,17 @@ XULTreeGridRowAccessible::ChildAtPoint(i nsIntRect rootRect = rootFrame->GetScreenRect(); int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x; int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y; int32_t row = -1; nsCOMPtr<nsITreeColumn> column; - nsAutoCString childEltUnused; + nsAutoString childEltUnused; mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column), childEltUnused); // Return if we failed to find tree cell in the row for the given point. if (row != mRow || !column) return nullptr; return GetCellAccessible(column); @@ -517,17 +517,17 @@ XULTreeGridCellAccessible::Bounds() cons // Get bounds for tree cell and add x and y of treechildren element to // x and y of the cell. nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree); if (!boxObj) return nsIntRect(); int32_t x = 0, y = 0, width = 0, height = 0; nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn, - NS_LITERAL_CSTRING("cell"), + NS_LITERAL_STRING("cell"), &x, &y, &width, &height); if (NS_FAILED(rv)) return nsIntRect(); int32_t tcX = 0, tcY = 0; boxObj->GetScreenX(&tcX); boxObj->GetScreenY(&tcY); x += tcX;
--- a/aclocal.m4 +++ b/aclocal.m4 @@ -3,17 +3,16 @@ dnl Local autoconf macros used with mozi dnl The contents of this file are under the Public Domain. dnl builtin(include, build/autoconf/hotfixes.m4)dnl builtin(include, build/autoconf/acwinpaths.m4)dnl builtin(include, build/autoconf/hooks.m4)dnl builtin(include, build/autoconf/config.status.m4)dnl builtin(include, build/autoconf/toolchain.m4)dnl -builtin(include, build/autoconf/ccache.m4)dnl builtin(include, build/autoconf/wrapper.m4)dnl builtin(include, build/autoconf/nspr.m4)dnl builtin(include, build/autoconf/nspr-build.m4)dnl builtin(include, build/autoconf/nss.m4)dnl builtin(include, build/autoconf/pkg.m4)dnl builtin(include, build/autoconf/codeset.m4)dnl builtin(include, build/autoconf/altoptions.m4)dnl builtin(include, build/autoconf/mozprog.m4)dnl
--- a/addon-sdk/source/test/jetpack-package.ini +++ b/addon-sdk/source/test/jetpack-package.ini @@ -1,16 +1,16 @@ [DEFAULT] support-files = buffers/** commonjs-test-adapter/** event/** fixtures/** loader/** - libs/** + lib/** modules/** private-browsing/** sidebar/** tabs/** traits/** windows/** zip/** fixtures.js
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -76,16 +76,17 @@ pref("network.http.max-connections", 20) pref("network.http.max-persistent-connections-per-server", 6); pref("network.http.max-persistent-connections-per-proxy", 20); // Keep the old default of accepting all cookies, // no matter if you already visited the website or not pref("network.cookie.cookieBehavior", 0); // spdy +pref("network.http.spdy.enabled.http2draft", false); pref("network.http.spdy.push-allowance", 32768); // See bug 545869 for details on why these are set the way they are pref("network.buffer.cache.count", 24); pref("network.buffer.cache.size", 16384); // predictive actions pref("network.predictor.enable", false); // disabled on b2g @@ -782,19 +783,24 @@ pref("dom.ipc.reuse_parent_app", false); // When a process receives a system message, we hold a CPU wake lock on its // behalf for this many seconds, or until it handles the system message, // whichever comes first. pref("dom.ipc.systemMessageCPULockTimeoutSec", 30); // Ignore the "dialog=1" feature in window.open. pref("dom.disable_window_open_dialog_feature", true); +// Enable before keyboard events and after keyboard events. +pref("dom.beforeAfterKeyboardEvent.enabled", true); + // Screen reader support pref("accessibility.accessfu.activate", 2); pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem"); +// Active quicknav mode, index value of list from quicknav_modes +pref("accessibility.accessfu.quicknav_index", 0); // Setting for an utterance order (0 - description first, 1 - description last). pref("accessibility.accessfu.utterance", 1); // Whether to skip images with empty alt text pref("accessibility.accessfu.skip_empty_images", true); // Enable hit-target fluffing pref("ui.touch.radius.enabled", true); pref("ui.touch.radius.leftmm", 3); @@ -867,16 +873,18 @@ pref("webgl.can-lose-context-in-foregrou pref("memory_info_dumper.watch_fifo.enabled", true); pref("memory_info_dumper.watch_fifo.directory", "/data/local"); // See ua-update.json.in for the packaged UA override list pref("general.useragent.updates.enabled", true); pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%"); pref("general.useragent.updates.interval", 604800); // 1 week pref("general.useragent.updates.retry", 86400); // 1 day +// Device ID can be composed of letter, numbers, hyphen ("-") and dot (".") +pref("general.useragent.device_id", ""); // Make <audio> and <video> talk to the AudioChannelService. pref("media.useAudioChannelService", true); pref("b2g.version", @MOZ_B2G_VERSION@); pref("b2g.osName", @MOZ_B2G_OS_NAME@); // Disable console buffering to save memory.
--- a/b2g/chrome/content/content.css +++ b/b2g/chrome/content/content.css @@ -173,18 +173,16 @@ input[type="submit"], input[type="reset"], button { border-width: 1px; padding: 0 7px 0 7px; } input[type="radio"], input[type="checkbox"] { - max-width: 14px; - max-height: 14px; border: 1px solid #a7a7a7 !important; padding: 2px 1px 2px 1px; } select > button { border-width: 0px !important; margin: 0px !important; padding: 0px !important;
--- a/b2g/chrome/content/devtools/adb.js +++ b/b2g/chrome/content/devtools/adb.js @@ -3,50 +3,46 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; // This file is only loaded on Gonk to manage ADB state +const { utils: Cu } = Components; + +const DEBUG = false; +var debug = function(str) { + dump("AdbController: " + str + "\n"); +} + let AdbController = { - DEBUG: false, locked: undefined, remoteDebuggerEnabled: undefined, lockEnabled: undefined, disableAdbTimer: null, disableAdbTimeoutHours: 12, umsActive: false, - debug: function(str) { - dump("AdbController: " + str + "\n"); - }, - setLockscreenEnabled: function(value) { this.lockEnabled = value; - if (this.DEBUG) { - this.debug("setLockscreenEnabled = " + this.lockEnabled); - } + DEBUG && debug("setLockscreenEnabled = " + this.lockEnabled); this.updateState(); }, setLockscreenState: function(value) { this.locked = value; - if (this.DEBUG) { - this.debug("setLockscreenState = " + this.locked); - } + DEBUG && debug("setLockscreenState = " + this.locked); this.updateState(); }, setRemoteDebuggerState: function(value) { this.remoteDebuggerEnabled = value; - if (this.DEBUG) { - this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled); - } + DEBUG && debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled); this.updateState(); }, startDisableAdbTimer: function() { if (this.disableAdbTimer) { this.disableAdbTimer.cancel(); } else { this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); @@ -54,48 +50,42 @@ let AdbController = { this.disableAdbTimeoutHours = Services.prefs.getIntPref("b2g.adb.timeout-hours"); } catch (e) { // This happens if the pref doesn't exist, in which case // disableAdbTimeoutHours will still be set to the default. } } if (this.disableAdbTimeoutHours <= 0) { - if (this.DEBUG) { - this.debug("Timer to disable ADB not started due to zero timeout"); - } + DEBUG && debug("Timer to disable ADB not started due to zero timeout"); return; } - if (this.DEBUG) { - this.debug("Starting timer to disable ADB in " + - this.disableAdbTimeoutHours + " hours"); - } + DEBUG && debug("Starting timer to disable ADB in " + + this.disableAdbTimeoutHours + " hours"); let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000; this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds, Ci.nsITimer.TYPE_ONE_SHOT); }, stopDisableAdbTimer: function() { - if (this.DEBUG) { - this.debug("Stopping timer to disable ADB"); - } + DEBUG && debug("Stopping timer to disable ADB"); if (this.disableAdbTimer) { this.disableAdbTimer.cancel(); this.disableAdbTimer = null; } }, notify: function(aTimer) { if (aTimer == this.disableAdbTimer) { this.disableAdbTimer = null; // The following dump will be the last thing that shows up in logcat, // and will at least give the user a clue about why logcat was // disconnected, if the user happens to be using logcat. - dump("AdbController: ADB timer expired - disabling ADB\n"); + debug("ADB timer expired - disabling ADB\n"); navigator.mozSettings.createLock().set( {'debugger.remote-mode': 'disabled'}); } }, updateState: function() { this.umsActive = false; this.storages = navigator.getDeviceStorages('sdcard'); @@ -105,47 +95,40 @@ let AdbController = { updateStorageState: function(storageIndex) { if (storageIndex >= this.storages.length) { // We've iterated through all of the storage objects, now we can // really do updateStateInternal. this.updateStateInternal(); return; } let storage = this.storages[storageIndex]; - if (this.DEBUG) { - this.debug("Checking availability of storage: '" + - storage.storageName); - } + DEBUG && debug("Checking availability of storage: '" + storage.storageName); let req = storage.available(); req.onsuccess = function(e) { - if (this.DEBUG) { - this.debug("Storage: '" + storage.storageName + "' is '" + - e.target.result); - } + DEBUG && debug("Storage: '" + storage.storageName + "' is '" + e.target.result); if (e.target.result == 'shared') { // We've found a storage area that's being shared with the PC. // We can stop looking now. this.umsActive = true; this.updateStateInternal(); return; } this.updateStorageState(storageIndex + 1); }.bind(this); req.onerror = function(e) { - dump("AdbController: error querying storage availability for '" + - this.storages[storageIndex].storageName + "' (ignoring)\n"); + + Cu.reportError("AdbController: error querying storage availability for '" + + this.storages[storageIndex].storageName + "' (ignoring)\n"); this.updateStorageState(storageIndex + 1); }.bind(this); }, updateStateInternal: function() { - if (this.DEBUG) { - this.debug("updateStateInternal: called"); - } + DEBUG && debug("updateStateInternal: called"); if (this.remoteDebuggerEnabled === undefined || this.lockEnabled === undefined || this.locked === undefined) { // Part of initializing the settings database will cause the observers // to trigger. We want to wait until both have been initialized before // we start changing ther adb state. Without this then we can wind up // toggling adb off and back on again (or on and back off again). @@ -157,28 +140,24 @@ let AdbController = { // receive the unlock event we haven't yet received the rde event, so // we turn adb off momentarily, which disconnects a logcat that might // be running. Changing the defaults (in AdbController) just moves the // problem to a different phone, which has adb disabled by default and // we wind up turning on adb for a short period when we shouldn't. // // By waiting until both values are properly initialized, we avoid // turning adb on or off accidentally. - if (this.DEBUG) { - this.debug("updateState: Waiting for all vars to be initialized"); - } + DEBUG && debug("updateState: Waiting for all vars to be initialized"); return; } // Check if we have a remote debugging session going on. If so, we won't // disable adb even if the screen is locked. let isDebugging = USBRemoteDebugger.isDebugging; - if (this.DEBUG) { - this.debug("isDebugging=" + isDebugging); - } + DEBUG && debug("isDebugging=" + isDebugging); // If USB Mass Storage, USB tethering, or a debug session is active, // then we don't want to disable adb in an automatic fashion (i.e. // when the screen locks or due to timeout). let sysUsbConfig = libcutils.property_get("sys.usb.config"); let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0); let usbFuncActive = rndisActive || this.umsActive || isDebugging; @@ -194,23 +173,21 @@ let AdbController = { // we want adb enabled all of the time. enableAdb = true; useDisableAdbTimer = false; } } catch (e) { // This means that the pref doesn't exist. Which is fine. We just leave // enableAdb alone. } - if (this.DEBUG) { - this.debug("updateState: enableAdb = " + enableAdb + - " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled + - " lockEnabled = " + this.lockEnabled + - " locked = " + this.locked + - " usbFuncActive = " + usbFuncActive); - } + DEBUG && debug("updateState: enableAdb = " + enableAdb + + " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled + + " lockEnabled = " + this.lockEnabled + + " locked = " + this.locked + + " usbFuncActive = " + usbFuncActive); // Configure adb. let currentConfig = libcutils.property_get("persist.sys.usb.config"); let configFuncs = currentConfig.split(","); let adbIndex = configFuncs.indexOf("adb"); if (enableAdb) { // Add adb to the list of functions, if not already present @@ -220,32 +197,31 @@ let AdbController = { } else { // Remove adb from the list of functions, if present if (adbIndex >= 0) { configFuncs.splice(adbIndex, 1); } } let newConfig = configFuncs.join(","); if (newConfig != currentConfig) { - if (this.DEBUG) { - this.debug("updateState: currentConfig = " + currentConfig); - this.debug("updateState: newConfig = " + newConfig); - } + DEBUG && debug("updateState: currentConfig = " + currentConfig); + DEBUG && debug("updateState: newConfig = " + newConfig); try { libcutils.property_set("persist.sys.usb.config", newConfig); } catch(e) { - dump("Error configuring adb: " + e); + Cu.reportError("Error configuring adb: " + e); } } if (useDisableAdbTimer) { if (enableAdb && !usbFuncActive) { this.startDisableAdbTimer(); } else { this.stopDisableAdbTimer(); } } } + }; SettingsListener.observe("lockscreen.locked", false, AdbController.setLockscreenState.bind(AdbController)); SettingsListener.observe("lockscreen.enabled", false, AdbController.setLockscreenEnabled.bind(AdbController));
--- a/b2g/chrome/content/devtools/debugger.js +++ b/b2g/chrome/content/devtools/debugger.js @@ -16,16 +16,22 @@ XPCOMUtils.defineLazyGetter(this, "devto Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); return devtools; }); XPCOMUtils.defineLazyGetter(this, "discovery", function() { return devtools.require("devtools/toolkit/discovery/discovery"); }); +XPCOMUtils.defineLazyGetter(this, "B2GTabList", function() { + const { B2GTabList } = + devtools.require("resource://gre/modules/DebuggerActors.js"); + return B2GTabList; +}); + let RemoteDebugger = { _promptDone: false, _promptAnswer: false, _listening: false, prompt: function() { this._listen(); @@ -86,25 +92,17 @@ let RemoteDebugger = { * * * @param connection DebuggerServerConnection * The conection to the client. */ DebuggerServer.createRootActor = function createRootActor(connection) { let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); let parameters = { - // We do not expose browser tab actors yet, - // but we still have to define tabList.getList(), - // otherwise, client won't be able to fetch global actors - // from listTabs request! - tabList: { - getList: function() { - return promise.resolve([]); - } - }, + tabList: new B2GTabList(connection), // Use an explicit global actor list to prevent exposing // unexpected actors globalActorFactories: restrictPrivileges ? { webappsActor: DebuggerServer.globalActorFactories.webappsActor, deviceActor: DebuggerServer.globalActorFactories.deviceActor, } : DebuggerServer.globalActorFactories }; let { RootActor } = devtools.require("devtools/server/actors/root");
--- a/b2g/chrome/content/devtools/hud.js +++ b/b2g/chrome/content/devtools/hud.js @@ -24,17 +24,17 @@ XPCOMUtils.defineLazyGetter(this, 'WebCo XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() { return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront; }); XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() { return devtools.require('devtools/server/actors/memory').MemoryFront; }); -Cu.import('resource://gre/modules/AppFrames.jsm'); +Cu.import('resource://gre/modules/Frames.jsm'); /** * The Developer HUD is an on-device developer tool that displays widgets, * showing visual debug information about apps. Each widget corresponds to a * metric as tracked by a metric watcher (e.g. consoleWatcher). */ let developerHUD = { @@ -75,19 +75,20 @@ let developerHUD = { this._client = new DebuggerClient(transport); for (let w of this._watchers) { if (w.init) { w.init(this._client); } } - AppFrames.addObserver(this); + Frames.addObserver(this); - for (let frame of AppFrames.list()) { + let appFrames = Frames.list().filter(frame => frame.getAttribute('mozapp')); + for (let frame of appFrames) { this.trackFrame(frame); } SettingsListener.observe('hud.logging', this._logging, enabled => { this._logging = enabled; }); }, @@ -95,17 +96,17 @@ let developerHUD = { if (!this._client) { return; } for (let frame of this._targets.keys()) { this.untrackFrame(frame); } - AppFrames.removeObserver(this); + Frames.removeObserver(this); this._client.close(); delete this._client; }, /** * This method will ask all registered watchers to track and update metrics * on an app frame. @@ -132,21 +133,29 @@ let developerHUD = { w.untrackTarget(target); } target.destroy(); this._targets.delete(frame); } }, - onAppFrameCreated: function (frame, isFirstAppFrame) { + onFrameCreated: function (frame, isFirstAppFrame) { + let mozapp = frame.getAttribute('mozapp'); + if (!mozapp) { + return; + } this.trackFrame(frame); }, - onAppFrameDestroyed: function (frame, isLastAppFrame) { + onFrameDestroyed: function (frame, isLastAppFrame) { + let mozapp = frame.getAttribute('mozapp'); + if (!mozapp) { + return; + } this.untrackFrame(frame); }, log: function dwp_log(message) { if (this._logging) { dump(DEVELOPER_HUD_LOG_PREFIX + ': ' + message + '\n'); } }
--- a/b2g/chrome/content/settings.js +++ b/b2g/chrome/content/settings.js @@ -452,16 +452,26 @@ SettingsListener.observe("theme.selected Services.prefs.setCharPref('dom.mozApps.selected_theme', newTheme); Services.prefs.savePrefFile(null); Services.obs.notifyObservers(null, 'app-theme-changed', newTheme); } }); // =================== Various simple mapping ====================== let settingsToObserve = { + 'accessibility.screenreader_quicknav_modes': { + prefName: 'accessibility.accessfu.quicknav_modes', + resetToPref: true, + defaultValue: '' + }, + 'accessibility.screenreader_quicknav_index': { + prefName: 'accessibility.accessfu.quicknav_index', + resetToPref: true, + defaultValue: 0 + }, 'app.update.channel': { resetToPref: true }, 'app.update.interval': 86400, 'app.update.url': { resetToPref: true }, 'apz.force-enable': {
--- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -319,25 +319,28 @@ var shell = { // Capture all key events so we can filter out hardware buttons // And send them to Gaia via mozChromeEvents. // Ideally, hardware buttons wouldn't generate key events at all, or // if they did, they would use keycodes that conform to DOM 3 Events. // See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362 chromeEventHandler.addEventListener('keydown', this, true); chromeEventHandler.addEventListener('keypress', this, true); chromeEventHandler.addEventListener('keyup', this, true); + chromeEventHandler.addEventListener('mozbrowserbeforekeydown', this, true); + chromeEventHandler.addEventListener('mozbrowserbeforekeyup', this, true); window.addEventListener('MozApplicationManifest', this); window.addEventListener('mozfullscreenchange', this); window.addEventListener('MozAfterPaint', this); window.addEventListener('sizemodechange', this); window.addEventListener('unload', this); this.contentBrowser.addEventListener('mozbrowserloadstart', this, true); this.contentBrowser.addEventListener('mozbrowserselectionchange', this, true); this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true); + this.contentBrowser.addEventListener('mozbrowsertouchcarettap', this, true); CustomEventManager.init(); WebappsHelper.init(); UserAgentOverrides.init(); IndexedDBPromptHelper.init(); CaptivePortalLoginHelper.init(); this.contentBrowser.src = homeURL; @@ -350,22 +353,25 @@ var shell = { ppmm.addMessageListener("file-picker", this); }, stop: function shell_stop() { window.removeEventListener('unload', this); window.removeEventListener('keydown', this, true); window.removeEventListener('keypress', this, true); window.removeEventListener('keyup', this, true); + window.removeEventListener('mozbrowserbeforekeydown', this, true); + window.removeEventListener('mozbrowserbeforekeyup', this, true); window.removeEventListener('MozApplicationManifest', this); window.removeEventListener('mozfullscreenchange', this); window.removeEventListener('sizemodechange', this); this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); this.contentBrowser.removeEventListener('mozbrowserselectionchange', this, true); this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true); + this.contentBrowser.removeEventListener('mozbrowsertouchcarettap', this, true); ppmm.removeMessageListener("content-handler", this); UserAgentOverrides.uninit(); IndexedDBPromptHelper.uninit(); }, // If this key event actually represents a hardware button, filter it here // and send a mozChromeEvent with detail.type set to xxx-button-press or @@ -413,27 +419,24 @@ var shell = { isMediaKey = true; type = mediaKeys[evt.key]; } if (!type) { return; } - // If we didn't return, then the key event represents a hardware key - // and we need to prevent it from propagating to Gaia - evt.stopImmediatePropagation(); - evt.preventDefault(); // Prevent keypress events (when #501496 is fixed). - // If it is a key down or key up event, we send a chrome event to Gaia. // If it is a keypress event we just ignore it. switch (evt.type) { + case 'mozbrowserbeforekeydown': case 'keydown': type = type + '-press'; break; + case 'mozbrowserbeforekeyup': case 'keyup': type = type + '-release'; break; case 'keypress': return; } // Let applications receive the headset button key press/release event. @@ -466,16 +469,18 @@ var shell = { visibleNormalAudioActive: false, handleEvent: function shell_handleEvent(evt) { let content = this.contentBrowser.contentWindow; switch (evt.type) { case 'keydown': case 'keyup': case 'keypress': + case 'mozbrowserbeforekeydown': + case 'mozbrowserbeforekeyup': this.filterHardwareKeys(evt); break; case 'mozfullscreenchange': // When the screen goes fullscreen make sure to set the focus to the // main window so noboby can prevent the ESC key to get out fullscreen // mode if (document.mozFullScreen) Services.fm.focusedWindow = window; @@ -503,16 +508,22 @@ var shell = { this.notifyContentStart(); break; case 'mozbrowserscrollviewchange': this.sendChromeEvent({ type: 'scrollviewchange', detail: evt.detail, }); break; + case 'mozbrowsertouchcarettap': + this.sendChromeEvent({ + type: 'touchcarettap', + detail: evt.detail, + }); + break; case 'mozbrowserselectionchange': // The mozbrowserselectionchange event, may have crossed the chrome-content boundary. // This event always dispatch to shell.js. But the offset we got from this event is // based on tab's coordinate. So get the actual offsets between shell and evt.target. let elt = evt.target; let win = elt.ownerDocument.defaultView; let offsetX = win.mozInnerScreenX - window.mozInnerScreenX; let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
new file mode 100644 --- /dev/null +++ b/b2g/components/DebuggerActors.js @@ -0,0 +1,83 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { Cu } = require("chrome"); +const DevToolsUtils = require("devtools/toolkit/DevToolsUtils.js"); +const promise = require("promise"); +const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); +const { BrowserTabList } = require("devtools/server/actors/webbrowser"); + +XPCOMUtils.defineLazyGetter(this, "Frames", function() { + const { Frames } = + Cu.import("resource://gre/modules/Frames.jsm", {}); + return Frames; +}); + +/** + * Unlike the original BrowserTabList which iterates over XUL windows, we + * override many portions to refer to Frames for the info needed here. + */ +function B2GTabList(connection) { + BrowserTabList.call(this, connection); + this._listening = false; +} + +B2GTabList.prototype = Object.create(BrowserTabList.prototype); + +B2GTabList.prototype._getBrowsers = function() { + return Frames.list().filter(frame => { + // Ignore app frames + return !frame.getAttribute("mozapp"); + }); +}; + +B2GTabList.prototype._getSelectedBrowser = function() { + return this._getBrowsers().find(frame => { + // Find the one visible browser (if any) + return !frame.classList.contains("hidden"); + }); +}; + +B2GTabList.prototype._checkListening = function() { + // The conditions from BrowserTabList are merged here, since we must listen to + // all events with our observer design. + this._listenForEventsIf(this._onListChanged && this._mustNotify || + this._actorByBrowser.size > 0); +}; + +B2GTabList.prototype._listenForEventsIf = function(shouldListen) { + if (this._listening != shouldListen) { + let op = shouldListen ? "addObserver" : "removeObserver"; + Frames[op](this); + this._listening = shouldListen; + } +}; + +B2GTabList.prototype.onFrameCreated = function(frame) { + let mozapp = frame.getAttribute("mozapp"); + if (mozapp) { + // Ignore app frames + return; + } + this._notifyListChanged(); + this._checkListening(); +}; + +B2GTabList.prototype.onFrameDestroyed = function(frame) { + let mozapp = frame.getAttribute("mozapp"); + if (mozapp) { + // Ignore app frames + return; + } + let actor = this._actorByBrowser.get(frame); + if (actor) { + this._handleActorClose(actor, frame); + } +}; + +exports.B2GTabList = B2GTabList;
rename from b2g/components/AppFrames.jsm rename to b2g/components/Frames.jsm --- a/b2g/components/AppFrames.jsm +++ b/b2g/components/Frames.jsm @@ -1,15 +1,15 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -this.EXPORTED_SYMBOLS = ['AppFrames']; +this.EXPORTED_SYMBOLS = ['Frames']; const Cu = Components.utils; const Ci = Components.interfaces; Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/SystemAppProxy.jsm'); const listeners = []; @@ -22,21 +22,23 @@ const Observer = { // Also save current number of iframes opened by app _apps: new Map(), start: function () { Services.obs.addObserver(this, 'remote-browser-shown', false); Services.obs.addObserver(this, 'inprocess-browser-shown', false); Services.obs.addObserver(this, 'message-manager-disconnect', false); - SystemAppProxy.getAppFrames().forEach((frame) => { + SystemAppProxy.getFrames().forEach(frame => { let mm = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; this._frames.set(mm, frame); let mozapp = frame.getAttribute('mozapp'); - this._apps.set(mozapp, (this._apps.get(mozapp) || 0) + 1); + if (mozapp) { + this._apps.set(mozapp, (this._apps.get(mozapp) || 0) + 1); + } }); }, stop: function () { Services.obs.removeObserver(this, 'remote-browser-shown'); Services.obs.removeObserver(this, 'inprocess-browser-shown'); Services.obs.removeObserver(this, 'message-manager-disconnect'); this._frames.clear(); @@ -63,58 +65,66 @@ const Observer = { this.onMessageManagerDestroyed(subject); break; } }, onMessageManagerCreated: function (mm, frame) { this._frames.set(mm, frame); + let isFirstAppFrame = null; let mozapp = frame.getAttribute('mozapp'); - let count = (this._apps.get(mozapp) || 0) + 1; - this._apps.set(mozapp, count); + if (mozapp) { + let count = (this._apps.get(mozapp) || 0) + 1; + this._apps.set(mozapp, count); + isFirstAppFrame = (count === 1); + } - let isFirstAppFrame = (count === 1); listeners.forEach(function (listener) { try { - listener.onAppFrameCreated(frame, isFirstAppFrame); + listener.onFrameCreated(frame, isFirstAppFrame); } catch(e) { - dump('Exception while calling Frames.jsm listener:' + e + '\n' + e.stack + '\n'); + dump('Exception while calling Frames.jsm listener:' + e + '\n' + + e.stack + '\n'); } }); }, onMessageManagerDestroyed: function (mm) { let frame = this._frames.get(mm); if (!frame) { - // We receive an event for a non mozapp message manager + // We received an event for an unknown message manager return; } this._frames.delete(mm); + let isLastAppFrame = null; let mozapp = frame.getAttribute('mozapp'); - let count = (this._apps.get(mozapp) || 0) - 1; - this._apps.set(mozapp, count); + if (mozapp) { + let count = (this._apps.get(mozapp) || 0) - 1; + this._apps.set(mozapp, count); + isLastAppFrame = (count === 0); + } - let isLastAppFrame = (count === 0); listeners.forEach(function (listener) { try { - listener.onAppFrameDestroyed(frame, isLastAppFrame); + listener.onFrameDestroyed(frame, isLastAppFrame); } catch(e) { - dump('Exception while calling Frames.jsm listener:' + e + '\n' + e.stack + '\n'); + dump('Exception while calling Frames.jsm listener:' + e + '\n' + + e.stack + '\n'); } }); } }; -let AppFrames = this.AppFrames = { +let Frames = this.Frames = { - list: () => SystemAppProxy.getAppFrames(), + list: () => SystemAppProxy.getFrames(), addObserver: function (listener) { if (listeners.indexOf(listener) !== -1) { return; } listeners.push(listener); if (listeners.length == 1) {
--- a/b2g/components/SystemAppProxy.jsm +++ b/b2g/components/SystemAppProxy.jsm @@ -112,30 +112,23 @@ let SystemAppProxy = { } else { this._pendingListeners = this._pendingListeners.filter( args => { return args[0] != name || args[1] != listener; }); } }, - getAppFrames: function systemApp_getAppFrames() { + getFrames: function systemApp_getFrames() { let systemAppFrame = this._frame; if (!systemAppFrame) { return []; } - let list = [systemAppFrame]; - - // List all app frames hosted in the system app: the homescreen, - // all regular apps, activities, rocket bar, attention screen and the keyboard. - // Bookmark apps and other system app internal frames like captive portal - // are also hosted in system app, but they are not using mozapp attribute. - let frames = systemAppFrame.contentDocument.querySelectorAll("iframe[mozapp]"); + let frames = systemAppFrame.contentDocument.querySelectorAll('iframe'); for (let i = 0; i < frames.length; i++) { list.push(frames[i]); } - return list; } }; this.SystemAppProxy = SystemAppProxy;
--- a/b2g/components/moz.build +++ b/b2g/components/moz.build @@ -43,19 +43,20 @@ EXTRA_PP_COMPONENTS += [ if CONFIG['MOZ_UPDATER']: EXTRA_PP_COMPONENTS += [ 'UpdatePrompt.js', ] EXTRA_JS_MODULES += [ 'AlertsHelper.jsm', - 'AppFrames.jsm', 'ContentRequestHelper.jsm', + 'DebuggerActors.js', 'ErrorPage.jsm', + 'Frames.jsm', 'FxAccountsMgmtService.jsm', 'LogCapture.jsm', 'LogParser.jsm', 'LogShake.jsm', 'SignInToWebsite.jsm', 'SystemAppProxy.jsm', 'TelURIParser.jsm', 'WebappsUpdater.jsm',
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/> <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/> @@ -128,16 +128,16 @@ <project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/> <!-- dolphin specific things --> <project name="device/sprd" path="device/sprd" revision="3a0f1b51e3b27b36b9df484f3c286b6099889f6e"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/> <project name="platform/frameworks/av" path="frameworks/av" revision="4387fe988e5a1001f29ce05fcfda03ed2d32137b"/> <project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/> <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/> <project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/> - <project name="kernel/common" path="kernel" revision="250294fb70e018b0966402f744ff9705109f8635"/> + <project name="kernel/common" path="kernel" revision="310657b79caae2c89e6375a4185fe35fde089c39"/> <project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/> <project name="u-boot" path="u-boot" revision="982c1fd67b89d5573317c1796cf5b0143de44e8a"/> <project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/> <project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="1d4697b16ed039fd1de0a23bda150523e743e2ad"/> <project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/> <project name="vendor/sprd/proprietories" path="vendor/sprd/proprietories" revision="d2466593022f7078aaaf69026adf3367c2adb7bb"/> </manifest>
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -14,23 +14,23 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/> <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/> <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/> <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/> <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/> @@ -129,12 +129,12 @@ <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/> <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/> <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/> <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/> <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/> <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/> </manifest>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/> <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -14,23 +14,23 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/> <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/> <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/> <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/> <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -10,25 +10,25 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/> <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/> <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/> <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/> @@ -128,17 +128,17 @@ <remove-project name="platform/external/bluetooth/bluedroid"/> <!--original fetch url was git://github.com/t2m-foxfone/--> <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/> <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/> <!-- Flame specific things --> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/> <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/> <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="52c909e821d107d414f851e267dedcd7aae2cebf"/> - <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="1072f7d31dc0bf3a2adc64177b1104da9f4ce4b6"/> + <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="7731d63c809dbca4da408e1de0c1a044f0765e52"/> <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/> <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/> <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/> <project name="platform/frameworks/av" path="frameworks/av" revision="ea2f399b3ca0a23524d2828f85f69902caefc22e"/> <project name="platform/frameworks/base" path="frameworks/base" revision="6b58ab45e3e56c1fc20708cc39fa2264c52558df"/> <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/> <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/> @@ -146,13 +146,13 @@ <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/> <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e5a971282719907f73fb1da964ca40aad67a3be0"/> <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/> <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/> <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/> <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/> <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/> <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/> <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/> <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/> <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="7704e16da545f4207812e593743d6743e1afb9c5"/> </manifest>
--- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/> @@ -140,13 +140,13 @@ <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/> <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/> <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/> <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/> <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/> <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/> <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/> <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/> <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/> <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/> <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/> </manifest>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { "git_revision": "", "remote": "", "branch": "" }, - "revision": "eeeae73691f91cd5042660b0f19c84747ebc7be2", + "revision": "8017299c3eb7b82bdaee1334994f546c11eb16ab", "repo_path": "/integration/gaia-central" }
--- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -12,22 +12,22 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/> <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/> <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/> <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/> <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/mozconfigs/win32_gecko/debug +++ b/b2g/config/mozconfigs/win32_gecko/debug @@ -10,17 +10,17 @@ ac_add_options --enable-debug ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then - . $topsrcdir/build/win32/mozconfig.vs2010-win64 + . $topsrcdir/build/win32/mozconfig.vs2013-win64 else . $topsrcdir/build/win32/mozconfig.vs2010 fi # B2G Options ac_add_options --enable-application=b2g ENABLE_MARIONETTE=1
--- a/b2g/config/mozconfigs/win32_gecko/nightly +++ b/b2g/config/mozconfigs/win32_gecko/nightly @@ -9,17 +9,17 @@ ac_add_options --enable-signmar ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then - . $topsrcdir/build/win32/mozconfig.vs2010-win64 + . $topsrcdir/build/win32/mozconfig.vs2013-win64 else . $topsrcdir/build/win32/mozconfig.vs2010 fi # B2G Options ac_add_options --enable-application=b2g export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -12,20 +12,20 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/> <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/> <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/> @@ -124,17 +124,17 @@ <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/> <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/> <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/> <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/> <!-- Nexus 4 specific things --> <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/> <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/> - <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/> + <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/> <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/> <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/> <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/> <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/> <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/> <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/> <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -12,22 +12,22 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cc5da7b055e2b06fdeb46fa94970550392ee571d"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="5c636a7a54b2c86d8ff6bc1aa1e5f9594c7bc586"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> - <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/> + <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/> <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/> <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/> <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/> <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/b2g/confvars.sh +++ b/b2g/confvars.sh @@ -1,16 +1,16 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. MOZ_APP_BASENAME=B2G MOZ_APP_VENDOR=Mozilla -MOZ_APP_VERSION=35.0a1 +MOZ_APP_VERSION=36.0a1 MOZ_APP_UA_NAME=Firefox MOZ_UA_OS_AGNOSTIC=1 MOZ_B2G_VERSION=2.2.0.0-prerelease MOZ_B2G_OS_NAME=Boot2Gecko MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
--- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -110,17 +110,16 @@ #ifndef MOZ_FOLD_LIBS @BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@ #endif @BINPATH@/blocklist.xml @BINPATH@/ua-update.json #ifdef XP_UNIX #ifndef XP_MACOSX @BINPATH@/run-mozilla.sh -@BINPATH@/mozilla-xremote-client #endif #endif ; [Components] @BINPATH@/components/components.manifest @BINPATH@/components/alerts.xpt #ifdef ACCESSIBILITY #ifdef XP_WIN32
--- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -1,10 +1,10 @@ <?xml version="1.0"?> -<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1412277891000"> +<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1412711894000"> <emItems> <emItem blockID="i454" id="sqlmoz@facebook.com"> <versionRange minVersion="0" maxVersion="*" severity="3"> </versionRange> <versionRange minVersion="0" maxVersion="*" severity="3"> </versionRange> <prefs> </prefs> @@ -995,16 +995,22 @@ </prefs> </emItem> <emItem blockID="i172" id="info@bflix.info"> <versionRange minVersion="0" maxVersion="*" severity="3"> </versionRange> <prefs> </prefs> </emItem> + <emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}"> + <versionRange minVersion="0" maxVersion="*" severity="3"> + </versionRange> + <prefs> + </prefs> + </emItem> <emItem blockID="i525" id="/^({65f9f6b7-2dae-46fc-bfaf-f88e4af1beca}|{9ed31f84-c8b3-4926-b950-dff74047ff79}|{0134af61-7a0c-4649-aeca-90d776060cb3}|{02edb56b-9b33-435b-b7df-b2843273a694}|{da51d4f6-3e7e-4ef8-b400-9198e0874606}|{b24577db-155e-4077-bb37-3fdd3c302bb5})$/"> <versionRange minVersion="0" maxVersion="*" severity="1"> </versionRange> <prefs> </prefs> </emItem> <emItem blockID="i485" id="/^brasilescape.*\@facebook\.com$//"> <versionRange minVersion="0" maxVersion="*" severity="3">
--- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -269,20 +269,17 @@ static int do_main(int argc, char* argv[ if (NS_FAILED(rv)) { Output("Couldn't find the application directory.\n"); return 255; } nsCOMPtr<nsIFile> greDir; exeFile->GetParent(getter_AddRefs(greDir)); #ifdef XP_MACOSX - nsCOMPtr<nsIFile> parent; - greDir->GetParent(getter_AddRefs(parent)); - greDir = parent.forget(); - greDir->AppendNative(NS_LITERAL_CSTRING(kOSXResourcesFolder)); + greDir->SetNativeLeafName(NS_LITERAL_CSTRING(kOSXResourcesFolder)); #endif nsCOMPtr<nsIFile> appSubdir; greDir->Clone(getter_AddRefs(appSubdir)); appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder)); SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get())); // xreDirectory already has a refcount from NS_NewLocalFile appData.xreDirectory = xreDirectory;
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1287,16 +1287,17 @@ pref("services.sync.prefs.sync.security. pref("services.sync.prefs.sync.security.tls.version.max", true); pref("services.sync.prefs.sync.signon.rememberSignons", true); pref("services.sync.prefs.sync.spellchecker.dictionary", true); pref("services.sync.prefs.sync.xpinstall.whitelist.required", true); #endif // Developer edition preferences pref("browser.devedition.theme.enabled", false); +pref("browser.devedition.theme.showCustomizeButton", false); // Disable the error console pref("devtools.errorconsole.enabled", false); // Developer toolbar and GCLI preferences pref("devtools.toolbar.enabled", true); pref("devtools.toolbar.visible", false); pref("devtools.commands.dir", ""); @@ -1374,16 +1375,23 @@ pref("devtools.debugger.ui.panes-visible pref("devtools.debugger.ui.variables-sorting-enabled", true); pref("devtools.debugger.ui.variables-only-enum-visible", false); pref("devtools.debugger.ui.variables-searchbox-visible", false); // Enable the Profiler and the Timeline pref("devtools.profiler.enabled", true); pref("devtools.timeline.enabled", false); +// Enable perftools via build command +#ifdef MOZ_DEVTOOLS_PERFTOOLS + pref("devtools.performance_dev.enabled", true); +#else + pref("devtools.performance_dev.enabled", false); +#endif + // The default Profiler UI settings pref("devtools.profiler.ui.show-platform-data", false); // The default cache UI setting pref("devtools.cache.disabled", false); // Enable the Network Monitor pref("devtools.netmonitor.enabled", true); @@ -1411,17 +1419,17 @@ pref("devtools.scratchpad.recentFilesMax pref("devtools.scratchpad.showTrailingSpace", false); pref("devtools.scratchpad.enableAutocompletion", true); // Enable the Storage Inspector pref("devtools.storage.enabled", false); // Enable the Style Editor. pref("devtools.styleeditor.enabled", true); -pref("devtools.styleeditor.source-maps-enabled", false); +pref("devtools.styleeditor.source-maps-enabled", true); pref("devtools.styleeditor.autocompletion-enabled", true); pref("devtools.styleeditor.showMediaSidebar", true); pref("devtools.styleeditor.mediaSidebarWidth", 238); pref("devtools.styleeditor.navSidebarWidth", 245); pref("devtools.styleeditor.transitions", true); // Enable the Shader Editor. pref("devtools.shadereditor.enabled", false); @@ -1547,17 +1555,17 @@ pref("browser.newtabpage.enabled", true) // number of rows of newtab grid pref("browser.newtabpage.rows", 3); // number of columns of newtab grid pref("browser.newtabpage.columns", 5); // directory tiles download URL -pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch"); +pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch/%LOCALE%"); // endpoint to send newtab click and view pings pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v2/links/"); // Enable the DOM fullscreen API. pref("full-screen-api.enabled", true); // True if the fullscreen API requires approval upon a domain entering fullscreen.
--- a/browser/base/content/aboutDialog.xul +++ b/browser/base/content/aboutDialog.xul @@ -123,17 +123,17 @@ <description class="text-blurb" id="communityExperimentalDesc"> &community.exp.start;<label class="text-link" href="http://www.mozilla.org/">&community.exp.mozillaLink;</label>&community.exp.middle;<label class="text-link" href="about:credits">&community.exp.creditsLink;</label>&community.exp.end; </description> </vbox> <description class="text-blurb" id="communityDesc"> &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end3; </description> <description class="text-blurb" id="contributeDesc"> - &contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end; + &helpus.start;<label class="text-link" href="https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_default_footer&ref=firefox_about&utm_campaign=firefox_about&tm_source=firefox&tm_medium=referral&utm_content=20140929_FireFoxAbout">&helpus.donateLink;</label>&helpus.middle;<label class="text-link" href="http://www.mozilla.org/contribute/">&helpus.getInvolvedLink;</label>&helpus.end; </description> </vbox> </vbox> </hbox> <vbox id="bottomBox"> <hbox pack="center"> <label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label> <label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
--- a/browser/base/content/aboutaccounts/aboutaccounts.js +++ b/browser/base/content/aboutaccounts/aboutaccounts.js @@ -285,32 +285,32 @@ function getStarted() { } function openPrefs() { window.openPreferences("paneSync"); } function init() { fxAccounts.getSignedInUser().then(user => { + // tests in particular might cause the window to start closing before + // getSignedInUser has returned. + if (window.closed) { + return; + } // If the url contains an entrypoint query parameter, extract it into a variable // to append it to the accounts URI resource. // Works for the following cases: // - about:accounts?entrypoint="abouthome" // - about:accounts?entrypoint=abouthome&action=signup let entryPointQParam = "entrypoint="; let entryPointPos = window.location.href.indexOf(entryPointQParam); let entryPoint = ""; if (entryPointPos >= 0) { entryPoint = window.location.href.substring(entryPointPos).split("&")[0]; } - // tests in particular might cause the window to start closing before - // getSignedInUser has returned. - if (window.closed) { - return; - } if (window.location.href.contains("action=signin")) { if (user) { // asking to sign-in when already signed in just shows manage. show("stage", "manage"); } else { show("remote"); wrapper.init(fxAccounts.getAccountsSignInURI(), entryPoint); }
--- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -703,23 +703,22 @@ var BookmarksEventHandler = { fillInBHTooltip: function BEH_fillInBHTooltip(aDocument, aEvent) { var node; var cropped = false; var targetURI; if (aDocument.tooltipNode.localName == "treechildren") { var tree = aDocument.tooltipNode.parentNode; - var row = {}, column = {}; var tbo = tree.treeBoxObject; - tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, column, {}); - if (row.value == -1) + var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY); + if (cell.row == -1) return false; - node = tree.view.nodeForTreeIndex(row.value); - cropped = tbo.isCellCropped(row.value, column.value); + node = tree.view.nodeForTreeIndex(cell.row); + cropped = tbo.isCellCropped(cell.row, cell.col); } else { // Check whether the tooltipNode is a Places node. // In such a case use it, otherwise check for targetURI attribute. var tooltipNode = aDocument.tooltipNode; if (tooltipNode._placesNode) node = tooltipNode._placesNode; else {
--- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -246,23 +246,29 @@ var gPluginHandler = { pluginData = new Map(); } for (var pluginInfo of plugins) { if (pluginData.has(pluginInfo.permissionString)) { continue; } - let url; - // TODO: allow the blocklist to specify a better link, bug 873093 + // If a block contains an infoURL, we should always prefer that to the default + // URL that we construct in-product, even for other blocklist types. + let url = Services.blocklist.getPluginInfoURL(pluginInfo.pluginTag); + if (pluginInfo.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) { - url = Services.urlFormatter.formatURLPref("plugins.update.url"); + if (!url) { + url = Services.urlFormatter.formatURLPref("plugins.update.url"); + } } else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) { - url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag); + if (!url) { + url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag); + } } else { url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay"; } pluginInfo.detailsLink = url; pluginData.set(pluginInfo.permissionString, pluginInfo); }
--- a/browser/base/content/newtab/newTab.css +++ b/browser/base/content/newtab/newTab.css @@ -56,16 +56,20 @@ input[type=button] { top: 15px; } #newtab-intro-what:-moz-locale-dir(rtl) { left: 55px; right: auto; } +#newtab-scrollbox[page-disabled] #newtab-intro-what { + display: none; +} + #newtab-intro-panel { color: #6a7b86; font-size: 15px; line-height: 19px; width: 520px; } #newtab-intro-panel h1 {
--- a/browser/base/content/newtab/updater.js +++ b/browser/base/content/newtab/updater.js @@ -149,32 +149,29 @@ let gUpdater = { /** * Tries to fill empty cells with new links if available. * @param aLinks The array of links. * @param aCallback The callback to call when finished. */ _fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) { let {cells, sites} = gGrid; - let batch = []; // Find empty cells and fill them. - sites.forEach(function (aSite, aIndex) { + Promise.all(sites.map((aSite, aIndex) => { if (aSite || !aLinks[aIndex]) - return; + return null; - batch.push(new Promise(resolve => { + return new Promise(resolve => { // Create the new site and fade it in. let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]); // Set the site's initial opacity to zero. site.node.style.opacity = 0; // Flush all style changes for the dynamically inserted site to make // the fade-in transition work. window.getComputedStyle(site.node).opacity; gTransformation.showSite(site, resolve); - })); - }); - - Promise.all(batch).then(aCallback); + }); + })).then(aCallback).catch(console.exception); } };
--- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -503,17 +503,17 @@ function makeGeneralTab() metaGroup.collapsed = true; else { var metaTagsCaption = document.getElementById("metaTagsCaption"); if (length == 1) metaTagsCaption.label = gBundle.getString("generalMetaTag"); else metaTagsCaption.label = gBundle.getFormattedString("generalMetaTags", [length]); var metaTree = document.getElementById("metatree"); - metaTree.treeBoxObject.view = gMetaView; + metaTree.view = gMetaView; for (var i = 0; i < length; i++) gMetaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]); metaGroup.collapsed = false; } // get the date of last modification
--- a/browser/base/content/pageinfo/permissions.js +++ b/browser/base/content/pageinfo/permissions.js @@ -1,13 +1,14 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ Components.utils.import("resource:///modules/SitePermissions.jsm"); +Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); const nsIQuotaManager = Components.interfaces.nsIQuotaManager; var gPermURI; var gUsageRequest; var gPermissions = SitePermissions.listPermissions(); gPermissions.push("plugins"); @@ -226,30 +227,16 @@ function onIndexedDBUsageCallback(uri, u status.value = gBundle.getFormattedString("indexedDBUsage", DownloadUtils.convertByteUnits(usage)); status.removeAttribute("hidden"); button.removeAttribute("hidden"); } } -// XXX copied this from browser-plugins.js - is there a way to share? -function makeNicePluginName(aName) { - if (aName == "Shockwave Flash") - return "Adobe Flash"; - - // Clean up the plugin name by stripping off any trailing version numbers - // or "plugin". EG, "Foo Bar Plugin 1.23_02" --> "Foo Bar" - // Do this by first stripping the numbers, etc. off the end, and then - // removing "Plugin" (and then trimming to get rid of any whitespace). - // (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled) - let newName = aName.replace(/[\s\d\.\-\_\(\)]+$/, "").replace(/\bplug-?in\b/i, "").trim(); - return newName; -} - function fillInPluginPermissionTemplate(aPluginName, aPermissionString) { let permPluginTemplate = document.getElementById("permPluginTemplate").cloneNode(true); permPluginTemplate.setAttribute("permString", aPermissionString); let attrs = [ [ ".permPluginTemplateLabel", "value", aPluginName ], [ ".permPluginTemplateRadioGroup", "id", aPermissionString + "RadioGroup" ], [ ".permPluginTemplateRadioDefault", "id", aPermissionString + "#0" ], [ ".permPluginTemplateRadioAsk", "id", aPermissionString + "#3" ], @@ -283,17 +270,17 @@ function initPluginsRow() { for (let plugin of pluginHost.getPluginTags()) { if (plugin.disabled) { continue; } for (let mimeType of plugin.getMimeTypes()) { let permString = pluginHost.getPermissionStringForType(mimeType); if (!permissionMap.has(permString)) { - var name = makeNicePluginName(plugin.name); + let name = BrowserUtils.makeNicePluginName(plugin.name); if (permString.startsWith("plugin-vulnerable:")) { name += " \u2014 " + vulnerableLabel; } permissionMap.set(permString, name); } } }
--- a/browser/base/content/popup-notifications.inc +++ b/browser/base/content/popup-notifications.inc @@ -54,8 +54,14 @@ </popupnotification> <popupnotification id="pointerLock-notification" hidden="true"> <popupnotificationcontent orient="vertical" align="start"> <separator class="thin"/> <label id="pointerLock-cancel" value="&pointerLock.notification.message;"/> </popupnotificationcontent> </popupnotification> + +#ifdef E10S_TESTING_ONLY + <popupnotification id="enable-e10s-notification" hidden="true"> + <popupnotificationcontent orient="vertical"/> + </popupnotification> +#endif
--- a/browser/base/content/safeMode.js +++ b/browser/base/content/safeMode.js @@ -67,17 +67,16 @@ function onExtra1() { } function onLoad() { let dialog = document.documentElement; if (appStartup.automaticSafeModeNecessary) { document.getElementById("autoSafeMode").hidden = false; document.getElementById("safeMode").hidden = true; if (ResetProfile.resetSupported()) { - populateResetPane("resetProfileItems"); document.getElementById("resetProfile").hidden = false; } else { // Hide the reset button is it's not supported. document.documentElement.getButton("extra1").hidden = true; } } else { if (!ResetProfile.resetSupported()) { // Hide the reset button and text if it's not supported.
--- a/browser/base/content/safeMode.xul +++ b/browser/base/content/safeMode.xul @@ -16,47 +16,36 @@ <?xml-stylesheet href="chrome://global/skin/"?> <?xml-stylesheet href="chrome://browser/content/safeMode.css"?> <dialog id="safeModeDialog" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="&safeModeDialog.title;" buttons="accept,extra1" buttonlabelaccept="&startSafeMode.label;" - buttonlabelextra1="&resetProfile.label;" + buttonlabelextra1="&refreshProfile.label;" maxwidth="&window.maxWidth;" ondialogaccept="return onDefaultButton()" ondialogcancel="onCancel();" ondialogextra1="return onExtra1()" onload="onLoad()"> <script type="application/javascript" src="chrome://global/content/resetProfile.js"/> <script type="application/javascript" src="chrome://browser/content/safeMode.js"/> <vbox id="autoSafeMode" hidden="true"> - <description>&autoSafeModeDescription2.label;</description> + <description>&autoSafeModeDescription3.label;</description> </vbox> - <vbox id ="safeMode"> + <vbox id="safeMode"> <label>&safeModeDescription3.label;</label> <separator class="thin"/> <label>&safeModeDescription4.label;</label> <separator class="thin"/> - <label id="resetProfileInstead">&resetProfileInstead.label;</label> + <label id="resetProfileInstead">&refreshProfileInstead.label;</label> </vbox> <vbox id="resetProfile" hidden="true"> - <label>&resetProfile.dialog.items2.label;</label> - - <vbox id="resetProfileItems" class="indent"> - </vbox> - - <separator class="thin"/> - - <label id="resetProfileFooter">&resetProfileFooter.label;</label> - - <label>&safeModeInstead.label;</label> - - <separator/> + <label id="resetProfileInstead">&refreshProfileInstead.label;</label> </vbox> <separator class="thin"/> </dialog>
--- a/browser/base/content/sanitize.js +++ b/browser/base/content/sanitize.js @@ -389,35 +389,50 @@ Sanitizer.prototype = { return true; } }, siteSettings: { clear: function () { // Clear site-specific permissions like "Allow this site to open popups" + // we ignore the "end" range and hope it is now() - none of the + // interfaces used here support a true range anyway. + let startDateMS = this.range == null ? null : this.range[0] / 1000; var pm = Components.classes["@mozilla.org/permissionmanager;1"] .getService(Components.interfaces.nsIPermissionManager); - pm.removeAll(); + if (startDateMS == null) { + pm.removeAll(); + } else { + pm.removeAllSince(startDateMS); + } // Clear site-specific settings like page-zoom level var cps = Components.classes["@mozilla.org/content-pref/service;1"] .getService(Components.interfaces.nsIContentPrefService2); - cps.removeAllDomains(null); + if (startDateMS == null) { + cps.removeAllDomains(null); + } else { + cps.removeAllDomainsSince(startDateMS, null); + } // Clear "Never remember passwords for this site", which is not handled by // the permission manager + // (Note the login manager doesn't support date ranges yet, and bug + // 1058438 is calling for loginSaving stuff to end up in the + // permission manager) var pwmgr = Components.classes["@mozilla.org/login-manager;1"] .getService(Components.interfaces.nsILoginManager); var hosts = pwmgr.getAllDisabledHosts(); for each (var host in hosts) { pwmgr.setLoginSavingEnabled(host, true); } - // Clear site security settings + // Clear site security settings - no support for ranges in this + // interface either, so we clearAll(). var sss = Cc["@mozilla.org/ssservice;1"] .getService(Ci.nsISiteSecurityService); sss.clearAll(); }, get canClear() { return true;
--- a/browser/base/content/searchSuggestionUI.js +++ b/browser/base/content/searchSuggestionUI.js @@ -296,16 +296,17 @@ SearchSuggestionUIController.prototype = _speculativeConnect: function () { if (this.engineName) { this._sendMsg("SpeculativeConnect", this.engineName); } }, _makeTableRow: function (type, suggestionStr, currentRow, searchWords) { let row = document.createElementNS(HTML_NS, "tr"); + row.dir = "auto"; row.classList.add("searchSuggestionRow"); row.classList.add(type); row.setAttribute("role", "presentation"); row.addEventListener("mousemove", this); row.addEventListener("mousedown", this); let entry = document.createElementNS(HTML_NS, "td"); entry.classList.add("searchSuggestionEntry"); @@ -360,17 +361,16 @@ SearchSuggestionUIController.prototype = } return row.rowIndex; }, _makeTable: function (id) { this._table = document.createElementNS(HTML_NS, "table"); this._table.id = id; this._table.hidden = true; - this._table.dir = "auto"; this._table.classList.add("searchSuggestionTable"); this._table.setAttribute("role", "listbox"); return this._table; }, _sendMsg: function (type, data=null) { dispatchEvent(new CustomEvent("ContentSearchClient", { detail: {
--- a/browser/base/content/sync/quota.js +++ b/browser/base/content/sync/quota.js @@ -156,20 +156,19 @@ let gUsageTreeView = { /* * Handle click events on the tree. */ onTreeClick: function onTreeClick(event) { if (event.button == 2) return; - let row = {}, col = {}; - this.treeBox.getCellAt(event.clientX, event.clientY, row, col, {}); - if (col.value && col.value.id == "enabled") - this.toggle(row.value); + let cell = this.treeBox.getCellAt(event.clientX, event.clientY); + if (cell.col && cell.col.id == "enabled") + this.toggle(cell.row); }, /* * Toggle enabled state of an engine. */ toggle: function toggle(row) { // Update the tree let collection = this._collections[row];
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1157,56 +1157,61 @@ // Since the user is switching away from a tab that has // a beforeunload prompt active, we remove the prompt. // This prevents confusing user flows like the following: // 1. User attempts to close Firefox // 2. User switches tabs (ingoring a beforeunload prompt) // 3. User returns to tab, presses "Leave page" let promptBox = this.getTabModalPromptBox(oldBrowser); let prompts = promptBox.listPrompts(); - // NB: This code assumes that the beforeunload prompt - // is the top-most prompt on the tab. - promptBox.removePrompt(prompts[prompts.length - 1]); + // There might not be any prompts here if the tab was closed + // while in an onbeforeunload prompt, which will have + // destroyed aforementioned prompt already, so check there's + // something to remove, first: + if (prompts.length) { + // NB: This code assumes that the beforeunload prompt + // is the top-most prompt on the tab. + promptBox.removePrompt(prompts[prompts.length - 1]); + } + } + + oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused); + if (this.isFindBarInitialized(oldTab)) { + let findBar = this.getFindBar(oldTab); + oldTab._findBarFocused = (!findBar.hidden && + findBar._findField.getAttribute("focused") == "true"); + } + + // If focus is in the tab bar, retain it there. + if (document.activeElement == oldTab) { + // We need to explicitly focus the new tab, because + // tabbox.xml does this only in some cases. + this.mCurrentTab.focus(); } if (!gMultiProcessBrowser) - this._adjustFocusAfterTabSwitch(this.mCurrentTab, oldTab); + this._adjustFocusAfterTabSwitch(this.mCurrentTab); } this.tabContainer._setPositionalAttributes(); if (!aForceUpdate) TelemetryStopwatch.finish("FX_TAB_SWITCH_UPDATE_MS"); ]]> </body> </method> <method name="_adjustFocusAfterTabSwitch"> <parameter name="newTab"/> - <parameter name="oldTab"/> <body><![CDATA[ let newBrowser = this.getBrowserForTab(newTab); - let oldBrowser = this.getBrowserForTab(oldTab); - - if (oldBrowser) { - oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused); - if (this.isFindBarInitialized(oldTab)) { - let findBar = this.getFindBar(oldTab); - oldTab._findBarFocused = (!findBar.hidden && - findBar._findField.getAttribute("focused") == "true"); - } - } - - // When focus is in the tab bar, retain it there. - if (document.activeElement == oldTab) { - // We need to explicitly focus the new tab, because - // tabbox.xml does this only in some cases. - this.mCurrentTab.focus(); + + // Don't steal focus from the tab bar. + if (document.activeElement == newTab) return; - } // If there's a tabmodal prompt showing, focus it. if (newBrowser.hasAttribute("tabmodalPromptShowing")) { let XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; let prompts = newBrowser.parentNode.getElementsByTagNameNS(XUL_NS, "tabmodalprompt"); let prompt = prompts[prompts.length - 1]; prompt.Dialog.setDefaultFocus(); return; @@ -1936,33 +1941,35 @@ <method name="_beginRemoveTab"> <parameter name="aTab"/> <parameter name="aTabWillBeMoved"/> <parameter name="aCloseWindowWithLastTab"/> <parameter name="aCloseWindowFastpath"/> <body> <![CDATA[ if (aTab.closing || - aTab._pendingPermitUnload || this._windowIsClosing) return false; var browser = this.getBrowserForTab(aTab); - - if (!aTabWillBeMoved) { + if (!aTab._pendingPermitUnload && !aTabWillBeMoved) { let ds = browser.docShell; if (ds && ds.contentViewer) { // We need to block while calling permitUnload() because it // processes the event queue and may lead to another removeTab() // call before permitUnload() even returned. aTab._pendingPermitUnload = true; let permitUnload = ds.contentViewer.permitUnload(); delete aTab._pendingPermitUnload; - - if (!permitUnload) { + // If we were closed during onbeforeunload, we return false now + // so we don't (try to) close the same tab again. Of course, we + // also stop if the unload was cancelled by the user: + if (aTab.closing || !permitUnload) { + // NB: deliberately keep the _closedDuringPermitUnload set to + // true so we keep exiting early in case of multiple calls. return false; } } } var closeWindow = false; var newTab = false; if (this.tabs.length - this._removingTabs.length == 1) { @@ -3309,17 +3316,17 @@ } ]]></body> </method> <method name="_finalizeTabSwitch"> <parameter name="toTab"/> <parameter name="fromTab"/> <body><![CDATA[ - this._adjustFocusAfterTabSwitch(toTab, fromTab); + this._adjustFocusAfterTabSwitch(toTab); this._deactivateContent(fromTab); let toBrowser = this.getBrowserForTab(toTab); toBrowser.setAttribute("type", "content-primary"); let fromBrowser = this.getBrowserForTab(fromTab); // It's possible that the tab we're switching from closed // before we were able to finalize, in which case, fromBrowser
--- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -50,16 +50,17 @@ support-files = file_bug906190_redirected.html file_bug906190.js file_bug906190.sjs file_bug970276_popup1.html file_bug970276_popup2.html file_bug970276_favicon1.ico file_bug970276_favicon2.ico file_dom_notifications.html + file_double_close_tab.html file_favicon_change.html file_fullscreen-window-open.html get_user_media.html head.js healthreport_testRemoteCommands.html moz.png offlineQuotaNotification.cacheManifest offlineQuotaNotification.html @@ -311,16 +312,18 @@ skip-if = e10s run-if = datareporting [browser_devedition.js] [browser_devices_get_user_media.js] skip-if = buildapp == 'mulet' || (os == "linux" && debug) || e10s # linux: bug 976544; e10s: Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent? [browser_devices_get_user_media_about_urls.js] skip-if = e10s # Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent? [browser_discovery.js] skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome +[browser_double_close_tab.js] +skip-if = e10s [browser_duplicateIDs.js] [browser_drag.js] skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. [browser_favicon_change.js] skip-if = e10s [browser_findbarClose.js] skip-if = e10s # Bug ?????? - test directly manipulates content (tries to grab an iframe directly from content) [browser_fullscreen-window-open.js]
--- a/browser/base/content/test/general/browser_aboutAccounts.js +++ b/browser/base/content/test/general/browser_aboutAccounts.js @@ -1,12 +1,19 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null"); + XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", "resource://gre/modules/FxAccounts.jsm"); const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/general/";
--- a/browser/base/content/test/general/browser_aboutHome.js +++ b/browser/base/content/test/general/browser_aboutHome.js @@ -1,12 +1,20 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: Assert is null"); + + XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils", "resource:///modules/AboutHome.jsm"); const TEST_CONTENT_HELPER = "chrome://mochitests/content/browser/browser/base/content/test/general/aboutHome_content_script.js";
--- a/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js +++ b/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js @@ -1,11 +1,19 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null"); + + add_task(function* checkIdentityOfAboutSupport() { let tab = gBrowser.loadOneTab("about:support", { referrerURI: null, inBackground: false, allowThirdPartyFixup: false, relatedToCurrent: false, skipAnimation: true, allowMixedContent: false
--- a/browser/base/content/test/general/browser_action_searchengine.js +++ b/browser/base/content/test/general/browser_action_searchengine.js @@ -38,14 +38,16 @@ add_task(function* () { gBrowser.removeTab(tab); } catch(ex) { /* tab may have already been closed in case of failure */ } return promiseClearHistory(); }); let result = yield promise_first_result("open a search"); isnot(result, null, "Should have a result"); + is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute"); + let tabPromise = promiseTabLoaded(gBrowser.selectedTab); EventUtils.synthesizeMouseAtCenter(result, {}); yield tabPromise; is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search"); });
--- a/browser/base/content/test/general/browser_action_searchengine_alias.js +++ b/browser/base/content/test/general/browser_action_searchengine_alias.js @@ -1,42 +1,48 @@ /** * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ **/ - let gOriginalEngine; +let gOriginalEngine; add_task(function* () { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) - return; + Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true); - Services.search.addEngineWithDetails("MozSearch", "", "moz", "", "GET", + let iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC"; + Services.search.addEngineWithDetails("MozSearch", iconURI, "moz", "", "GET", "http://example.com/?q={searchTerms}"); let engine = Services.search.getEngineByName("MozSearch"); gOriginalEngine = Services.search.currentEngine; Services.search.currentEngine = engine; let tab = gBrowser.selectedTab = gBrowser.addTab(); registerCleanupFunction(() => { Services.search.currentEngine = gOriginalEngine; let engine = Services.search.getEngineByName("MozSearch"); Services.search.removeEngine(engine); + Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete"); try { gBrowser.removeTab(tab); } catch(ex) { /* tab may have already been closed in case of failure */ } return promiseClearHistory(); }); gURLBar.focus(); gURLBar.value = "moz open a searc"; EventUtils.synthesizeKey("h" , {}); yield promiseSearchComplete(); + let result = gURLBar.popup.richlistbox.children[0]; + ok(result.hasAttribute("image"), "Result should have an image attribute"); + // Image attribute gets a suffix (-moz-resolution) added in the value. + ok(result.getAttribute("image").startsWith(engine.iconURI.spec), + "Image attribute should have the search engine's icon"); + EventUtils.synthesizeKey("VK_RETURN" , { }); yield promiseTabLoaded(gBrowser.selectedTab); is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search"); });
--- a/browser/base/content/test/general/browser_devedition.js +++ b/browser/base/content/test/general/browser_devedition.js @@ -19,17 +19,19 @@ registerCleanupFunction(() => { }); function test() { waitForExplicitFinish(); startTests(); } function startTests() { - ok (!DevEdition.styleSheet, "There is no devedition style sheet by default."); + info ("Setting browser.devedition.theme.enabled to false."); + Services.prefs.setBoolPref(PREF_DEVEDITION_THEME, false); + ok (!DevEdition.styleSheet, "There is no devedition style sheet when the pref is false."); info ("Setting browser.devedition.theme.enabled to true."); Services.prefs.setBoolPref(PREF_DEVEDITION_THEME, true); ok (DevEdition.styleSheet, "There is a devedition stylesheet when no themes are applied and pref is set."); info ("Adding a lightweight theme."); Services.prefs.setBoolPref(PREF_LWTHEME, true); ok (!DevEdition.styleSheet, "The devedition stylesheet has been removed when a lightweight theme is applied."); @@ -48,16 +50,17 @@ function startTests() { Services.prefs.clearUserPref(PREF_THEME); ok (DevEdition.styleSheet, "The devedition stylesheet is still here when a complete theme is removed."); info ("Setting browser.devedition.theme.enabled to false."); Services.prefs.setBoolPref(PREF_DEVEDITION_THEME, false); ok (!DevEdition.styleSheet, "The devedition stylesheet has been removed."); info ("Checking :root attributes based on devtools theme."); + Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light"); is (document.documentElement.getAttribute("devtoolstheme"), "light", "The documentElement has an attribute based on devtools theme."); Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark"); is (document.documentElement.getAttribute("devtoolstheme"), "dark", "The documentElement has an attribute based on devtools theme."); Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light"); is (document.documentElement.getAttribute("devtoolstheme"), "light", "The documentElement has an attribute based on devtools theme.");
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/general/browser_double_close_tab.js @@ -0,0 +1,80 @@ +"use strict"; +const TEST_PAGE = "http://mochi.test:8888/browser/browser/base/content/test/general/file_double_close_tab.html"; +let testTab; + +function waitForDialog(callback) { + function onTabModalDialogLoaded(node) { + Services.obs.removeObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded"); + callback(node); + } + + // Listen for the dialog being created + Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded", false); +} + +function waitForDialogDestroyed(node, callback) { + // Now listen for the dialog going away again... + let observer = new MutationObserver(function(muts) { + if (!node.parentNode) { + ok(true, "Dialog is gone"); + done(); + } + }); + observer.observe(node.parentNode, {childList: true}); + let failureTimeout = setTimeout(function() { + ok(false, "Dialog should have been destroyed"); + done(); + }, 10000); + + function done() { + clearTimeout(failureTimeout); + observer.disconnect(); + observer = null; + callback(); + } +} + +add_task(function*() { + testTab = gBrowser.selectedTab = gBrowser.addTab(); + yield promiseTabLoadEvent(testTab, TEST_PAGE); + //XXXgijs the reason this has nesting and callbacks rather than promises is + // that DOM promises resolve on the next tick. So they're scheduled + // in an event queue. So when we spin a new event queue for a modal dialog... + // everything gets messed up and the promise's .then callbacks never get + // called, despite resolve() being called just fine. + let dialogNode = yield new Promise(resolveOuter => { + waitForDialog(dialogNode => { + waitForDialogDestroyed(dialogNode, () => { + let doCompletion = () => setTimeout(resolveOuter, 0); + info("Now checking if dialog is destroyed"); + ok(!dialogNode.parentNode, "onbeforeunload dialog should be gone."); + if (dialogNode.parentNode) { + // Failed to remove onbeforeunload dialog, so do it ourselves: + let leaveBtn = dialogNode.ui.button0; + waitForDialogDestroyed(dialogNode, doCompletion); + EventUtils.synthesizeMouseAtCenter(leaveBtn, {}); + return; + } + doCompletion(); + }); + // Click again: + document.getAnonymousElementByAttribute(testTab, "anonid", "close-button").click(); + }); + // Click once: + document.getAnonymousElementByAttribute(testTab, "anonid", "close-button").click(); + }); + yield promiseWaitForCondition(() => !testTab.parentNode); + ok(!testTab.parentNode, "Tab should be closed completely"); +}); + +registerCleanupFunction(function() { + if (testTab.parentNode) { + // Remove the handler, or closing this tab will prove tricky: + try { + testTab.linkedBrowser.contentWindow.onbeforeunload = null; + } catch (ex) {} + gBrowser.removeTab(testTab); + } +}); + +
--- a/browser/base/content/test/general/browser_fxa_oauth.js +++ b/browser/base/content/test/general/browser_fxa_oauth.js @@ -1,12 +1,19 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null"); + Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsOAuthClient", "resource://gre/modules/FxAccountsOAuthClient.jsm"); const HTTP_PATH = "http://example.com"; const HTTP_ENDPOINT = "/browser/browser/base/content/test/general/browser_fxa_oauth.html";
--- a/browser/base/content/test/general/browser_notification_tab_switching.js +++ b/browser/base/content/test/general/browser_notification_tab_switching.js @@ -1,58 +1,95 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -"use strict"; - -let tab; -let notification; -let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; - -function test () { - waitForExplicitFinish(); - - let pm = Services.perms; - registerCleanupFunction(function() { - pm.remove(notificationURL, "desktop-notification"); - gBrowser.removeTab(tab); - window.restore(); - }); - - pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); - - tab = gBrowser.addTab(notificationURL); - tab.linkedBrowser.addEventListener("load", onLoad, true); -} - -function onLoad() { - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - tab.linkedBrowser.removeEventListener("load", onLoad, true); - let win = tab.linkedBrowser.contentWindow.wrappedJSObject; - notification = win.showNotification(); - notification.addEventListener("show", onAlertShowing); -} - -function onAlertShowing() { - info("Notification alert showing"); - notification.removeEventListener("show", onAlertShowing); - - let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); - if (!alertWindow) { - todo(false, "Notifications don't use XUL windows on all platforms."); - notification.close(); - finish(); - return; - } - gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); - EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); - info("Clicked on notification"); - alertWindow.close(); -} - -function onTabSelect() { - gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); - is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, - "Notification tab should be selected."); - - finish(); -} +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +let tab; +let notification; +let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html"; +let newWindowOpenedFromTab; + +function test () { + waitForExplicitFinish(); + + let pm = Services.perms; + registerCleanupFunction(function() { + pm.remove(notificationURL, "desktop-notification"); + gBrowser.removeTab(tab); + window.restore(); + }); + + pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); + + tab = gBrowser.addTab(notificationURL); + tab.linkedBrowser.addEventListener("load", onLoad, true); +} + +function onLoad() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + tab.linkedBrowser.removeEventListener("load", onLoad, true); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + win.newWindow = win.open("about:blank", "", "height=100,width=100"); + newWindowOpenedFromTab = win.newWindow; + win.newWindow.addEventListener("load", function() { + info("new window loaded"); + win.newWindow.addEventListener("blur", function b() { + info("new window got blur"); + win.newWindow.removeEventListener("blur", b); + notification = win.showNotification1(); + win.newWindow.addEventListener("focus", onNewWindowFocused); + notification.addEventListener("show", onAlertShowing); + }); + + function waitUntilNewWindowHasFocus() { + if (!win.newWindow.document.hasFocus()) { + setTimeout(waitUntilNewWindowHasFocus, 50); + } else { + // Focus another window so that new window gets blur event. + gBrowser.selectedTab.linkedBrowser.contentWindow.focus(); + } + } + win.newWindow.focus(); + waitUntilNewWindowHasFocus(); + }); +} + +function onAlertShowing() { + info("Notification alert showing"); + notification.removeEventListener("show", onAlertShowing); + + let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul"); + if (!alertWindow) { + todo(false, "Notifications don't use XUL windows on all platforms."); + notification.close(); + newWindowOpenedFromTab.close(); + finish(); + return; + } + gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); + EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); + info("Clicked on notification"); + alertWindow.close(); +} + +function onNewWindowFocused(event) { + event.target.close(); + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + // Using timeout to test that something do *not* happen! + setTimeout(openSecondNotification, 50); +} + +function openSecondNotification() { + isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); + let win = tab.linkedBrowser.contentWindow.wrappedJSObject; + notification = win.showNotification2(); + notification.addEventListener("show", onAlertShowing); +} + +function onTabSelect() { + gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); + is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL, + "Notification tab should be selected."); + + finish(); +}
--- a/browser/base/content/test/general/browser_scope.js +++ b/browser/base/content/test/general/browser_scope.js @@ -1,4 +1,11 @@ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null"); + function test() { ok(!!gBrowser, "gBrowser exists"); is(gBrowser, getBrowser(), "both ways of getting tabbrowser work"); }
--- a/browser/base/content/test/general/browser_tabs_owner.js +++ b/browser/base/content/test/general/browser_tabs_owner.js @@ -1,8 +1,22 @@ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function"); + +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function"); + function test() { gBrowser.addTab(); gBrowser.addTab(); gBrowser.addTab(); var tabs = gBrowser.tabs; var owner;
--- a/browser/base/content/test/general/browser_zbug569342.js +++ b/browser/base/content/test/general/browser_zbug569342.js @@ -1,12 +1,19 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed(""); + var gTab = null; function load(url, cb) { gTab = gBrowser.addTab(url); gBrowser.addEventListener("load", function (event) { if (event.target.location != url) return;
--- a/browser/base/content/test/general/file_dom_notifications.html +++ b/browser/base/content/test/general/file_dom_notifications.html @@ -1,23 +1,40 @@ -<html> -<head> -<script> -"use strict"; - -function showNotification() { - var options = { - dir: undefined, - lang: undefined, - body: "Test body", - tag: "Test tag", - icon: undefined, - }; - return new Notification("Test title", options); -} -</script> -</head> -<body> -<form id="notificationForm" onsubmit="showNotification();"> - <input type="submit" value="Show notification" id="submit"/> -</form> -</body> -</html> +<html> +<head> +<script> +"use strict"; + +function showNotification1() { + var options = { + dir: undefined, + lang: undefined, + body: "Test body", + tag: "Test tag", + icon: undefined, + }; + var n = new Notification("Test title", options); + n.addEventListener("click", function(event) { + event.preventDefault(); + dump("Should focus new window."); + newWindow.focus(); + }); + return n; +} + +function showNotification2() { + var options = { + dir: undefined, + lang: undefined, + body: "Test body", + tag: "Test tag", + icon: undefined, + }; + return new Notification("Test title", options); +} +</script> +</head> +<body> +<form id="notificationForm" onsubmit="showNotification();"> + <input type="submit" value="Show notification" id="submit"/> +</form> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/general/file_double_close_tab.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Test for bug 1050638 - clicking tab close button twice should close tab even in beforeunload case</title> + </head> + <body> + This page will block beforeunload. It should still be user-closable at all times. + <script> + window.onbeforeunload = function() { + return "stop"; + }; + </script> + </body> +</html>
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/plugins/blockPluginInfoURL.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000"> + <emItems> + </emItems> + <pluginItems> + <pluginItem blockID="p9999"> + <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" /> + <versionRange severity="2"></versionRange> + <infoURL>http://test.url.com/</infoURL> + </pluginItem> + </pluginItems> +</blocklist>
--- a/browser/base/content/test/plugins/browser.ini +++ b/browser/base/content/test/plugins/browser.ini @@ -4,16 +4,17 @@ # * Bug 921916 - no plugin events # * Bug XXXXX - no plugins in content processes ("Error: You cannot use the AddonManager in child processes!") # * Bug 866413 - PageInfo doesn't work in e10s [browser_pageInfo_plugins.js] # * Bug 921957 - remote webprogress doesn't supply originalURI attribute on the request object [browser_clearplugindata.js] skip-if = buildapp == "mulet" || e10s support-files = blockNoPlugins.xml blockPluginHard.xml + blockPluginInfoURL.xml blockPluginVulnerableNoUpdate.xml blockPluginVulnerableUpdatable.xml browser_clearplugindata.html browser_clearplugindata_noage.html head.js plugin_add_dynamically.html plugin_alternate_content.html plugin_big.html
--- a/browser/base/content/test/plugins/browser_pluginnotification.js +++ b/browser/base/content/test/plugins/browser_pluginnotification.js @@ -56,16 +56,19 @@ TabOpenListener.prototype = { function test() { waitForExplicitFinish(); SimpleTest.requestCompleteLog(); requestLongerTimeout(2); registerCleanupFunction(function() { clearAllPluginPermissions(); Services.prefs.clearUserPref("extensions.blocklist.suppressUI"); + return new Promise(resolve => { + setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", resolve); + }); }); Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true); setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY); setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in"); var newTab = gBrowser.addTab(); gBrowser.selectedTab = newTab; @@ -816,10 +819,51 @@ function test24d() { }, "Test 24d, plugin should be activated"); } function test25() { let notification = PopupNotifications.getNotification("click-to-play-plugins"); ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed"); ok(notification.dismissed, "Test 25: The notification should be dismissed by default"); + prepareTest26(); +} + +function prepareTest26() { + info("prepareTest26"); + let plugin = getTestPlugin(); + plugin.enabledState = Ci.nsIPluginTag.STATE_ENABLED; + setAndUpdateBlocklist(gHttpTestRoot + "blockPluginInfoURL.xml", + function() { + info("prepareTest26 callback"); + prepareTest(runAfterPluginBindingAttached(test26), gTestRoot + "plugin_test.html"); + }); +} + +// Tests a page with a blocked plugin in it and make sure the +// infoURL property from the blocklist file gets used. +function test26() { + info("test26 - Test infoURL"); + let notification = PopupNotifications.getNotification("click-to-play-plugins"); + + // Since the plugin notification is dismissed by default, reshow it. + notification.reshow(); + + let pluginNode = gTestBrowser.contentDocument.getElementById("test"); + ok(pluginNode, "Test 26, Found plugin in page"); + let objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent); + is(objLoadingContent.pluginFallbackType, + Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED, + "Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED"); + + const testUrl = "http://test.url.com/"; + + let doc = gTestBrowser.contentDocument; + let firstPanelChild = PopupNotifications.panel.firstChild; + + let infoLink = doc.getAnonymousElementByAttribute( + firstPanelChild, "anonid", "click-to-play-plugins-notification-link"); + + is(infoLink.href, testUrl, + "Test 26, the notification URL needs to match the infoURL from the blocklist file."); + finishTest(); }
--- a/browser/base/content/test/social/browser.ini +++ b/browser/base/content/test/social/browser.ini @@ -44,16 +44,17 @@ skip-if = e10s # Bug 915547 (social prov skip-if = e10s # Bug 915547 (social providers don't install) [browser_social_errorPage.js] [browser_social_flyout.js] skip-if = e10s # when we backed out bug 1047603, this test broke. [browser_social_isVisible.js] [browser_social_marks.js] skip-if = e10s # Bug 915547 (social providers don't install) [browser_social_multiprovider.js] +skip-if = e10s # Bug 1069162 - lots of orange [browser_social_multiworker.js] [browser_social_perwindowPB.js] [browser_social_sidebar.js] [browser_social_status.js] skip-if = e10s # Bug 915547 (social providers don't install) [browser_social_window.js] [browser_social_workercrash.js] skip-if = !crashreporter
--- a/browser/base/content/test/social/browser_social_activation.js +++ b/browser/base/content/test/social/browser_social_activation.js @@ -1,12 +1,20 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/////////////////// +// +// Whitelisting this test. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// +thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: Assert is null"); + + let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; let tabsToRemove = []; function removeAllProviders(callback) { // all the providers may have been added. function removeProviders() {
--- a/browser/components/customizableui/CustomizableUI.jsm +++ b/browser/components/customizableui/CustomizableUI.jsm @@ -32,16 +32,17 @@ XPCOMUtils.defineLazyServiceGetter(this, const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const kSpecialWidgetPfx = "customizableui-special-"; const kPrefCustomizationState = "browser.uiCustomization.state"; const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd"; const kPrefCustomizationDebug = "browser.uiCustomization.debug"; const kPrefDrawInTitlebar = "browser.tabs.drawInTitlebar"; +const kPrefDeveditionTheme = "browser.devedition.theme.enabled"; /** * The keys are the handlers that are fired when the event type (the value) * is fired on the subview. A widget that provides a subview has the option * of providing onViewShowing and onViewHiding event handlers. */ const kSubviewEvents = [ "ViewShowing", @@ -134,16 +135,17 @@ let gBuildWindows = new Map(); let gNewElementCount = 0; let gGroupWrapperCache = new Map(); let gSingleWrapperCache = new WeakMap(); let gListeners = new Set(); let gUIStateBeforeReset = { uiCustomizationState: null, drawInTitlebar: null, + gUIStateBeforeReset: null, }; let gModuleName = "[CustomizableUI]"; #include logging.js let CustomizableUIInternal = { initialize: function() { LOG("Initializing"); @@ -2294,23 +2296,25 @@ let CustomizableUIInternal = { this._rebuildRegisteredAreas(); gResetting = false; }, _resetUIState: function() { try { gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar); + gUIStateBeforeReset.deveditionTheme = Services.prefs.getBoolPref(kPrefDeveditionTheme); gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState); } catch(e) { } this._resetExtraToolbars(); Services.prefs.clearUserPref(kPrefCustomizationState); Services.prefs.clearUserPref(kPrefDrawInTitlebar); + Services.prefs.clearUserPref(kPrefDeveditionTheme); LOG("State reset"); // Reset placements to make restoring default placements possible. gPlacements = new Map(); gDirtyAreaCache = new Set(); gSeenWidgets = new Set(); // Clear the saved state to ensure that defaults will be used. gSavedState = null; @@ -2362,30 +2366,33 @@ let CustomizableUIInternal = { } }, /** * Undoes a previous reset, restoring the state of the UI to the state prior to the reset. */ undoReset: function() { if (gUIStateBeforeReset.uiCustomizationState == null || - gUIStateBeforeReset.drawInTitlebar == null) { + gUIStateBeforeReset.drawInTitlebar == null || + gUIStateBeforeReset.deveditionTheme == null) { return; } gUndoResetting = true; let uiCustomizationState = gUIStateBeforeReset.uiCustomizationState; let drawInTitlebar = gUIStateBeforeReset.drawInTitlebar; + let deveditionTheme = gUIStateBeforeReset.deveditionTheme; // Need to clear the previous state before setting the prefs // because pref observers may check if there is a previous UI state. this._clearPreviousUIState(); Services.prefs.setCharPref(kPrefCustomizationState, uiCustomizationState); Services.prefs.setBoolPref(kPrefDrawInTitlebar, drawInTitlebar); + Services.prefs.setBoolPref(kPrefDeveditionTheme, deveditionTheme); this.loadSavedState(); // If the user just customizes toolbar/titlebar visibility, gSavedState will be null // and we don't need to do anything else here: if (gSavedState) { for (let areaId of Object.keys(gSavedState.placements)) { let placements = gSavedState.placements[areaId]; gPlacements.set(areaId, placements); } @@ -2553,16 +2560,20 @@ let CustomizableUIInternal = { } } } if (Services.prefs.prefHasUserValue(kPrefDrawInTitlebar)) { LOG(kPrefDrawInTitlebar + " pref is non-default"); return false; } + if (Services.prefs.prefHasUserValue(kPrefDeveditionTheme)) { + LOG(kPrefDeveditionTheme + " pref is non-default"); + return false; + } return true; }, setToolbarVisibility: function(aToolbarId, aIsVisible) { // We only persist the attribute the first time. let isFirstChangedToolbar = true; for (let window of CustomizableUI.windows) { @@ -3253,17 +3264,18 @@ this.CustomizableUI = { /** * Can the last Restore Defaults operation be undone. * * @return A boolean stating whether an undo of the * Restore Defaults can be performed. */ get canUndoReset() { return gUIStateBeforeReset.uiCustomizationState != null || - gUIStateBeforeReset.drawInTitlebar != null; + gUIStateBeforeReset.drawInTitlebar != null || + gUIStateBeforeReset.deveditionTheme != null; }, /** * Get the placement of a widget. This is by far the best way to obtain * information about what the state of your widget is. The internals of * this call are cheap (no DOM necessary) and you will know where the user * has put your widget. *
--- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -918,17 +918,17 @@ const CustomizableWidgets = [ tooltiptext: "email-link-button.tooltiptext3", onCommand: function(aEvent) { let win = aEvent.view; win.MailIntegration.sendLinkForWindow(win.content); } }, { id: "loop-call-button", type: "custom", - label: "loop-call-button2.label", + label: "loop-call-button3.label", tooltiptext: "loop-call-button2.tooltiptext", defaultArea: CustomizableUI.AREA_NAVBAR, introducedInVersion: 1, onBuild: function(aDocument) { let node = aDocument.createElementNS(kNSXUL, "toolbarbutton"); node.setAttribute("id", this.id); node.classList.add("toolbarbutton-1"); node.classList.add("chromeclass-toolbar-additional");
--- a/browser/components/customizableui/CustomizeMode.jsm +++ b/browser/components/customizableui/CustomizeMode.jsm @@ -12,16 +12,18 @@ const kPrefCustomizationDebug = "browser const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation"; const kPaletteId = "customization-palette"; const kAboutURI = "about:customizing"; const kDragDataTypePrefix = "text/toolbarwrapper-id/"; const kPlaceholderClass = "panel-customization-placeholder"; const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck"; const kToolbarVisibilityBtn = "customization-toolbar-visibility-button"; const kDrawInTitlebarPref = "browser.tabs.drawInTitlebar"; +const kDeveditionThemePref = "browser.devedition.theme.enabled"; +const kDeveditionButtonPref = "browser.devedition.theme.showCustomizeButton"; const kMaxTransitionDurationMs = 2000; const kPanelItemContextMenu = "customizationPanelItemContextMenu"; const kPaletteItemContextMenu = "customizationPaletteItemContextMenu"; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/CustomizableUI.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -64,18 +66,21 @@ function CustomizeMode(aWindow) { this.tipPanel = this.document.getElementById("customization-tipPanel"); let lwthemeButton = this.document.getElementById("customization-lwtheme-button"); if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") { lwthemeButton.setAttribute("hidden", "true"); } #ifdef CAN_DRAW_IN_TITLEBAR this._updateTitlebarButton(); Services.prefs.addObserver(kDrawInTitlebarPref, this, false); +#endif + this._updateDevEditionThemeButton(); + Services.prefs.addObserver(kDeveditionButtonPref, this, false); + Services.prefs.addObserver(kDeveditionThemePref, this, false); this.window.addEventListener("unload", this); -#endif }; CustomizeMode.prototype = { _changed: false, _transitioning: false, window: null, document: null, // areas is used to cache the customizable areas when in customization mode. @@ -100,16 +105,18 @@ CustomizeMode.prototype = { get _handler() { return this.window.CustomizationHandler; }, uninit: function() { #ifdef CAN_DRAW_IN_TITLEBAR Services.prefs.removeObserver(kDrawInTitlebarPref, this); #endif + Services.prefs.removeObserver(kDeveditionButtonPref, this); + Services.prefs.removeObserver(kDeveditionThemePref, this); }, toggle: function() { if (this._handler.isEnteringCustomizeMode || this._handler.isExitingCustomizeMode) { this._wantToBeInCustomizeMode = !this._wantToBeInCustomizeMode; return; } if (this._customizing) { @@ -1442,32 +1449,31 @@ CustomizeMode.prototype = { case "mouseup": this._onMouseUp(aEvent); break; case "keypress": if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { this.exit(); } break; -#ifdef CAN_DRAW_IN_TITLEBAR case "unload": this.uninit(); break; -#endif } }, observe: function(aSubject, aTopic, aData) { switch (aTopic) { case "nsPref:changed": this._updateResetButton(); this._updateUndoResetButton(); #ifdef CAN_DRAW_IN_TITLEBAR this._updateTitlebarButton(); #endif + this._updateDevEditionThemeButton(); break; case "lightweight-theme-window-updated": if (aSubject == this.window) { aData = JSON.parse(aData); if (!aData) { this.removeLWTStyling(); } else { this.updateLWTStyling(aData); @@ -1493,16 +1499,39 @@ CustomizeMode.prototype = { }, toggleTitlebar: function(aShouldShowTitlebar) { // Drawing in the titlebar means not showing the titlebar, hence the negation: Services.prefs.setBoolPref(kDrawInTitlebarPref, !aShouldShowTitlebar); }, #endif + _updateDevEditionThemeButton: function() { + let button = this.document.getElementById("customization-devedition-theme-button"); + + let themeEnabled = Services.prefs.getBoolPref(kDeveditionThemePref); + if (themeEnabled) { + button.setAttribute("checked", "true"); + } else { + button.removeAttribute("checked"); + } + + let buttonVisible = Services.prefs.getBoolPref(kDeveditionButtonPref); + if (buttonVisible) { + button.removeAttribute("hidden"); + } else { + button.setAttribute("hidden", "true"); + } + }, + toggleDevEditionTheme: function() { + let button = this.document.getElementById("customization-devedition-theme-button"); + let preferenceValue = button.hasAttribute("checked"); + Services.prefs.setBoolPref(kDeveditionThemePref, preferenceValue); + }, + _onDragStart: function(aEvent) { __dumpDragData(aEvent); let item = aEvent.target; while (item && item.localName != "toolbarpaletteitem") { if (item.localName == "toolbar") { return; } item = item.parentNode; @@ -1871,18 +1900,24 @@ CustomizeMode.prototype = { if (!aEvent.dataTransfer.mozTypesAt(0)) { return; } let draggedItemId = aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0); let draggedWrapper = document.getElementById("wrapper-" + draggedItemId); - draggedWrapper.hidden = false; - draggedWrapper.removeAttribute("mousedown"); + + // DraggedWrapper might no longer available if a widget node is + // destroyed after starting (but before stopping) a drag. + if (draggedWrapper) { + draggedWrapper.hidden = false; + draggedWrapper.removeAttribute("mousedown"); + } + if (this._dragOverItem) { this._cancelDragActive(this._dragOverItem); this._dragOverItem = null; } this._updateToolbarCustomizationOutline(this.window); this._showPanelCustomizationPlaceholders(); DragPositionManager.stop(); },
--- a/browser/components/customizableui/content/customizeMode.inc.xul +++ b/browser/components/customizableui/content/customizeMode.inc.xul @@ -47,16 +47,24 @@ <toolbarbutton class="customization-lwtheme-menu-footeritem" label="&customizeMode.lwthemes.menuGetMore;" accesskey="&customizeMode.lwthemes.menuGetMore.accessKey;" tabindex="0" oncommand="gCustomizeMode.getMoreThemes(event);"/> </hbox> </panel> </button> + + <button id="customization-devedition-theme-button" + class="customizationmode-button" + hidden="true" + label="&customizeMode.deveditionTheme.label;" + oncommand="gCustomizeMode.toggleDevEditionTheme()" + type="checkbox" /> + <spacer id="customization-footer-spacer"/> <button id="customization-undo-reset-button" class="customizationmode-button" hidden="true" oncommand="gCustomizeMode.undoReset();" label="&undoCmd.label;"/> <button id="customization-reset-button" oncommand="gCustomizeMode.reset();"
--- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -183,17 +183,17 @@ <vbox class="panel-subview-body"> <hbox id="PanelUI-panic-timeframe"> <image id="PanelUI-panic-timeframe-icon" alt=""/> <vbox flex="1"> <hbox id="PanelUI-panic-header"> <image id="PanelUI-panic-timeframe-icon-small" alt=""/> <description id="PanelUI-panic-mainDesc" flex="1">&panicButton.view.mainTimeframeDesc;</description> </hbox> - <radiogroup id="PanelUI-panic-timeSpan" aria-labelledby="PanelUI-panic-mainDesc"> + <radiogroup id="PanelUI-panic-timeSpan" aria-labelledby="PanelUI-panic-mainDesc" closemenu="none"> <radio id="PanelUI-panic-5min" label="&panicButton.view.5min;" selected="true" value="5" class="subviewradio"/> <radio id="PanelUI-panic-2hr" label="&panicButton.view.2hr;" value="2" class="subviewradio"/> <radio id="PanelUI-panic-day" label="&panicButton.view.day;" value="6" class="subviewradio"/> </radiogroup> </vbox>
--- a/browser/components/customizableui/test/browser_970511_undo_restore_default.js +++ b/browser/components/customizableui/test/browser_970511_undo_restore_default.js @@ -96,12 +96,50 @@ add_task(function() { is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value"); is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked"); Services.prefs.clearUserPref(prefName); ok(CustomizableUI.inDefaultState, "In default state after pref cleared"); is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test"); }); +// Bug 1082108 - Restore Defaults should clear user pref for devedition theme +add_task(function() { + let prefName = "browser.devedition.theme.enabled"; + Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true); + let defaultValue = Services.prefs.getBoolPref(prefName); + let restoreDefaultsButton = document.getElementById("customization-reset-button"); + let deveditionThemeButton = document.getElementById("customization-devedition-theme-button"); + let undoResetButton = document.getElementById("customization-undo-reset-button"); + ok(CustomizableUI.inDefaultState, "Should be in default state at start of test"); + ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled when in default state"); + is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "Devedition theme button should reflect pref value"); + is(undoResetButton.hidden, true, "Undo reset button should be hidden at start of test"); + Services.prefs.setBoolPref(prefName, !defaultValue); + ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled when pref changed"); + is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "Devedition theme button should reflect changed pref value"); + ok(!CustomizableUI.inDefaultState, "With devedition theme flipped, no longer default"); + is(undoResetButton.hidden, true, "Undo reset button should be hidden after pref change"); + + yield gCustomizeMode.reset(); + ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled after reset"); + is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "devedition theme button should reflect default value after reset"); + is(Services.prefs.getBoolPref(prefName), defaultValue, "Reset should reset devedition.theme.enabled"); + ok(CustomizableUI.inDefaultState, "In default state after devedition theme reset"); + is(undoResetButton.hidden, false, "Undo reset button should be visible after reset"); + ok(!undoResetButton.disabled, "Undo reset button should be enabled after reset"); + + yield gCustomizeMode.undoReset(); + ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled after undo-reset"); + is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "devedition theme button should reflect undo-reset value"); + ok(!CustomizableUI.inDefaultState, "No longer in default state after undo"); + is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value"); + is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked"); + + Services.prefs.clearUserPref(prefName); + ok(CustomizableUI.inDefaultState, "In default state after pref cleared"); + is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test"); +}); + add_task(function asyncCleanup() { yield gCustomizeMode.reset(); yield endCustomizing(); });
--- a/browser/components/downloads/DownloadsCommon.jsm +++ b/browser/components/downloads/DownloadsCommon.jsm @@ -62,16 +62,18 @@ XPCOMUtils.defineLazyModuleGetter(this, XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", "resource:///modules/RecentWindow.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "DownloadsLogger", "resource:///modules/DownloadsLogger.jsm"); const nsIDM = Ci.nsIDownloadManager; const kDownloadsStringBundleUrl = "chrome://browser/locale/downloads/downloads.properties"; @@ -138,16 +140,23 @@ PrefObserver.register({ //////////////////////////////////////////////////////////////////////////////// //// DownloadsCommon /** * This object is exposed directly to the consumers of this JavaScript module, * and provides shared methods for all the instances of the user interface. */ this.DownloadsCommon = { + /** + * Constants with the different types of unblock messages. + */ + BLOCK_VERDICT_MALWARE: "Malware", + BLOCK_VERDICT_POTENTIALLY_UNWANTED: "PotentiallyUnwanted", + BLOCK_VERDICT_UNCOMMON: "Uncommon", + log: function DC_log(...aMessageArgs) { delete this.log; this.log = function DC_log(...aMessageArgs) { if (!PrefObserver.debug) { return; } DownloadsLogger.log.apply(DownloadsLogger, aMessageArgs); } @@ -506,17 +515,79 @@ this.DownloadsCommon = { // If launch also fails (probably because it's not implemented), let // the OS handler try to open the parent. Cc["@mozilla.org/uriloader/external-protocol-service;1"] .getService(Ci.nsIExternalProtocolService) .loadUrl(NetUtil.newURI(parent)); } } } - } + }, + + /** + * Displays an alert message box which asks the user if they want to + * unblock the downloaded file or not. + * + * @param aType + * The type of malware the downloaded file contains. + * @param aOwnerWindow + * The window with which this action is associated. + * + * @return True to unblock the file, false to keep the user safe and + * cancel the operation. + */ + confirmUnblockDownload: Task.async(function* DP_confirmUnblockDownload(aType, aOwnerWindow) { + let s = DownloadsCommon.strings; + let title = s.unblockHeader; + let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) + + (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1); + let type = ""; + let message = s.unblockTip; + let okButton = s.unblockButtonContinue; + let cancelButton = s.unblockButtonCancel; + + switch (aType) { + case this.BLOCK_VERDICT_MALWARE: + type = s.unblockTypeMalware; + break; + case this.BLOCK_VERDICT_POTENTIALLY_UNWANTED: + type = s.unblockTypePotentiallyUnwanted; + break; + case this.BLOCK_VERDICT_UNCOMMON: + type = s.unblockTypeUncommon; + break; + } + + if (type) { + message = type + "\n\n" + message; + } + + Services.ww.registerNotification(function onOpen(subj, topic) { + if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) { + // Make sure to listen for "DOMContentLoaded" because it is fired + // before the "load" event. + subj.addEventListener("DOMContentLoaded", function onLoad() { + subj.removeEventListener("DOMContentLoaded", onLoad); + if (subj.document.documentURI == + "chrome://global/content/commonDialog.xul") { + Services.ww.unregisterNotification(onOpen); + let dialog = subj.document.getElementById("commonDialog"); + if (dialog) { + // Change the dialog to use a warning icon. + dialog.classList.add("alert-dialog"); + } + } + }); + } + }); + + let rv = Services.prompt.confirmEx(aOwnerWindow, title, message, buttonFlags, + cancelButton, okButton, null, null, {}); + return (rv == 1); + }), }; /** * Returns true if we are executing on Windows Vista or a later version. */ XPCOMUtils.defineLazyGetter(DownloadsCommon, "isWinVistaOrHigher", function () { let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS; if (os != "WINNT") {
--- a/browser/components/downloads/test/browser/browser.ini +++ b/browser/components/downloads/test/browser/browser.ini @@ -2,8 +2,9 @@ support-files = head.js [browser_basic_functionality.js] skip-if = buildapp == "mulet" || e10s [browser_first_download_panel.js] skip-if = os == "linux" # Bug 949434 [browser_overflow_anchor.js] skip-if = os == "linux" # Bug 952422 +[browser_confirm_unblock_download.js]
--- a/browser/components/downloads/test/browser/browser_basic_functionality.js +++ b/browser/components/downloads/test/browser/browser_basic_functionality.js @@ -1,57 +1,55 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +registerCleanupFunction(function*() { + yield task_resetState(); +}); + /** * Make sure the downloads panel can display items in the right order and * contains the expected data. */ -function test_task() -{ +add_task(function* test_basic_functionality() { // Display one of each download state. const DownloadData = [ { state: nsIDM.DOWNLOAD_NOTSTARTED }, { state: nsIDM.DOWNLOAD_PAUSED }, { state: nsIDM.DOWNLOAD_FINISHED }, { state: nsIDM.DOWNLOAD_FAILED }, { state: nsIDM.DOWNLOAD_CANCELED }, ]; - try { - // Wait for focus first - yield promiseFocus(); + // Wait for focus first + yield promiseFocus(); - // Ensure that state is reset in case previous tests didn't finish. - yield task_resetState(); + // Ensure that state is reset in case previous tests didn't finish. + yield task_resetState(); - // For testing purposes, show all the download items at once. - var originalCountLimit = DownloadsView.kItemCountLimit; - DownloadsView.kItemCountLimit = DownloadData.length; - registerCleanupFunction(function () { - DownloadsView.kItemCountLimit = originalCountLimit; - }); + // For testing purposes, show all the download items at once. + var originalCountLimit = DownloadsView.kItemCountLimit; + DownloadsView.kItemCountLimit = DownloadData.length; + registerCleanupFunction(function () { + DownloadsView.kItemCountLimit = originalCountLimit; + }); - // Populate the downloads database with the data required by this test. - yield task_addDownloads(DownloadData); + // Populate the downloads database with the data required by this test. + yield task_addDownloads(DownloadData); - // Open the user interface and wait for data to be fully loaded. - yield task_openPanel(); + // Open the user interface and wait for data to be fully loaded. + yield task_openPanel(); - // Test item data and count. This also tests the ordering of the display. - let richlistbox = document.getElementById("downloadsListBox"); -/* disabled for failing intermittently (bug 767828) + // Test item data and count. This also tests the ordering of the display. + let richlistbox = document.getElementById("downloadsListBox"); + /* disabled for failing intermittently (bug 767828) is(richlistbox.children.length, DownloadData.length, "There is the correct number of richlistitems"); -*/ - let itemCount = richlistbox.children.length; - for (let i = 0; i < itemCount; i++) { - let element = richlistbox.children[itemCount - i - 1]; - let dataItem = new DownloadsViewItemController(element).dataItem; - is(dataItem.state, DownloadData[i].state, "Download states match up"); - } - } finally { - // Clean up when the test finishes. - yield task_resetState(); + */ + let itemCount = richlistbox.children.length; + for (let i = 0; i < itemCount; i++) { + let element = richlistbox.children[itemCount - i - 1]; + let dataItem = new DownloadsViewItemController(element).dataItem; + is(dataItem.state, DownloadData[i].state, "Download states match up"); } -} +});
new file mode 100644 --- /dev/null +++ b/browser/components/downloads/test/browser/browser_confirm_unblock_download.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests the dialog which allows the user to unblock a downloaded file. + +registerCleanupFunction(() => {}); + +function addDialogOpenObserver(buttonAction) { + Services.ww.registerNotification(function onOpen(subj, topic, data) { + if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) { + // The test listens for the "load" event which guarantees that the alert + // class has already been added (it is added when "DOMContentLoaded" is + // fired). + subj.addEventListener("load", function onLoad() { + subj.removeEventListener("load", onLoad); + if (subj.document.documentURI == + "chrome://global/content/commonDialog.xul") { + Services.ww.unregisterNotification(onOpen); + + let dialog = subj.document.getElementById("commonDialog"); + ok(dialog.classList.contains("alert-dialog"), + "The dialog element should contain an alert class."); + + let doc = subj.document.documentElement; + doc.getButton(buttonAction).click(); + } + }); + } + }); +} + +add_task(function* test_confirm_unblock_dialog_unblock() { + addDialogOpenObserver("cancel"); + let result = yield DownloadsCommon.confirmUnblockDownload(DownloadsCommon.UNBLOCK_MALWARE, + window); + ok(result, "Should return true when the user clicks on `Unblock` button."); +}); + +add_task(function* test_confirm_unblock_dialog_keep_safe() { + addDialogOpenObserver("accept"); + let result = yield DownloadsCommon.confirmUnblockDownload(DownloadsCommon.UNBLOCK_MALWARE, + window); + ok(!result, "Should return false when the user clicks on `Keep me safe` button."); +});
--- a/browser/components/downloads/test/browser/browser_first_download_panel.js +++ b/browser/components/downloads/test/browser/browser_first_download_panel.js @@ -3,63 +3,55 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Make sure the downloads panel only opens automatically on the first * download it notices. All subsequent downloads, even across sessions, should * not open the panel automatically. */ -function test_task() -{ +add_task(function* test_first_download_panel() { // Clear the download panel has shown preference first as this test is used to // verify this preference's behaviour. - let oldPrefValue = true; - try { - oldPrefValue = Services.prefs.getBoolPref("browser.download.panel.shown"); - } catch(ex) { } + let oldPrefValue = Services.prefs.getBoolPref("browser.download.panel.shown"); Services.prefs.setBoolPref("browser.download.panel.shown", false); - try { - // Ensure that state is reset in case previous tests didn't finish. + registerCleanupFunction(function*() { + // Clean up when the test finishes. yield task_resetState(); - // With this set to false, we should automatically open the panel the first - // time a download is started. - DownloadsCommon.getData(window).panelHasShownBefore = false; - - let promise = promisePanelOpened(); - DownloadsCommon.getData(window)._notifyDownloadEvent("start"); - yield promise; - - // If we got here, that means the panel opened. - DownloadsPanel.hidePanel(); - - ok(DownloadsCommon.getData(window).panelHasShownBefore, - "Should have recorded that the panel was opened on a download.") - - // Next, make sure that if we start another download, we don't open the - // panel automatically. - let originalOnPopupShown = DownloadsPanel.onPopupShown; - DownloadsPanel.onPopupShown = function () { - originalOnPopupShown.apply(this, arguments); - ok(false, "Should not have opened the downloads panel."); - }; - - try { - DownloadsCommon.getData(window)._notifyDownloadEvent("start"); - - // Wait 2 seconds to ensure that the panel does not open. - let deferTimeout = Promise.defer(); - setTimeout(deferTimeout.resolve, 2000); - yield deferTimeout.promise; - } finally { - DownloadsPanel.onPopupShown = originalOnPopupShown; - } - } finally { - // Clean up when the test finishes. - yield task_resetState(); // Set the preference instead of clearing it afterwards to ensure the // right value is used no matter what the default was. This ensures the // panel doesn't appear and affect other tests. Services.prefs.setBoolPref("browser.download.panel.shown", oldPrefValue); - } -} + }); + + // Ensure that state is reset in case previous tests didn't finish. + yield task_resetState(); + + // With this set to false, we should automatically open the panel the first + // time a download is started. + DownloadsCommon.getData(window).panelHasShownBefore = false; + + let promise = promisePanelOpened(); + DownloadsCommon.getData(window)._notifyDownloadEvent("start"); + yield promise; + + // If we got here, that means the panel opened. + DownloadsPanel.hidePanel(); + + ok(DownloadsCommon.getData(window).panelHasShownBefore, + "Should have recorded that the panel was opened on a download.") + + // Next, make sure that if we start another download, we don't open the + // panel automatically. + let originalOnPopupShown = DownloadsPanel.onPopupShown; + DownloadsPanel.onPopupShown = function () { + originalOnPopupShown.apply(this, arguments); + ok(false, "Should not have opened the downloads panel."); + }; + + DownloadsCommon.getData(window)._notifyDownloadEvent("start"); + + // Wait 2 seconds to ensure that the panel does not open. + yield new Promise(resolve => setTimeout(resolve, 2000)); + DownloadsPanel.onPopupShown = originalOnPopupShown; +});
--- a/browser/components/downloads/test/browser/browser_overflow_anchor.js +++ b/browser/components/downloads/test/browser/browser_overflow_anchor.js @@ -1,74 +1,74 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ +registerCleanupFunction(function*() { + // Clean up when the test finishes. + yield task_resetState(); +}); + /** * Make sure the downloads button and indicator overflows into the nav-bar * chevron properly, and then when those buttons are clicked in the overflow * panel that the downloads panel anchors to the chevron. */ -function test_task() { - try { - // Ensure that state is reset in case previous tests didn't finish. - yield task_resetState(); +add_task(function* test_overflow_anchor() { + // Ensure that state is reset in case previous tests didn't finish. + yield task_resetState(); - // Record the original width of the window so we can put it back when - // this test finishes. - let oldWidth = window.outerWidth; + // Record the original width of the window so we can put it back when + // this test finishes. + let oldWidth = window.outerWidth; - // The downloads button should not be overflowed to begin with. - let button = CustomizableUI.getWidget("downloads-button") - .forWindow(window); - ok(!button.overflowed, "Downloads button should not be overflowed."); + // The downloads button should not be overflowed to begin with. + let button = CustomizableUI.getWidget("downloads-button") + .forWindow(window); + ok(!button.overflowed, "Downloads button should not be overflowed."); - // Hack - we lock the size of the default flex-y items in the nav-bar, - // namely, the URL and search inputs. That way we can resize the - // window without worrying about them flexing. - const kFlexyItems = ["urlbar-container", "search-container"]; - registerCleanupFunction(() => unlockWidth(kFlexyItems)); - lockWidth(kFlexyItems); + // Hack - we lock the size of the default flex-y items in the nav-bar, + // namely, the URL and search inputs. That way we can resize the + // window without worrying about them flexing. + const kFlexyItems = ["urlbar-container", "search-container"]; + registerCleanupFunction(() => unlockWidth(kFlexyItems)); + lockWidth(kFlexyItems); - // Resize the window to half of its original size. That should - // be enough to overflow the downloads button. - window.resizeTo(oldWidth / 2, window.outerHeight); - yield waitForOverflowed(button, true); + // Resize the window to half of its original size. That should + // be enough to overflow the downloads button. + window.resizeTo(oldWidth / 2, window.outerHeight); + yield waitForOverflowed(button, true); - let promise = promisePanelOpened(); - button.node.doCommand(); - yield promise; - - let panel = DownloadsPanel.panel; - let chevron = document.getElementById("nav-bar-overflow-button"); - is(panel.anchorNode, chevron, "Panel should be anchored to the chevron."); + let promise = promisePanelOpened(); + button.node.doCommand(); + yield promise; - DownloadsPanel.hidePanel(); + let panel = DownloadsPanel.panel; + let chevron = document.getElementById("nav-bar-overflow-button"); + is(panel.anchorNode, chevron, "Panel should be anchored to the chevron."); - // Unlock the widths on the flex-y items. - unlockWidth(kFlexyItems); + DownloadsPanel.hidePanel(); - // Put the window back to its original dimensions. - window.resizeTo(oldWidth, window.outerHeight); + // Unlock the widths on the flex-y items. + unlockWidth(kFlexyItems); - // The downloads button should eventually be un-overflowed. - yield waitForOverflowed(button, false); + // Put the window back to its original dimensions. + window.resizeTo(oldWidth, window.outerHeight); - // Now try opening the panel again. - promise = promisePanelOpened(); - button.node.doCommand(); - yield promise; + // The downloads button should eventually be un-overflowed. + yield waitForOverflowed(button, false); - is(panel.anchorNode.id, "downloads-indicator-anchor"); + // Now try opening the panel again. + promise = promisePanelOpened(); + button.node.doCommand(); + yield promise; - DownloadsPanel.hidePanel(); - } finally { - // Clean up when the test finishes. - yield task_resetState(); - } -} + is(panel.anchorNode.id, "downloads-indicator-anchor"); + + DownloadsPanel.hidePanel(); +}); /** * For some node IDs, finds the nodes and sets their min-width's to their * current width, preventing them from flex-shrinking. * * @param aItemIDs an array of item IDs to set min-width on. */ function lockWidth(aItemIDs) {
--- a/browser/components/downloads/test/browser/head.js +++ b/browser/components/downloads/test/browser/head.js @@ -24,25 +24,16 @@ const nsIDM = Ci.nsIDownloadManager; let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]); gTestTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); registerCleanupFunction(function () { gTestTargetFile.remove(false); }); //////////////////////////////////////////////////////////////////////////////// -//// Infrastructure - -function test() -{ - waitForExplicitFinish(); - Task.spawn(test_task).then(null, ex => ok(false, ex)).then(finish); -} - -//////////////////////////////////////////////////////////////////////////////// //// Asynchronous support subroutines function promiseFocus() { let deferred = Promise.defer(); waitForFocus(deferred.resolve); return deferred.promise; }
--- a/browser/components/feeds/FeedWriter.js +++ b/browser/components/feeds/FeedWriter.js @@ -853,17 +853,16 @@ FeedWriter.prototype = { * Application" item is being selected with the keyboard. We do this * by ignoring command events while the dropdown is closed (user * arrowing through the combobox), but handling them while the * combobox dropdown is open (user pressed enter when an item was * selected). If we don't show the filepicker here, it will be shown * when clicking "Subscribe Now". */ var popupbox = this._handlersMenuList.firstChild.boxObject; - popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject); if (popupbox.popupState == "hiding") { this._chooseClientApp(function(aResult) { if (!aResult) { // Select the (per-prefs) selected handler if no application // was selected this._setSelectedHandler(this._getFeedType()); } }.bind(this));
--- a/browser/components/loop/GoogleImporter.jsm +++ b/browser/components/loop/GoogleImporter.jsm @@ -446,17 +446,17 @@ this.GoogleImporter.prototype = { // Process telephone numbers. let phoneNodes = entry.getElementsByTagNameNS(kNS_GD, "phoneNumber"); if (phoneNodes.length) { contact.tel = []; for (let [,phoneNode] of Iterator(phoneNodes)) { contact.tel.push({ pref: (phoneNode.getAttribute("primary") == "true"), type: [getFieldType(phoneNode)], - value: phoneNode.firstChild.nodeValue + value: phoneNode.getAttribute("uri").replace("tel:", "") }); } } let orgNodes = entry.getElementsByTagNameNS(kNS_GD, "organization"); if (orgNodes.length) { contact.org = []; contact.jobTitle = []; @@ -496,17 +496,17 @@ this.GoogleImporter.prototype = { try { email = getPreferred(contact); } catch (ex) {} if (email) { contact.name = [email.value]; } else { let tel; try { - tel = getPreferred(contact, "phone"); + tel = getPreferred(contact, "tel"); } catch (ex) {} if (tel) { contact.name = [tel.value]; } } } } }
--- a/browser/components/loop/MozLoopAPI.jsm +++ b/browser/components/loop/MozLoopAPI.jsm @@ -5,18 +5,21 @@ "use strict"; const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://services-common/utils.js"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/loop/MozLoopService.jsm"); -Cu.import("resource:///modules/loop/LoopContacts.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts", + "resource:///modules/loop/LoopContacts.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage", + "resource:///modules/loop/LoopStorage.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose", "resource://gre/modules/MozSocialAPI.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); XPCOMUtils.defineLazyGetter(this, "appInfo", function() { return Cc["@mozilla.org/xre/app-info;1"] .getService(Ci.nsIXULAppInfo) .QueryInterface(Ci.nsIXULRuntime); @@ -35,17 +38,27 @@ this.EXPORTED_SYMBOLS = ["injectLoopAPI" * object. * * @param {Error} error Error object to copy * @param {nsIDOMWindow} targetWindow The content window to attach the API */ const cloneErrorObject = function(error, targetWindow) { let obj = new targetWindow.Error(); for (let prop of Object.getOwnPropertyNames(error)) { - obj[prop] = String(error[prop]); + let value = error[prop]; + if (typeof value != "string" && typeof value != "number") { + value = String(value); + } + + Object.defineProperty(Cu.waiveXrays(obj), prop, { + configurable: false, + enumerable: true, + value: value, + writable: false + }); } return obj; }; /** * Makes an object or value available to an unprivileged target window. * * Primitives are returned as they are, while objects are cloned into the @@ -216,16 +229,22 @@ function injectLoopAPI(targetWindow) { * @returns {Object} The contacts API object */ contacts: { enumerable: true, get: function() { if (contactsAPI) { return contactsAPI; } + + // Make a database switch when a userProfile is active already. + let profile = MozLoopService.userProfile; + if (profile) { + LoopStorage.switchDatabase(profile.uid); + } return contactsAPI = injectObjectAPI(LoopContacts, targetWindow); } }, /** * Import a list of (new) contacts from an external data source. * * @param {Object} options Property bag of options for the importer
--- a/browser/components/loop/MozLoopService.jsm +++ b/browser/components/loop/MozLoopService.jsm @@ -1600,21 +1600,31 @@ this.MozLoopService = { // clearError calls notifyStatusChanged so should be done last when the // state is clean. MozLoopServiceInternal.clearError("registration"); MozLoopServiceInternal.clearError("login"); MozLoopServiceInternal.clearError("profile"); }), - openFxASettings: function() { - let url = new URL("/settings", gFxAOAuthClient.parameters.content_uri); - let win = Services.wm.getMostRecentWindow("navigator:browser"); - win.switchToTabHavingURI(url.toString(), true); - }, + openFxASettings: Task.async(function() { + try { + let fxAOAuthClient = yield MozLoopServiceInternal.promiseFxAOAuthClient(); + if (!fxAOAuthClient) { + log.error("Could not get the OAuth client"); + return; + } + + let url = new URL("/settings", fxAOAuthClient.parameters.content_uri); + let win = Services.wm.getMostRecentWindow("navigator:browser"); + win.switchToTabHavingURI(url.toString(), true); + } catch (ex) { + log.error("Error opening FxA settings", ex); + } + }), /** * Performs a hawk based request to the loop server. * * @param {LOOP_SESSION_TYPE} sessionType The type of session to use for the request. * One of the LOOP_SESSION_TYPE members. * @param {String} path The path to make the request to. * @param {String} method The request method, e.g. 'POST', 'GET'.
--- a/browser/components/loop/content/conversation.html +++ b/browser/components/loop/content/conversation.html @@ -15,30 +15,32 @@ <div id="messages"></div> <div id="main"></div> <script type="text/javascript" src="loop/libs/l10n.js"></script> <script type="text/javascript" src="loop/js/otconfig.js"></script> <script type="text/javascript" src="loop/libs/sdk.js"></script> - <script type="text/javascript" src="loop/shared/libs/react-0.11.1.js"></script> + <script type="text/javascript" src="loop/shared/libs/react-0.11.2.js"></script> <script type="text/javascript" src="loop/shared/libs/jquery-2.1.0.js"></script> <script type="text/javascript" src="loop/shared/libs/lodash-2.4.1.js"></script> <script type="text/javascript" src="loop/shared/libs/backbone-1.1.2.js"></script> <script type="text/javascript" src="loop/shared/js/utils.js"></script> <script type="text/javascript" src="loop/shared/js/models.js"></script> <script type="text/javascript" src="loop/shared/js/mixins.js"></script> <script type="text/javascript" src="loop/shared/js/views.js"></script> <script type="text/javascript" src="loop/shared/js/feedbackApiClient.js"></script> <script type="text/javascript" src="loop/shared/js/actions.js"></script> <script type="text/javascript" src="loop/shared/js/validate.js"></script> <script type="text/javascript" src="loop/shared/js/dispatcher.js"></script> <script type="text/javascript" src="loop/shared/js/otSdkDriver.js"></script> <script type="text/javascript" src="loop/shared/js/conversationStore.js"></script> + <script type="text/javascript" src="loop/shared/js/localRoomStore.js"></script> <script type="text/javascript" src="loop/js/conversationViews.js"></script> <script type="text/javascript" src="loop/shared/js/websocket.js"></script> <script type="text/javascript" src="loop/js/client.js"></script> <script type="text/javascript" src="loop/js/conversationViews.js"></script> + <script type="text/javascript" src="loop/js/roomViews.js"></script> <script type="text/javascript" src="loop/js/conversation.js"></script> </body> </html>
--- a/browser/components/loop/content/js/conversation.js +++ b/browser/components/loop/content/js/conversation.js @@ -9,17 +9,21 @@ var loop = loop || {}; loop.conversation = (function(mozL10n) { "use strict"; var sharedViews = loop.shared.views; var sharedMixins = loop.shared.mixins; var sharedModels = loop.shared.models; + var sharedActions = loop.shared.actions; + var OutgoingConversationView = loop.conversationViews.OutgoingConversationView; + var CallIdentifierView = loop.conversationViews.CallIdentifierView; + var EmptyRoomView = loop.roomViews.EmptyRoomView; var IncomingCallView = React.createClass({displayName: 'IncomingCallView', mixins: [sharedMixins.DropdownMenuMixin], propTypes: { model: React.PropTypes.object.isRequired, video: React.PropTypes.bool.isRequired }, @@ -89,19 +93,24 @@ loop.conversation = (function(mozL10n) { render: function() { /* jshint ignore:start */ var dropdownMenuClassesDecline = React.addons.classSet({ "native-dropdown-menu": true, "conversation-window-dropdown": true, "visually-hidden": !this.state.showMenu }); + return ( React.DOM.div({className: "call-window"}, - React.DOM.h2(null, mozL10n.get("incoming_call_title2")), + CallIdentifierView({video: this.props.video, + peerIdentifier: this.props.model.getCallIdentifier(), + urlCreationDate: this.props.model.get("urlCreationDate"), + showIcons: true}), + React.DOM.div({className: "btn-group call-action-group"}, React.DOM.div({className: "fx-embedded-call-button-spacer"}), React.DOM.div({className: "btn-chevron-menu-group"}, React.DOM.div({className: "btn-group-chevron"}, React.DOM.div({className: "btn-group"}, @@ -224,18 +233,17 @@ loop.conversation = (function(mozL10n) { return ( IncomingCallView({ model: this.props.conversation, video: this.props.conversation.hasVideoStream("incoming")} ) ); } case "connected": { - // XXX This should be the caller id (bug 1020449) - document.title = mozL10n.get("incoming_call_title2"); + document.title = this.props.conversation.getCallIdentifier(); var callType = this.props.conversation.get("selectedCallType"); return ( sharedViews.ConversationView({ initiate: true, sdk: this.props.sdk, model: this.props.conversation, @@ -381,17 +389,18 @@ loop.conversation = (function(mozL10n) { * @param {Object} progressData The progress data from the websocket. * @param {String} previousState The previous state from the websocket. */ _handleWebSocketProgress: function(progressData, previousState) { // We only care about the terminated state at the moment. if (progressData.state !== "terminated") return; - if (progressData.reason === "cancel") { + if (progressData.reason === "cancel" || + progressData.reason === "closed") { this._abortIncomingCall(); return; } if (progressData.reason === "timeout" && (previousState === "init" || previousState === "alerting")) { this._abortIncomingCall(); } @@ -469,40 +478,52 @@ loop.conversation = (function(mozL10n) { console.error("Failed initiating the call session."); }, }); /** * Master controller view for handling if incoming or outgoing calls are * in progress, and hence, which view to display. */ - var ConversationControllerView = React.createClass({displayName: 'ConversationControllerView', + var AppControllerView = React.createClass({displayName: 'AppControllerView', propTypes: { // XXX Old types required for incoming call view. client: React.PropTypes.instanceOf(loop.Client).isRequired, conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel) .isRequired, sdk: React.PropTypes.object.isRequired, // XXX New types for OutgoingConversationView store: React.PropTypes.instanceOf(loop.store.ConversationStore).isRequired, - dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired + dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, + + // if not passed, this is not a room view + localRoomStore: React.PropTypes.instanceOf(loop.store.LocalRoomStore) }, getInitialState: function() { return this.props.store.attributes; }, componentWillMount: function() { this.props.store.on("change:outgoing", function() { this.setState(this.props.store.attributes); }, this); }, render: function() { + if (this.props.localRoomStore) { + return ( + EmptyRoomView({ + mozLoop: navigator.mozLoop, + localRoomStore: this.props.localRoomStore} + ) + ); + } + // Don't display anything, until we know what type of call we are. if (this.state.outgoing === undefined) { return null; } if (this.state.outgoing) { return (OutgoingConversationView({ store: this.props.store, @@ -558,53 +579,72 @@ loop.conversation = (function(mozL10n) { {sdk: window.OT} // Model dependencies ); // Obtain the callId and pass it through var helper = new loop.shared.utils.Helper(); var locationHash = helper.locationHash(); var callId; var outgoing; + var localRoomStore; - var hash = locationHash.match(/\#incoming\/(.*)/); + // XXX removeMe, along with noisy comment at the beginning of + // conversation_test.js "when locationHash begins with #room". + if (navigator.mozLoop.getLoopBoolPref("test.alwaysUseRooms")) { + locationHash = "#room/32"; + } + + var hash = locationHash.match(/#incoming\/(.*)/); if (hash) { callId = hash[1]; outgoing = false; + } else if (hash = locationHash.match(/#room\/(.*)/)) { + localRoomStore = new loop.store.LocalRoomStore({ + dispatcher: dispatcher, + mozLoop: navigator.mozLoop + }); } else { - hash = locationHash.match(/\#outgoing\/(.*)/); + hash = locationHash.match(/#outgoing\/(.*)/); if (hash) { callId = hash[1]; outgoing = true; } } conversation.set({callId: callId}); window.addEventListener("unload", function(event) { // Handle direct close of dialog box via [x] control. navigator.mozLoop.releaseCallData(callId); }); document.body.classList.add(loop.shared.utils.getTargetPlatform()); - React.renderComponent(ConversationControllerView({ + React.renderComponent(AppControllerView({ + localRoomStore: localRoomStore, store: conversationStore, client: client, conversation: conversation, dispatcher: dispatcher, sdk: window.OT} ), document.querySelector('#main')); + if (localRoomStore) { + dispatcher.dispatch( + new sharedActions.SetupEmptyRoom({localRoomId: hash[1]})); + return; + } + dispatcher.dispatch(new loop.shared.actions.GatherCallData({ callId: callId, outgoing: outgoing })); } return { - ConversationControllerView: ConversationControllerView, + AppControllerView: AppControllerView, IncomingConversationView: IncomingConversationView, IncomingCallView: IncomingCallView, init: init }; })(document.mozL10n); document.addEventListener('DOMContentLoaded', loop.conversation.init);
--- a/browser/components/loop/content/js/conversation.jsx +++ b/browser/components/loop/content/js/conversation.jsx @@ -9,17 +9,21 @@ var loop = loop || {}; loop.conversation = (function(mozL10n) { "use strict"; var sharedViews = loop.shared.views; var sharedMixins = loop.shared.mixins; var sharedModels = loop.shared.models; + var sharedActions = loop.shared.actions; + var OutgoingConversationView = loop.conversationViews.OutgoingConversationView; + var CallIdentifierView = loop.conversationViews.CallIdentifierView; + var EmptyRoomView = loop.roomViews.EmptyRoomView; var IncomingCallView = React.createClass({ mixins: [sharedMixins.DropdownMenuMixin], propTypes: { model: React.PropTypes.object.isRequired, video: React.PropTypes.bool.isRequired }, @@ -89,19 +93,24 @@ loop.conversation = (function(mozL10n) { render: function() { /* jshint ignore:start */ var dropdownMenuClassesDecline = React.addons.classSet({ "native-dropdown-menu": true, "conversation-window-dropdown": true, "visually-hidden": !this.state.showMenu }); + return ( <div className="call-window"> - <h2>{mozL10n.get("incoming_call_title2")}</h2> + <CallIdentifierView video={this.props.video} + peerIdentifier={this.props.model.getCallIdentifier()} + urlCreationDate={this.props.model.get("urlCreationDate")} + showIcons={true} /> + <div className="btn-group call-action-group"> <div className="fx-embedded-call-button-spacer"></div> <div className="btn-chevron-menu-group"> <div className="btn-group-chevron"> <div className="btn-group"> @@ -224,18 +233,17 @@ loop.conversation = (function(mozL10n) { return ( <IncomingCallView model={this.props.conversation} video={this.props.conversation.hasVideoStream("incoming")} /> ); } case "connected": { - // XXX This should be the caller id (bug 1020449) - document.title = mozL10n.get("incoming_call_title2"); + document.title = this.props.conversation.getCallIdentifier(); var callType = this.props.conversation.get("selectedCallType"); return ( <sharedViews.ConversationView initiate={true} sdk={this.props.sdk} model={this.props.conversation} @@ -381,17 +389,18 @@ loop.conversation = (function(mozL10n) { * @param {Object} progressData The progress data from the websocket. * @param {String} previousState The previous state from the websocket. */ _handleWebSocketProgress: function(progressData, previousState) { // We only care about the terminated state at the moment. if (progressData.state !== "terminated") return; - if (progressData.reason === "cancel") { + if (progressData.reason === "cancel" || + progressData.reason === "closed") { this._abortIncomingCall(); return; } if (progressData.reason === "timeout" && (previousState === "init" || previousState === "alerting")) { this._abortIncomingCall(); } @@ -469,40 +478,52 @@ loop.conversation = (function(mozL10n) { console.error("Failed initiating the call session."); }, }); /** * Master controller view for handling if incoming or outgoing calls are * in progress, and hence, which view to display. */ - var ConversationControllerView = React.createClass({ + var AppControllerView = React.createClass({ propTypes: { // XXX Old types required for incoming call view. client: React.PropTypes.instanceOf(loop.Client).isRequired, conversation: React.PropTypes.instanceOf(sharedModels.ConversationModel) .isRequired, sdk: React.PropTypes.object.isRequired, // XXX New types for OutgoingConversationView store: React.PropTypes.instanceOf(loop.store.ConversationStore).isRequired, - dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired + dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, + + // if not passed, this is not a room view + localRoomStore: React.PropTypes.instanceOf(loop.store.LocalRoomStore) }, getInitialState: function() { return this.props.store.attributes; }, componentWillMount: function() { this.props.store.on("change:outgoing", function() { this.setState(this.props.store.attributes); }, this); }, render: function() { + if (this.props.localRoomStore) { + return ( + <EmptyRoomView + mozLoop={navigator.mozLoop} + localRoomStore={this.props.localRoomStore} + /> + ); + } + // Don't display anything, until we know what type of call we are. if (this.state.outgoing === undefined) { return null; } if (this.state.outgoing) { return (<OutgoingConversationView store={this.props.store} @@ -558,53 +579,72 @@ loop.conversation = (function(mozL10n) { {sdk: window.OT} // Model dependencies ); // Obtain the callId and pass it through var helper = new loop.shared.utils.Helper(); var locationHash = helper.locationHash(); var callId; var outgoing; + var localRoomStore; - var hash = locationHash.match(/\#incoming\/(.*)/); + // XXX removeMe, along with noisy comment at the beginning of + // conversation_test.js "when locationHash begins with #room". + if (navigator.mozLoop.getLoopBoolPref("test.alwaysUseRooms")) { + locationHash = "#room/32"; + } + + var hash = locationHash.match(/#incoming\/(.*)/); if (hash) { callId = hash[1]; outgoing = false; + } else if (hash = locationHash.match(/#room\/(.*)/)) { + localRoomStore = new loop.store.LocalRoomStore({ + dispatcher: dispatcher, + mozLoop: navigator.mozLoop + }); } else { - hash = locationHash.match(/\#outgoing\/(.*)/); + hash = locationHash.match(/#outgoing\/(.*)/); if (hash) { callId = hash[1]; outgoing = true; } } conversation.set({callId: callId}); window.addEventListener("unload", function(event) { // Handle direct close of dialog box via [x] control. navigator.mozLoop.releaseCallData(callId); }); document.body.classList.add(loop.shared.utils.getTargetPlatform()); - React.renderComponent(<ConversationControllerView + React.renderComponent(<AppControllerView + localRoomStore={localRoomStore} store={conversationStore} client={client} conversation={conversation} dispatcher={dispatcher} sdk={window.OT} />, document.querySelector('#main')); + if (localRoomStore) { + dispatcher.dispatch( + new sharedActions.SetupEmptyRoom({localRoomId: hash[1]})); + return; + } + dispatcher.dispatch(new loop.shared.actions.GatherCallData({ callId: callId, outgoing: outgoing })); } return { - ConversationControllerView: ConversationControllerView, + AppControllerView: AppControllerView, IncomingConversationView: IncomingConversationView, IncomingCallView: IncomingCallView, init: init }; })(document.mozL10n); document.addEventListener('DOMContentLoaded', loop.conversation.init);
--- a/browser/components/loop/content/js/conversationViews.js +++ b/browser/components/loop/content/js/conversationViews.js @@ -10,16 +10,83 @@ var loop = loop || {}; loop.conversationViews = (function(mozL10n) { var CALL_STATES = loop.store.CALL_STATES; var CALL_TYPES = loop.shared.utils.CALL_TYPES; var sharedActions = loop.shared.actions; var sharedViews = loop.shared.views; /** + * Displays information about the call + * Caller avatar, name & conversation creation date + */ + var CallIdentifierView = React.createClass({displayName: 'CallIdentifierView', + propTypes: { + peerIdentifier: React.PropTypes.string, + showIcons: React.PropTypes.bool.isRequired, + urlCreationDate: React.PropTypes.string, + video: React.PropTypes.bool + }, + + getDefaultProps: function() { + return { + peerIdentifier: "", + showLinkDetail: true, + urlCreationDate: "", + video: true + }; + }, + + getInitialState: function() { + return {timestamp: 0}; + }, + + /** + * Gets and formats the incoming call creation date + */ + formatCreationDate: function() { + if (!this.props.urlCreationDate) { + return ""; + } + + var timestamp = this.props.urlCreationDate; + return "(" + loop.shared.utils.formatDate(timestamp) + ")"; + }, + + render: function() { + var iconVideoClasses = React.addons.classSet({ + "fx-embedded-tiny-video-icon": true, + "muted": !this.props.video + }); + var callDetailClasses = React.addons.classSet({ + "fx-embedded-call-detail": true, + "hide": !this.props.showIcons + }); + + return ( + React.DOM.div({className: "fx-embedded-call-identifier"}, + React.DOM.div({className: "fx-embedded-call-identifier-avatar fx-embedded-call-identifier-item"}), + React.DOM.div({className: "fx-embedded-call-identifier-info fx-embedded-call-identifier-item"}, + React.DOM.div({className: "fx-embedded-call-identifier-text overflow-text-ellipsis"}, + this.props.peerIdentifier + ), + React.DOM.div({className: callDetailClasses}, + React.DOM.span({className: "fx-embedded-tiny-audio-icon"}), + React.DOM.span({className: iconVideoClasses}), + React.DOM.span({className: "fx-embedded-conversation-timestamp"}, + this.formatCreationDate() + ) + ) + ) + ) + ); + } + }); + + /** * Displays details of the incoming/outgoing conversation * (name, link, audio/video type etc). * * Allows the view to be extended with different buttons and progress * via children properties. */ var ConversationDetailView = React.createClass({displayName: 'ConversationDetailView', propTypes: { @@ -46,17 +113,19 @@ loop.conversationViews = (function(mozL1 } else { contactName = this._getPreferredEmail(this.props.contact).value; } document.title = contactName; return ( React.DOM.div({className: "call-window"}, - React.DOM.h2(null, contactName), + CallIdentifierView({ + peerIdentifier: contactName, + showIcons: false}), React.DOM.div(null, this.props.children) ) ); } }); /** * View for pending conversations. Displays a cancel button and appropriate @@ -210,19 +279,21 @@ loop.conversationViews = (function(mozL1 // height set to 100%" to fix video layout on Google Chrome // @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445 return { insertMode: "append", width: "100%", height: "100%", publishVideo: this.props.video.enabled, style: { + audioLevelDisplayMode: "off", bugDisplayMode: "off", buttonDisplayMode: "off", - nameDisplayMode: "off" + nameDisplayMode: "off", + videoDisabledDisplayMode: "off" } } }, /** * Used to update the video container whenever the orientation or size of the * display area changes. */ @@ -377,15 +448,16 @@ loop.conversationViews = (function(mozL1 )) } } }, }); return { PendingConversationView: PendingConversationView, + CallIdentifierView: CallIdentifierView, ConversationDetailView: ConversationDetailView, CallFailedView: CallFailedView, OngoingConversationView: OngoingConversationView, OutgoingConversationView: OutgoingConversationView }; })(document.mozL10n || navigator.mozL10n);
--- a/browser/components/loop/content/js/conversationViews.jsx +++ b/browser/components/loop/content/js/conversationViews.jsx @@ -10,16 +10,83 @@ var loop = loop || {}; loop.conversationViews = (function(mozL10n) { var CALL_STATES = loop.store.CALL_STATES; var CALL_TYPES = loop.shared.utils.CALL_TYPES; var sharedActions = loop.shared.actions; var sharedViews = loop.shared.views; /** + * Displays information about the call + * Caller avatar, name & conversation creation date + */ + var CallIdentifierView = React.createClass({ + propTypes: { + peerIdentifier: React.PropTypes.string, + showIcons: React.PropTypes.bool.isRequired, + urlCreationDate: React.PropTypes.string, + video: React.PropTypes.bool + }, + + getDefaultProps: function() { + return { + peerIdentifier: "", + showLinkDetail: true, + urlCreationDate: "", + video: true + }; + }, + + getInitialState: function() { + return {timestamp: 0}; + }, + + /** + * Gets and formats the incoming call creation date + */ + formatCreationDate: function() { + if (!this.props.urlCreationDate) { + return ""; + } + + var timestamp = this.props.urlCreationDate; + return "(" + loop.shared.utils.formatDate(timestamp) + ")"; + }, + + render: function() { + var iconVideoClasses = React.addons.classSet({ + "fx-embedded-tiny-video-icon": true, + "muted": !this.props.video + }); + var callDetailClasses = React.addons.classSet({ + "fx-embedded-call-detail": true, + "hide": !this.props.showIcons + }); + + return ( + <div className="fx-embedded-call-identifier"> + <div className="fx-embedded-call-identifier-avatar fx-embedded-call-identifier-item"/> + <div className="fx-embedded-call-identifier-info fx-embedded-call-identifier-item"> + <div className="fx-embedded-call-identifier-text overflow-text-ellipsis"> + {this.props.peerIdentifier} + </div> + <div className={callDetailClasses}> + <span className="fx-embedded-tiny-audio-icon"></span> + <span className={iconVideoClasses}></span> + <span className="fx-embedded-conversation-timestamp"> + {this.formatCreationDate()} + </span> + </div> + </div> + </div> + ); + } + }); + + /** * Displays details of the incoming/outgoing conversation * (name, link, audio/video type etc). * * Allows the view to be extended with different buttons and progress * via children properties. */ var ConversationDetailView = React.createClass({ propTypes: { @@ -46,17 +113,19 @@ loop.conversationViews = (function(mozL1 } else { contactName = this._getPreferredEmail(this.props.contact).value; } document.title = contactName; return ( <div className="call-window"> - <h2>{contactName}</h2> + <CallIdentifierView + peerIdentifier={contactName} + showIcons={false} /> <div>{this.props.children}</div> </div> ); } }); /** * View for pending conversations. Displays a cancel button and appropriate @@ -210,19 +279,21 @@ loop.conversationViews = (function(mozL1 // height set to 100%" to fix video layout on Google Chrome // @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445 return { insertMode: "append", width: "100%", height: "100%", publishVideo: this.props.video.enabled, style: { + audioLevelDisplayMode: "off", bugDisplayMode: "off", buttonDisplayMode: "off", - nameDisplayMode: "off" + nameDisplayMode: "off", + videoDisabledDisplayMode: "off" } } }, /** * Used to update the video container whenever the orientation or size of the * display area changes. */ @@ -377,15 +448,16 @@ loop.conversationViews = (function(mozL1 />) } } }, }); return { PendingConversationView: PendingConversationView, + CallIdentifierView: CallIdentifierView, ConversationDetailView: ConversationDetailView, CallFailedView: CallFailedView, OngoingConversationView: OngoingConversationView, OutgoingConversationView: OutgoingConversationView }; })(document.mozL10n || navigator.mozL10n);
--- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -303,41 +303,34 @@ loop.panel = (function(_, mozL10n) { /** * Provided by DocumentVisibilityMixin. Schedules retrieval of a new call * URL everytime the panel is reopened. */ onDocumentVisible: function() { this._fetchCallUrl(); }, - /** - * Returns a random 5 character string used to identify - * the conversation. - * XXX this will go away once the backend changes - */ - conversationIdentifier: function() { - return Math.random().toString(36).substring(5); - }, - componentDidMount: function() { // If we've already got a callURL, don't bother requesting a new one. // As of this writing, only used for visual testing in the UI showcase. if (this.state.callUrl.length) { return; } this._fetchCallUrl(); }, /** * Fetches a call URL. */ _fetchCallUrl: function() { this.setState({pending: true}); - this.props.client.requestCallUrl(this.conversationIdentifier(), + // XXX This is an empty string as a conversation identifier. Bug 1015938 implements + // a user-set string. + this.props.client.requestCallUrl("", this._onCallUrlReceived); }, _onCallUrlReceived: function(err, callUrlData) { if (err) { if (err.code != 401) { // 401 errors are already handled in hawkRequest and show an error // message about the session.
--- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -303,41 +303,34 @@ loop.panel = (function(_, mozL10n) { /** * Provided by DocumentVisibilityMixin. Schedules retrieval of a new call * URL everytime the panel is reopened. */ onDocumentVisible: function() { this._fetchCallUrl(); }, - /** - * Returns a random 5 character string used to identify - * the conversation. - * XXX this will go away once the backend changes - */ - conversationIdentifier: function() { - return Math.random().toString(36).substring(5); - }, - componentDidMount: function() { // If we've already got a callURL, don't bother requesting a new one. // As of this writing, only used for visual testing in the UI showcase. if (this.state.callUrl.length) { return; } this._fetchCallUrl(); }, /** * Fetches a call URL. */ _fetchCallUrl: function() { this.setState({pending: true}); - this.props.client.requestCallUrl(this.conversationIdentifier(), + // XXX This is an empty string as a conversation identifier. Bug 1015938 implements + // a user-set string. + this.props.client.requestCallUrl("", this._onCallUrlReceived); }, _onCallUrlReceived: function(err, callUrlData) { if (err) { if (err.code != 401) { // 401 errors are already handled in hawkRequest and show an error // message about the session.
new file mode 100644 --- /dev/null +++ b/browser/components/loop/content/js/roomViews.js @@ -0,0 +1,109 @@ +/** @jsx React.DOM */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global loop:true, React */ + +var loop = loop || {}; +loop.roomViews = (function(mozL10n) { + "use strict"; + + /** + * Root object, by default set to window. + * @type {DOMWindow|Object} + */ + var rootObject = window; + + /** + * Sets a new root object. This is useful for testing native DOM events so we + * can fake them. + * + * @param {Object} + */ + function setRootObject(obj) { + rootObject = obj; + } + + var EmptyRoomView = React.createClass({displayName: 'EmptyRoomView', + mixins: [Backbone.Events], + + propTypes: { + mozLoop: + React.PropTypes.object.isRequired, + localRoomStore: + React.PropTypes.instanceOf(loop.store.LocalRoomStore).isRequired, + }, + + getInitialState: function() { + return this.props.localRoomStore.getStoreState(); + }, + + componentWillMount: function() { + this.listenTo(this.props.localRoomStore, "change", + this._onLocalRoomStoreChanged); + }, + + componentDidMount: function() { + // XXXremoveMe (just the conditional itself) in patch 2 for bug 1074686, + // once the addCallback stuff lands + if (this.props.mozLoop.rooms && this.props.mozLoop.rooms.addCallback) { + this.props.mozLoop.rooms.addCallback( + this.state.localRoomId, + "RoomCreationError", this.onCreationError); + } + }, + + /** + * Attached to the "RoomCreationError" with mozLoop.rooms.addCallback, + * which is fired mozLoop.rooms.createRoom from the panel encounters an + * error while attempting to create the room for this view. + * + * @param {Error} err - JS Error object with info about the problem + */ + onCreationError: function(err) { + // XXX put up a user friendly error instead of this + rootObject.console.error("EmptyRoomView creation error: ", err); + }, + + /** + * Handles a "change" event on the localRoomStore, and updates this.state + * to match the store. + * + * @private + */ + _onLocalRoomStoreChanged: function() { + this.setState(this.props.localRoomStore.getStoreState()); + }, + + componentWillUnmount: function() { + this.stopListening(this.props.localRoomStore); + + // XXXremoveMe (just the conditional itself) in patch 2 for bug 1074686, + // once the addCallback stuff lands + if (this.props.mozLoop.rooms && this.props.mozLoop.rooms.removeCallback) { + this.props.mozLoop.rooms.removeCallback( + this.state.localRoomId, + "RoomCreationError", this.onCreationError); + } + }, + + render: function() { + // XXX switch this to use the document title mixin once bug 1081079 lands + if (this.state.serverData && this.state.serverData.roomName) { + rootObject.document.title = this.state.serverData.roomName; + } + + return ( + React.DOM.div({className: "goat"}) + ); + } + }); + + return { + setRootObject: setRootObject, + EmptyRoomView: EmptyRoomView + }; + +})(document.mozL10n || navigator.mozL10n);;
new file mode 100644 --- /dev/null +++ b/browser/components/loop/content/js/roomViews.jsx @@ -0,0 +1,109 @@ +/** @jsx React.DOM */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global loop:true, React */ + +var loop = loop || {}; +loop.roomViews = (function(mozL10n) { + "use strict"; + + /** + * Root object, by default set to window. + * @type {DOMWindow|Object} + */ + var rootObject = window; + + /** + * Sets a new root object. This is useful for testing native DOM events so we + * can fake them. + * + * @param {Object} + */ + function setRootObject(obj) { + rootObject = obj; + } + + var EmptyRoomView = React.createClass({ + mixins: [Backbone.Events], + + propTypes: { + mozLoop: + React.PropTypes.object.isRequired, + localRoomStore: + React.PropTypes.instanceOf(loop.store.LocalRoomStore).isRequired, + }, + + getInitialState: function() { + return this.props.localRoomStore.getStoreState(); + }, + + componentWillMount: function() { + this.listenTo(this.props.localRoomStore, "change", + this._onLocalRoomStoreChanged); + }, + + componentDidMount: function() { + // XXXremoveMe (just the conditional itself) in patch 2 for bug 1074686, + // once the addCallback stuff lands + if (this.props.mozLoop.rooms && this.props.mozLoop.rooms.addCallback) { + this.props.mozLoop.rooms.addCallback( + this.state.localRoomId, + "RoomCreationError", this.onCreationError); + } + }, + + /** + * Attached to the "RoomCreationError" with mozLoop.rooms.addCallback, + * which is fired mozLoop.rooms.createRoom from the panel encounters an + * error while attempting to create the room for this view. + * + * @param {Error} err - JS Error object with info about the problem + */ + onCreationError: function(err) { + // XXX put up a user friendly error instead of this + rootObject.console.error("EmptyRoomView creation error: ", err); + }, + + /** + * Handles a "change" event on the localRoomStore, and updates this.state + * to match the store. + * + * @private + */ + _onLocalRoomStoreChanged: function() { + this.setState(this.props.localRoomStore.getStoreState()); + }, + + componentWillUnmount: function() { + this.stopListening(this.props.localRoomStore); + + // XXXremoveMe (just the conditional itself) in patch 2 for bug 1074686, + // once the addCallback stuff lands + if (this.props.mozLoop.rooms && this.props.mozLoop.rooms.removeCallback) { + this.props.mozLoop.rooms.removeCallback( + this.state.localRoomId, + "RoomCreationError", this.onCreationError); + } + }, + + render: function() { + // XXX switch this to use the document title mixin once bug 1081079 lands + if (this.state.serverData && this.state.serverData.roomName) { + rootObject.document.title = this.state.serverData.roomName; + } + + return ( + <div className="goat"/> + ); + } + }); + + return { + setRootObject: setRootObject, + EmptyRoomView: EmptyRoomView + }; + +})(document.mozL10n || navigator.mozL10n);;
--- a/browser/components/loop/content/panel.html +++ b/browser/components/loop/content/panel.html @@ -9,17 +9,17 @@ <link rel="stylesheet" type="text/css" href="loop/shared/css/common.css"> <link rel="stylesheet" type="text/css" href="loop/shared/css/panel.css"> <link rel="stylesheet" type="text/css" href="loop/shared/css/contacts.css"> </head> <body class="panel"> <div id="main"></div> - <script type="text/javascript" src="loop/shared/libs/react-0.11.1.js"></script> + <script type="text/javascript" src="loop/shared/libs/react-0.11.2.js"></script> <script type="text/javascript" src="loop/libs/l10n.js"></script> <script type="text/javascript" src="loop/shared/libs/jquery-2.1.0.js"></script> <script type="text/javascript" src="loop/shared/libs/lodash-2.4.1.js"></script> <script type="text/javascript" src="loop/shared/libs/backbone-1.1.2.js"></script> <script type="text/javascript" src="loop/shared/js/utils.js"></script> <script type="text/javascript" src="loop/shared/js/models.js"></script> <script type="text/javascript" src="loop/shared/js/mixins.js"></script>
--- a/browser/components/loop/content/shared/css/conversation.css +++ b/browser/components/loop/content/shared/css/conversation.css @@ -89,22 +89,24 @@ vertical-align: top; width: .8rem; height: .8rem; background-repeat: no-repeat; cursor: pointer; } .fx-embedded-btn-icon-video, -.fx-embedded-btn-video-small { +.fx-embedded-btn-video-small, +.fx-embedded-tiny-video-icon { background-image: url("../img/video-inverse-14x14.png"); } .fx-embedded-btn-icon-audio, -.fx-embedded-btn-audio-small { +.fx-embedded-btn-audio-small, +.fx-embedded-tiny-audio-icon { background-image: url("../img/audio-inverse-14x14.png"); } .fx-embedded-btn-audio-small, .fx-embedded-btn-video-small { width: 26px; height: 26px; border-left: 1px solid rgba(255,255,255,.4); @@ -479,16 +481,84 @@ background-size: contain; background-position: center; } .fx-embedded .media.nested { min-height: 200px; } +.fx-embedded-call-identifier { + display: inline; + width: 100%; + padding: 1.2em; +} + +.fx-embedded-call-identifier-item { + height: 50px; +} + +.fx-embedded-call-identifier-avatar { + max-width: 50px; + min-width: 50px; + background: #ccc; + border-radius: 50%; + background-image: url("../img/audio-call-avatar.svg"); + background-repeat: no-repeat; + background-color: #4ba6e7; + background-size: contain; + overflow: hidden; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3); + float: left; + -moz-margin-end: 1em; +} + +.fx-embedded-call-identifier-text { + font-weight: bold; +} + +.fx-embedded-call-identifier-info { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + -moz-margin-start: 1em; +} + +.fx-embedded-conversation-timestamp { + font-size: .6rem; + line-height: 17px; + display: inline-block; + vertical-align: top; +} + +.fx-embedded-call-detail { + padding-top: 1.2em; +} + +.fx-embedded-tiny-video-icon { + margin: 0 0.8em; +} + +.fx-embedded-tiny-audio-icon, +.fx-embedded-tiny-video-icon { + width: 18px; + height: 18px; + background-size: 12px 12px; + background-color: #4ba6e7; + display: inline-block; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; +} + + .fx-embedded-tiny-video-icon.muted { + background-color: rgba(0,0,0,.2) + } + @media screen and (min-width:640px) { /* Force full height on all parents up to the video elements * this way we can ensure the aspect ratio and use height 100% * on the video element * */ html, body, #main, .video-layout-wrapper,
--- a/browser/components/loop/content/shared/css/panel.css +++ b/browser/components/loop/content/shared/css/panel.css @@ -54,25 +54,28 @@ body { background-size: 16px 16px; background-position: center; } .tab-view > li:last-child { border-right-style: none; } -.tab-view > li[data-tab-name="call"] { +.tab-view > li[data-tab-name="call"], +.tab-view > li[data-tab-name="rooms"] { background-image: url("../img/icons-16x16.svg#precall"); } -.tab-view > li[data-tab-name="call"]:hover { +.tab-view > li[data-tab-name="call"]:hover, +.tab-view > li[data-tab-name="rooms"]:hover { background-image: url("../img/icons-16x16.svg#precall-hover"); } -.tab-view > li[data-tab-name="call"].selected { +.tab-view > li[data-tab-name="call"].selected, +.tab-view > li[data-tab-name="rooms"].selected { background-image: url("../img/icons-16x16.svg#precall-active"); } .tab-view > li[data-tab-name="contacts"] { background-image: url("../img/icons-16x16.svg#contacts"); } .tab-view > li[data-tab-name="contacts"]:hover {
--- a/browser/components/loop/content/shared/js/actions.js +++ b/browser/components/loop/content/shared/js/actions.js @@ -120,11 +120,21 @@ loop.shared.actions = (function() { enabled: Boolean }), /** * Retrieves room list. * XXX: should move to some roomActions module - refs bug 1079284 */ GetAllRooms: Action.define("getAllRooms", { - }) + }), + + /** + * Primes localRoomStore with roomLocalId, which triggers the EmptyRoomView + * to do any necessary setup. + * + * XXX should move to localRoomActions module + */ + SetupEmptyRoom: Action.define("setupEmptyRoom", { + localRoomId: String + }), }; })();
new file mode 100644 --- /dev/null +++ b/browser/components/loop/content/shared/js/localRoomStore.js @@ -0,0 +1,113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global loop:true */ + +var loop = loop || {}; +loop.store = loop.store || {}; +loop.store.LocalRoomStore = (function() { + "use strict"; + + var sharedActions = loop.shared.actions; + + /** + * Store for things that are local to this instance (in this profile, on + * this machine) of this roomRoom store, in addition to a mirror of some + * remote-state. + * + * @extends {Backbone.Events} + * + * @param {Object} options - Options object + * @param {loop.Dispatcher} options.dispatch - The dispatcher for dispatching + * actions and registering to consume them. + * @param {MozLoop} options.mozLoop - MozLoop API provider object + */ + function LocalRoomStore(options) { + options = options || {}; + + if (!options.dispatcher) { + throw new Error("Missing option dispatcher"); + } + this.dispatcher = options.dispatcher; + + if (!options.mozLoop) { + throw new Error("Missing option mozLoop"); + } + this.mozLoop = options.mozLoop; + + this.dispatcher.register(this, ["setupEmptyRoom"]); + } + + LocalRoomStore.prototype = _.extend({ + + /** + * Stored data reflecting the local state of a given room, used to drive + * the room's views. + * + * @property {Object} serverData - local cache of the data returned by + * MozLoop.getRoomData for this room. + * @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D + * + * @property {Error=} error - if the room is an error state, this will be + * set to an Error object reflecting the problem; + * otherwise it will be unset. + * + * @property {String} localRoomId - profile-local identifier used with + * the MozLoop API. + */ + _storeState: { + }, + + getStoreState: function() { + return this._storeState; + }, + + setStoreState: function(state) { + this._storeState = state; + this.trigger("change"); + }, + + /** + * Proxy to mozLoop.rooms.getRoomData for setupEmptyRoom action. + * + * XXXremoveMe Can probably be removed when bug 1074664 lands. + * + * @param {sharedActions.setupEmptyRoom} actionData + * @param {Function} cb Callback(error, roomData) + */ + _fetchRoomData: function(actionData, cb) { + if (this.mozLoop.rooms && this.mozLoop.rooms.getRoomData) { + this.mozLoop.rooms.getRoomData(actionData.localRoomId, cb); + } else { + cb(null, {roomName: "Donkeys"}); + } + }, + + /** + * Execute setupEmptyRoom event action from the dispatcher. This primes + * the store with the localRoomId, and calls MozLoop.getRoomData on that + * ID. This will return either a reflection of state on the server, or, + * if the createRoom call hasn't yet returned, it will have at least the + * roomName as specified to the createRoom method. + * + * When the room name gets set, that will trigger the view to display + * that name. + * + * @param {sharedActions.setupEmptyRoom} actionData + */ + setupEmptyRoom: function(actionData) { + this._fetchRoomData(actionData, function(error, roomData) { + this.setStoreState({ + error: error, + localRoomId: actionData.localRoomId, + serverData: roomData + }); + }.bind(this)); + } + + }, Backbone.Events); + + return LocalRoomStore; + +})();
--- a/browser/components/loop/content/shared/js/models.js +++ b/browser/components/loop/content/shared/js/models.js @@ -27,16 +27,17 @@ loop.shared.models = (function(l10n) { websocketToken: undefined, // The token to use for websocket auth, this is // stored as a hex string which is what the server // requires. callType: undefined, // The type of incoming call selected by // other peer ("audio" or "audio-video") selectedCallType: "audio-video", // The selected type for the call that was // initiated ("audio" or "audio-video") callToken: undefined, // Incoming call token. + callUrl: undefined, // Incoming call url // Used for blocking a call url subscribedStream: false, // Used to indicate that a stream has been // subscribed to publishedStream: false // Used to indicate that a stream has been // published }, /** @@ -137,25 +138,28 @@ loop.shared.models = (function(l10n) { /** * Sets session information about the incoming call. * * @param {Object} sessionData Conversation session information. */ setIncomingSessionData: function(sessionData) { // Explicit property assignment to prevent later "surprises" this.set({ - sessionId: sessionData.sessionId, - sessionToken: sessionData.sessionToken, - sessionType: sessionData.sessionType, - apiKey: sessionData.apiKey, - callId: sessionData.callId, - progressURL: sessionData.progressURL, - websocketToken: sessionData.websocketToken.toString(16), - callType: sessionData.callType || "audio-video", - callToken: sessionData.callToken + sessionId: sessionData.sessionId, + sessionToken: sessionData.sessionToken, + sessionType: sessionData.sessionType, + apiKey: sessionData.apiKey, + callId: sessionData.callId, + callerId: sessionData.callerId, + urlCreationDate: sessionData.urlCreationDate, + progressURL: sessionData.progressURL, + websocketToken: sessionData.websocketToken.toString(16), + callType: sessionData.callType || "audio-video", + callToken: sessionData.callToken, + callUrl: sessionData.callUrl }); }, /** * Starts a SDK session and subscribe to call events. */ startSession: function() { if (!this.isSessionReady()) { @@ -194,16 +198,33 @@ loop.shared.models = (function(l10n) { } if (callType === "outgoing") { return this.get("selectedCallType") === "audio-video"; } return undefined; }, /** + * Used to remove the scheme from a url. + */ + _removeScheme: function(url) { + if (!url) { + return ""; + } + return url.replace(/^https?:\/\//, ""); + }, + + /** + * Returns a conversation identifier for the incoming call view + */ + getCallIdentifier: function() { + return this.get("callerId") || this._removeScheme(this.get("callUrl")); + }, + + /** * Publishes a local stream. * * @param {Publisher} publisher The publisher object to publish * to the session. */ publish: function(publisher) { this.session.publish(publisher); this.set("publishedStream", true);
--- a/browser/components/loop/content/shared/js/utils.js +++ b/browser/components/loop/content/shared/js/utils.js @@ -13,16 +13,28 @@ loop.shared.utils = (function() { * Call types used for determining if a call is audio/video or audio-only. */ var CALL_TYPES = { AUDIO_VIDEO: "audio-video", AUDIO_ONLY: "audio" }; /** + * Format a given date into an l10n-friendly string. + * + * @param {Integer} The timestamp in seconds to format. + * @return {String} The formatted string. + */ + function formatDate(timestamp) { + var date = (new Date(timestamp * 1000)); + var options = {year: "numeric", month: "long", day: "numeric"}; + return date.toLocaleDateString(navigator.language, options); + } + + /** * Used for adding different styles to the panel * @returns {String} Corresponds to the client platform * */ function getTargetPlatform() { var platform="unknown_platform"; if (navigator.platform.indexOf("Win") !== -1) { platform = "windows"; @@ -82,12 +94,13 @@ loop.shared.utils = (function() { locationHash: function() { return window.location.hash; } }; return { CALL_TYPES: CALL_TYPES, Helper: Helper, + formatDate: formatDate, getTargetPlatform: getTargetPlatform, getBoolPreference: getBoolPreference }; })();
--- a/browser/components/loop/content/shared/js/views.js +++ b/browser/components/loop/content/shared/js/views.js @@ -146,19 +146,21 @@ loop.shared.views = (function(_, OT, l10 // height set to 100%" to fix video layout on Google Chrome // @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445 publisherConfig: { insertMode: "append", width: "100%", height: "100%", style: { + audioLevelDisplayMode: "off", bugDisplayMode: "off", buttonDisplayMode: "off", - nameDisplayMode: "off" + nameDisplayMode: "off", + videoDisabledDisplayMode: "off" } }, getDefaultProps: function() { return { initiate: true, video: {enabled: true, visible: true}, audio: {enabled: true, visible: true}
--- a/browser/components/loop/content/shared/js/views.jsx +++ b/browser/components/loop/content/shared/js/views.jsx @@ -146,19 +146,21 @@ loop.shared.views = (function(_, OT, l10 // height set to 100%" to fix video layout on Google Chrome // @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445 publisherConfig: { insertMode: "append", width: "100%", height: "100%", style: { + audioLevelDisplayMode: "off", bugDisplayMode: "off", buttonDisplayMode: "off", - nameDisplayMode: "off" + nameDisplayMode: "off", + videoDisabledDisplayMode: "off" } }, getDefaultProps: function() { return { initiate: true, video: {enabled: true, visible: true}, audio: {enabled: true, visible: true}
rename from browser/components/loop/content/shared/libs/react-0.11.1-prod.js rename to browser/components/loop/content/shared/libs/react-0.11.2-prod.js --- a/browser/components/loop/content/shared/libs/react-0.11.1-prod.js +++ b/browser/components/loop/content/shared/libs/react-0.11.2-prod.js @@ -1,22 +1,22 @@ /** - * React (with addons) v0.11.1 + * React (with addons) v0.11.2 * * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.React=e()}}(function(){return function e(t,n,r){function o(a,s){if(!n[a]){if(!t[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);throw new Error("Cannot find module '"+a+"'")}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){var n=t[a][1][e];return o(n?n:e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(e,t){"use strict";var n=e("./focusNode"),r={componentDidMount:function(){this.props.autoFocus&&n(this.getDOMNode())}};t.exports=r},{"./focusNode":117}],2:[function(e,t){"use strict";function n(){var e=window.opera;return"object"==typeof e&&"function"==typeof e.version&&parseInt(e.version(),10)<=12}function r(e){return(e.ctrlKey||e.altKey||e.metaKey)&&!(e.ctrlKey&&e.altKey)}var o=e("./EventConstants"),i=e("./EventPropagators"),a=e("./ExecutionEnvironment"),s=e("./SyntheticInputEvent"),u=e("./keyOf"),c=a.canUseDOM&&"TextEvent"in window&&!("documentMode"in document||n()),l=32,p=String.fromCharCode(l),d=o.topLevelTypes,f={beforeInput:{phasedRegistrationNames:{bubbled:u({onBeforeInput:null}),captured:u({onBeforeInputCapture:null})},dependencies:[d.topCompositionEnd,d.topKeyPress,d.topTextInput,d.topPaste]}},h=null,v={eventTypes:f,extractEvents:function(e,t,n,o){var a;if(c)switch(e){case d.topKeyPress:var u=o.which;if(u!==l)return;a=String.fromCharCode(u);break;case d.topTextInput:if(a=o.data,a===p)return;break;default:return}else{switch(e){case d.topPaste:h=null;break;case d.topKeyPress:o.which&&!r(o)&&(h=String.fromCharCode(o.which));break;case d.topCompositionEnd:h=o.data}if(null===h)return;a=h}if(a){var v=s.getPooled(f.beforeInput,n,o);return v.data=a,h=null,i.accumulateTwoPhaseDispatches(v),v}}};t.exports=v},{"./EventConstants":16,"./EventPropagators":21,"./ExecutionEnvironment":22,"./SyntheticInputEvent":95,"./keyOf":138}],3:[function(e,t){var n=e("./invariant"),r={addClass:function(e,t){return n(!/\s/.test(t)),t&&(e.classList?e.classList.add(t):r.hasClass(e,t)||(e.className=e.className+" "+t)),e},removeClass:function(e,t){return n(!/\s/.test(t)),t&&(e.classList?e.classList.remove(t):r.hasClass(e,t)&&(e.className=e.className.replace(new RegExp("(^|\\s)"+t+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,""))),e},conditionClass:function(e,t,n){return(n?r.addClass:r.removeClass)(e,t)},hasClass:function(e,t){return n(!/\s/.test(t)),e.classList?!!t&&e.classList.contains(t):(" "+e.className+" ").indexOf(" "+t+" ")>-1}};t.exports=r},{"./invariant":131}],4:[function(e,t){"use strict";function n(e,t){return e+t.charAt(0).toUpperCase()+t.substring(1)}var r={columnCount:!0,fillOpacity:!0,flex:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},o=["Webkit","ms","Moz","O"];Object.keys(r).forEach(function(e){o.forEach(function(t){r[n(t,e)]=r[e]})});var i={background:{backgroundImage:!0,backgroundPosition:!0,backgroundRepeat:!0,backgroundColor:!0},border:{borderWidth:!0,borderStyle:!0,borderColor:!0},borderBottom:{borderBottomWidth:!0,borderBottomStyle:!0,borderBottomColor:!0},borderLeft:{borderLeftWidth:!0,borderLeftStyle:!0,borderLeftColor:!0},borderRight:{borderRightWidth:!0,borderRightStyle:!0,borderRightColor:!0},borderTop:{borderTopWidth:!0,borderTopStyle:!0,borderTopColor:!0},font:{fontStyle:!0,fontVariant:!0,fontWeight:!0,fontSize:!0,lineHeight:!0,fontFamily:!0}},a={isUnitlessNumber:r,shorthandPropertyExpansions:i};t.exports=a},{}],5:[function(e,t){"use strict";var n=e("./CSSProperty"),r=e("./dangerousStyleValue"),o=e("./hyphenateStyleName"),i=e("./memoizeStringOnly"),a=i(function(e){return o(e)}),s={createMarkupForStyles:function(e){var t="";for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];null!=o&&(t+=a(n)+":",t+=r(n,o)+";")}return t||null},setValueForStyles:function(e,t){var o=e.style;for(var i in t)if(t.hasOwnProperty(i)){var a=r(i,t[i]);if(a)o[i]=a;else{var s=n.shorthandPropertyExpansions[i];if(s)for(var u in s)o[u]="";else o[i]=""}}}};t.exports=s},{"./CSSProperty":4,"./dangerousStyleValue":112,"./hyphenateStyleName":129,"./memoizeStringOnly":140}],6:[function(e,t){"use strict";function n(){this._callbacks=null,this._contexts=null}var r=e("./PooledClass"),o=e("./invariant"),i=e("./mixInto");i(n,{enqueue:function(e,t){this._callbacks=this._callbacks||[],this._contexts=this._contexts||[],this._callbacks.push(e),this._contexts.push(t)},notifyAll:function(){var e=this._callbacks,t=this._contexts;if(e){o(e.length===t.length),this._callbacks=null,this._contexts=null;for(var n=0,r=e.length;r>n;n++)e[n].call(t[n]);e.length=0,t.length=0}},reset:function(){this._callbacks=null,this._contexts=null},destructor:function(){this.reset()}}),r.addPoolingTo(n),t.exports=n},{"./PooledClass":28,"./invariant":131,"./mixInto":144}],7:[function(e,t){"use strict";function n(e){return"SELECT"===e.nodeName||"INPUT"===e.nodeName&&"file"===e.type}function r(e){var t=M.getPooled(P.change,S,e);C.accumulateTwoPhaseDispatches(t),R.batchedUpdates(o,t)}function o(e){y.enqueueEvents(e),y.processEventQueue()}function i(e,t){T=e,S=t,T.attachEvent("onchange",r)}function a(){T&&(T.detachEvent("onchange",r),T=null,S=null)}function s(e,t,n){return e===O.topChange?n:void 0}function u(e,t,n){e===O.topFocus?(a(),i(t,n)):e===O.topBlur&&a()}function c(e,t){T=e,S=t,w=e.value,_=Object.getOwnPropertyDescriptor(e.constructor.prototype,"value"),Object.defineProperty(T,"value",k),T.attachEvent("onpropertychange",p)}function l(){T&&(delete T.value,T.detachEvent("onpropertychange",p),T=null,S=null,w=null,_=null)}function p(e){if("value"===e.propertyName){var t=e.srcElement.value;t!==w&&(w=t,r(e))}}function d(e,t,n){return e===O.topInput?n:void 0}function f(e,t,n){e===O.topFocus?(l(),c(t,n)):e===O.topBlur&&l()}function h(e){return e!==O.topSelectionChange&&e!==O.topKeyUp&&e!==O.topKeyDown||!T||T.value===w?void 0:(w=T.value,S)}function v(e){return"INPUT"===e.nodeName&&("checkbox"===e.type||"radio"===e.type)}function m(e,t,n){return e===O.topClick?n:void 0}var g=e("./EventConstants"),y=e("./EventPluginHub"),C=e("./EventPropagators"),E=e("./ExecutionEnvironment"),R=e("./ReactUpdates"),M=e("./SyntheticEvent"),D=e("./isEventSupported"),x=e("./isTextInputElement"),b=e("./keyOf"),O=g.topLevelTypes,P={change:{phasedRegistrationNames:{bubbled:b({onChange:null}),captured:b({onChangeCapture:null})},dependencies:[O.topBlur,O.topChange,O.topClick,O.topFocus,O.topInput,O.topKeyDown,O.topKeyUp,O.topSelectionChange]}},T=null,S=null,w=null,_=null,I=!1;E.canUseDOM&&(I=D("change")&&(!("documentMode"in document)||document.documentMode>8));var N=!1;E.canUseDOM&&(N=D("input")&&(!("documentMode"in document)||document.documentMode>9));var k={get:function(){return _.get.call(this)},set:function(e){w=""+e,_.set.call(this,e)}},A={eventTypes:P,extractEvents:function(e,t,r,o){var i,a;if(n(t)?I?i=s:a=u:x(t)?N?i=d:(i=h,a=f):v(t)&&(i=m),i){var c=i(e,t,r);if(c){var l=M.getPooled(P.change,c,o);return C.accumulateTwoPhaseDispatches(l),l}}a&&a(e,t,r)}};t.exports=A},{"./EventConstants":16,"./EventPluginHub":18,"./EventPropagators":21,"./ExecutionEnvironment":22,"./ReactUpdates":84,"./SyntheticEvent":93,"./isEventSupported":132,"./isTextInputElement":134,"./keyOf":138}],8:[function(e,t){"use strict";var n=0,r={createReactRootIndex:function(){return n++}};t.exports=r},{}],9:[function(e,t){"use strict";function n(e){switch(e){case g.topCompositionStart:return C.compositionStart;case g.topCompositionEnd:return C.compositionEnd;case g.topCompositionUpdate:return C.compositionUpdate}}function r(e,t){return e===g.topKeyDown&&t.keyCode===h}function o(e,t){switch(e){case g.topKeyUp:return-1!==f.indexOf(t.keyCode);case g.topKeyDown:return t.keyCode!==h;case g.topKeyPress:case g.topMouseDown:case g.topBlur:return!0;default:return!1}}function i(e){this.root=e,this.startSelection=c.getSelection(e),this.startValue=this.getText()}var a=e("./EventConstants"),s=e("./EventPropagators"),u=e("./ExecutionEnvironment"),c=e("./ReactInputSelection"),l=e("./SyntheticCompositionEvent"),p=e("./getTextContentAccessor"),d=e("./keyOf"),f=[9,13,27,32],h=229,v=u.canUseDOM&&"CompositionEvent"in window,m=!v||"documentMode"in document&&document.documentMode>8&&document.documentMode<=11,g=a.topLevelTypes,y=null,C={compositionEnd:{phasedRegistrationNames:{bubbled:d({onCompositionEnd:null}),captured:d({onCompositionEndCapture:null})},dependencies:[g.topBlur,g.topCompositionEnd,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]},compositionStart:{phasedRegistrationNames:{bubbled:d({onCompositionStart:null}),captured:d({onCompositionStartCapture:null})},dependencies:[g.topBlur,g.topCompositionStart,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]},compositionUpdate:{phasedRegistrationNames:{bubbled:d({onCompositionUpdate:null}),captured:d({onCompositionUpdateCapture:null})},dependencies:[g.topBlur,g.topCompositionUpdate,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]}};i.prototype.getText=function(){return this.root.value||this.root[p()]},i.prototype.getData=function(){var e=this.getText(),t=this.startSelection.start,n=this.startValue.length-this.startSelection.end;return e.substr(t,e.length-n-t)};var E={eventTypes:C,extractEvents:function(e,t,a,u){var c,p;if(v?c=n(e):y?o(e,u)&&(c=C.compositionEnd):r(e,u)&&(c=C.compositionStart),m&&(y||c!==C.compositionStart?c===C.compositionEnd&&y&&(p=y.getData(),y=null):y=new i(t)),c){var d=l.getPooled(c,a,u);return p&&(d.data=p),s.accumulateTwoPhaseDispatches(d),d}}};t.exports=E},{"./EventConstants":16,"./EventPropagators":21,"./ExecutionEnvironment":22,"./ReactInputSelection":61,"./SyntheticCompositionEvent":91,"./getTextContentAccessor":126,"./keyOf":138}],10:[function(e,t){"use strict";function n(e,t,n){e.insertBefore(t,e.childNodes[n]||null)}var r,o=e("./Danger"),i=e("./ReactMultiChildUpdateTypes"),a=e("./getTextContentAccessor"),s=e("./invariant"),u=a();r="textContent"===u?function(e,t){e.textContent=t}:function(e,t){for(;e.firstChild;)e.removeChild(e.firstChild);if(t){var n=e.ownerDocument||document;e.appendChild(n.createTextNode(t))}};var c={dangerouslyReplaceNodeWithMarkup:o.dangerouslyReplaceNodeWithMarkup,updateTextContent:r,processUpdates:function(e,t){for(var a,u=null,c=null,l=0;a=e[l];l++)if(a.type===i.MOVE_EXISTING||a.type===i.REMOVE_NODE){var p=a.fromIndex,d=a.parentNode.childNodes[p],f=a.parentID;s(d),u=u||{},u[f]=u[f]||[],u[f][p]=d,c=c||[],c.push(d)}var h=o.dangerouslyRenderMarkup(t);if(c)for(var v=0;v<c.length;v++)c[v].parentNode.removeChild(c[v]);for(var m=0;a=e[m];m++)switch(a.type){case i.INSERT_MARKUP:n(a.parentNode,h[a.markupIndex],a.toIndex);break;case i.MOVE_EXISTING:n(a.parentNode,u[a.parentID][a.fromIndex],a.toIndex);break;case i.TEXT_CONTENT:r(a.parentNode,a.textContent);break;case i.REMOVE_NODE:}}};t.exports=c},{"./Danger":13,"./ReactMultiChildUpdateTypes":67,"./getTextContentAccessor":126,"./invariant":131}],11:[function(e,t){"use strict";var n=e("./invariant"),r={MUST_USE_ATTRIBUTE:1,MUST_USE_PROPERTY:2,HAS_SIDE_EFFECTS:4,HAS_BOOLEAN_VALUE:8,HAS_NUMERIC_VALUE:16,HAS_POSITIVE_NUMERIC_VALUE:48,HAS_OVERLOADED_BOOLEAN_VALUE:64,injectDOMPropertyConfig:function(e){var t=e.Properties||{},o=e.DOMAttributeNames||{},a=e.DOMPropertyNames||{},s=e.DOMMutationMethods||{};e.isCustomAttribute&&i._isCustomAttributeFunctions.push(e.isCustomAttribute);for(var u in t){n(!i.isStandardName.hasOwnProperty(u)),i.isStandardName[u]=!0;var c=u.toLowerCase();if(i.getPossibleStandardName[c]=u,o.hasOwnProperty(u)){var l=o[u];i.getPossibleStandardName[l]=u,i.getAttributeName[u]=l}else i.getAttributeName[u]=c;i.getPropertyName[u]=a.hasOwnProperty(u)?a[u]:u,i.getMutationMethod[u]=s.hasOwnProperty(u)?s[u]:null;var p=t[u];i.mustUseAttribute[u]=p&r.MUST_USE_ATTRIBUTE,i.mustUseProperty[u]=p&r.MUST_USE_PROPERTY,i.hasSideEffects[u]=p&r.HAS_SIDE_EFFECTS,i.hasBooleanValue[u]=p&r.HAS_BOOLEAN_VALUE,i.hasNumericValue[u]=p&r.HAS_NUMERIC_VALUE,i.hasPositiveNumericValue[u]=p&r.HAS_POSITIVE_NUMERIC_VALUE,i.hasOverloadedBooleanValue[u]=p&r.HAS_OVERLOADED_BOOLEAN_VALUE,n(!i.mustUseAttribute[u]||!i.mustUseProperty[u]),n(i.mustUseProperty[u]||!i.hasSideEffects[u]),n(!!i.hasBooleanValue[u]+!!i.hasNumericValue[u]+!!i.hasOverloadedBooleanValue[u]<=1)}}},o={},i={ID_ATTRIBUTE_NAME:"data-reactid",isStandardName:{},getPossibleStandardName:{},getAttributeName:{},getPropertyName:{},getMutationMethod:{},mustUseAttribute:{},mustUseProperty:{},hasSideEffects:{},hasBooleanValue:{},hasNumericValue:{},hasPositiveNumericValue:{},hasOverloadedBooleanValue:{},_isCustomAttributeFunctions:[],isCustomAttribute:function(e){for(var t=0;t<i._isCustomAttributeFunctions.length;t++){var n=i._isCustomAttributeFunctions[t];if(n(e))return!0}return!1},getDefaultValueForProperty:function(e,t){var n,r=o[e];return r||(o[e]=r={}),t in r||(n=document.createElement(e),r[t]=n[t]),r[t]},injection:r};t.exports=i},{"./invariant":131}],12:[function(e,t){"use strict";function n(e,t){return null==t||r.hasBooleanValue[e]&&!t||r.hasNumericValue[e]&&isNaN(t)||r.hasPositiveNumericValue[e]&&1>t||r.hasOverloadedBooleanValue[e]&&t===!1}var r=e("./DOMProperty"),o=e("./escapeTextForBrowser"),i=e("./memoizeStringOnly"),a=(e("./warning"),i(function(e){return o(e)+'="'})),s={createMarkupForID:function(e){return a(r.ID_ATTRIBUTE_NAME)+o(e)+'"'},createMarkupForProperty:function(e,t){if(r.isStandardName.hasOwnProperty(e)&&r.isStandardName[e]){if(n(e,t))return"";var i=r.getAttributeName[e];return r.hasBooleanValue[e]||r.hasOverloadedBooleanValue[e]&&t===!0?o(i):a(i)+o(t)+'"'}return r.isCustomAttribute(e)?null==t?"":a(e)+o(t)+'"':null},setValueForProperty:function(e,t,o){if(r.isStandardName.hasOwnProperty(t)&&r.isStandardName[t]){var i=r.getMutationMethod[t];if(i)i(e,o);else if(n(t,o))this.deleteValueForProperty(e,t);else if(r.mustUseAttribute[t])e.setAttribute(r.getAttributeName[t],""+o);else{var a=r.getPropertyName[t];r.hasSideEffects[t]&&e[a]===o||(e[a]=o)}}else r.isCustomAttribute(t)&&(null==o?e.removeAttribute(t):e.setAttribute(t,""+o))},deleteValueForProperty:function(e,t){if(r.isStandardName.hasOwnProperty(t)&&r.isStandardName[t]){var n=r.getMutationMethod[t];if(n)n(e,void 0);else if(r.mustUseAttribute[t])e.removeAttribute(r.getAttributeName[t]);else{var o=r.getPropertyName[t],i=r.getDefaultValueForProperty(e.nodeName,o);r.hasSideEffects[t]&&e[o]===i||(e[o]=i)}}else r.isCustomAttribute(t)&&e.removeAttribute(t)}};t.exports=s},{"./DOMProperty":11,"./escapeTextForBrowser":115,"./memoizeStringOnly":140,"./warning":153}],13:[function(e,t){"use strict";function n(e){return e.substring(1,e.indexOf(" "))}var r=e("./ExecutionEnvironment"),o=e("./createNodesFromMarkup"),i=e("./emptyFunction"),a=e("./getMarkupWrap"),s=e("./invariant"),u=/^(<[^ \/>]+)/,c="data-danger-index",l={dangerouslyRenderMarkup:function(e){s(r.canUseDOM);for(var t,l={},p=0;p<e.length;p++)s(e[p]),t=n(e[p]),t=a(t)?t:"*",l[t]=l[t]||[],l[t][p]=e[p];var d=[],f=0;for(t in l)if(l.hasOwnProperty(t)){var h=l[t];for(var v in h)if(h.hasOwnProperty(v)){var m=h[v];h[v]=m.replace(u,"$1 "+c+'="'+v+'" ')}var g=o(h.join(""),i);for(p=0;p<g.length;++p){var y=g[p];y.hasAttribute&&y.hasAttribute(c)&&(v=+y.getAttribute(c),y.removeAttribute(c),s(!d.hasOwnProperty(v)),d[v]=y,f+=1)}}return s(f===d.length),s(d.length===e.length),d},dangerouslyReplaceNodeWithMarkup:function(e,t){s(r.canUseDOM),s(t),s("html"!==e.tagName.toLowerCase());var n=o(t,i)[0];e.parentNode.replaceChild(n,e)}};t.exports=l},{"./ExecutionEnvironment":22,"./createNodesFromMarkup":110,"./emptyFunction":113,"./getMarkupWrap":123,"./invariant":131}],14:[function(e,t){"use strict";var n=e("./keyOf"),r=[n({ResponderEventPlugin:null}),n({SimpleEventPlugin:null}),n({TapEventPlugin:null}),n({EnterLeaveEventPlugin:null}),n({ChangeEventPlugin:null}),n({SelectEventPlugin:null}),n({CompositionEventPlugin:null}),n({BeforeInputEventPlugin:null}),n({AnalyticsEventPlugin:null}),n({MobileSafariClickEventPlugin:null})];t.exports=r},{"./keyOf":138}],15:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./EventPropagators"),o=e("./SyntheticMouseEvent"),i=e("./ReactMount"),a=e("./keyOf"),s=n.topLevelTypes,u=i.getFirstReactDOM,c={mouseEnter:{registrationName:a({onMouseEnter:null}),dependencies:[s.topMouseOut,s.topMouseOver]},mouseLeave:{registrationName:a({onMouseLeave:null}),dependencies:[s.topMouseOut,s.topMouseOver]}},l=[null,null],p={eventTypes:c,extractEvents:function(e,t,n,a){if(e===s.topMouseOver&&(a.relatedTarget||a.fromElement))return null;if(e!==s.topMouseOut&&e!==s.topMouseOver)return null;var p;if(t.window===t)p=t;else{var d=t.ownerDocument;p=d?d.defaultView||d.parentWindow:window}var f,h;if(e===s.topMouseOut?(f=t,h=u(a.relatedTarget||a.toElement)||p):(f=p,h=t),f===h)return null;var v=f?i.getID(f):"",m=h?i.getID(h):"",g=o.getPooled(c.mouseLeave,v,a);g.type="mouseleave",g.target=f,g.relatedTarget=h;var y=o.getPooled(c.mouseEnter,m,a);return y.type="mouseenter",y.target=h,y.relatedTarget=f,r.accumulateEnterLeaveDispatches(g,y,v,m),l[0]=g,l[1]=y,l}};t.exports=p},{"./EventConstants":16,"./EventPropagators":21,"./ReactMount":65,"./SyntheticMouseEvent":97,"./keyOf":138}],16:[function(e,t){"use strict";var n=e("./keyMirror"),r=n({bubbled:null,captured:null}),o=n({topBlur:null,topChange:null,topClick:null,topCompositionEnd:null,topCompositionStart:null,topCompositionUpdate:null,topContextMenu:null,topCopy:null,topCut:null,topDoubleClick:null,topDrag:null,topDragEnd:null,topDragEnter:null,topDragExit:null,topDragLeave:null,topDragOver:null,topDragStart:null,topDrop:null,topError:null,topFocus:null,topInput:null,topKeyDown:null,topKeyPress:null,topKeyUp:null,topLoad:null,topMouseDown:null,topMouseMove:null,topMouseOut:null,topMouseOver:null,topMouseUp:null,topPaste:null,topReset:null,topScroll:null,topSelectionChange:null,topSubmit:null,topTextInput:null,topTouchCancel:null,topTouchEnd:null,topTouchMove:null,topTouchStart:null,topWheel:null}),i={topLevelTypes:o,PropagationPhases:r};t.exports=i},{"./keyMirror":137}],17:[function(e,t){var n=e("./emptyFunction"),r={listen:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!1),{remove:function(){e.removeEventListener(t,n,!1)}}):e.attachEvent?(e.attachEvent("on"+t,n),{remove:function(){e.detachEvent("on"+t,n)}}):void 0},capture:function(e,t,r){return e.addEventListener?(e.addEventListener(t,r,!0),{remove:function(){e.removeEventListener(t,r,!0)}}):{remove:n}},registerDefault:function(){}};t.exports=r},{"./emptyFunction":113}],18:[function(e,t){"use strict";var n=e("./EventPluginRegistry"),r=e("./EventPluginUtils"),o=e("./accumulate"),i=e("./forEachAccumulated"),a=e("./invariant"),s=(e("./isEventSupported"),e("./monitorCodeUse"),{}),u=null,c=function(e){if(e){var t=r.executeDispatch,o=n.getPluginModuleForEvent(e);o&&o.executeDispatch&&(t=o.executeDispatch),r.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e)}},l=null,p={injection:{injectMount:r.injection.injectMount,injectInstanceHandle:function(e){l=e},getInstanceHandle:function(){return l},injectEventPluginOrder:n.injectEventPluginOrder,injectEventPluginsByName:n.injectEventPluginsByName},eventNameDispatchConfigs:n.eventNameDispatchConfigs,registrationNameModules:n.registrationNameModules,putListener:function(e,t,n){a(!n||"function"==typeof n);var r=s[t]||(s[t]={});r[e]=n},getListener:function(e,t){var n=s[t];return n&&n[e]},deleteListener:function(e,t){var n=s[t];n&&delete n[e]},deleteAllListeners:function(e){for(var t in s)delete s[t][e]},extractEvents:function(e,t,r,i){for(var a,s=n.plugins,u=0,c=s.length;c>u;u++){var l=s[u];if(l){var p=l.extractEvents(e,t,r,i);p&&(a=o(a,p))}}return a},enqueueEvents:function(e){e&&(u=o(u,e))},processEventQueue:function(){var e=u;u=null,i(e,c),a(!u)},__purge:function(){s={}},__getListenerBank:function(){return s}};t.exports=p},{"./EventPluginRegistry":19,"./EventPluginUtils":20,"./accumulate":103,"./forEachAccumulated":118,"./invariant":131,"./isEventSupported":132,"./monitorCodeUse":145}],19:[function(e,t){"use strict";function n(){if(a)for(var e in s){var t=s[e],n=a.indexOf(e);if(i(n>-1),!u.plugins[n]){i(t.extractEvents),u.plugins[n]=t;var o=t.eventTypes;for(var c in o)i(r(o[c],t,c))}}}function r(e,t,n){i(!u.eventNameDispatchConfigs.hasOwnProperty(n)),u.eventNameDispatchConfigs[n]=e;var r=e.phasedRegistrationNames;if(r){for(var a in r)if(r.hasOwnProperty(a)){var s=r[a];o(s,t,n)}return!0}return e.registrationName?(o(e.registrationName,t,n),!0):!1}function o(e,t,n){i(!u.registrationNameModules[e]),u.registrationNameModules[e]=t,u.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var i=e("./invariant"),a=null,s={},u={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},injectEventPluginOrder:function(e){i(!a),a=Array.prototype.slice.call(e),n()},injectEventPluginsByName:function(e){var t=!1;for(var r in e)if(e.hasOwnProperty(r)){var o=e[r];s.hasOwnProperty(r)&&s[r]===o||(i(!s[r]),s[r]=o,t=!0)}t&&n()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return u.registrationNameModules[t.registrationName]||null;for(var n in t.phasedRegistrationNames)if(t.phasedRegistrationNames.hasOwnProperty(n)){var r=u.registrationNameModules[t.phasedRegistrationNames[n]];if(r)return r}return null},_resetEventPlugins:function(){a=null;for(var e in s)s.hasOwnProperty(e)&&delete s[e];u.plugins.length=0;var t=u.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=u.registrationNameModules;for(var o in r)r.hasOwnProperty(o)&&delete r[o]}};t.exports=u},{"./invariant":131}],20:[function(e,t){"use strict";function n(e){return e===v.topMouseUp||e===v.topTouchEnd||e===v.topTouchCancel}function r(e){return e===v.topMouseMove||e===v.topTouchMove}function o(e){return e===v.topMouseDown||e===v.topTouchStart}function i(e,t){var n=e._dispatchListeners,r=e._dispatchIDs;if(Array.isArray(n))for(var o=0;o<n.length&&!e.isPropagationStopped();o++)t(e,n[o],r[o]);else n&&t(e,n,r)}function a(e,t,n){e.currentTarget=h.Mount.getNode(n);var r=t(e,n);return e.currentTarget=null,r}function s(e,t){i(e,t),e._dispatchListeners=null,e._dispatchIDs=null}function u(e){var t=e._dispatchListeners,n=e._dispatchIDs;if(Array.isArray(t)){for(var r=0;r<t.length&&!e.isPropagationStopped();r++)if(t[r](e,n[r]))return n[r]}else if(t&&t(e,n))return n;return null}function c(e){var t=u(e);return e._dispatchIDs=null,e._dispatchListeners=null,t}function l(e){var t=e._dispatchListeners,n=e._dispatchIDs;f(!Array.isArray(t));var r=t?t(e,n):null;return e._dispatchListeners=null,e._dispatchIDs=null,r}function p(e){return!!e._dispatchListeners}var d=e("./EventConstants"),f=e("./invariant"),h={Mount:null,injectMount:function(e){h.Mount=e}},v=d.topLevelTypes,m={isEndish:n,isMoveish:r,isStartish:o,executeDirectDispatch:l,executeDispatch:a,executeDispatchesInOrder:s,executeDispatchesInOrderStopAtTrue:c,hasDispatches:p,injection:h,useTouchEvents:!1};t.exports=m},{"./EventConstants":16,"./invariant":131}],21:[function(e,t){"use strict";function n(e,t,n){var r=t.dispatchConfig.phasedRegistrationNames[n];return v(e,r)}function r(e,t,r){var o=t?h.bubbled:h.captured,i=n(e,r,o);i&&(r._dispatchListeners=d(r._dispatchListeners,i),r._dispatchIDs=d(r._dispatchIDs,e))}function o(e){e&&e.dispatchConfig.phasedRegistrationNames&&p.injection.getInstanceHandle().traverseTwoPhase(e.dispatchMarker,r,e)}function i(e,t,n){if(n&&n.dispatchConfig.registrationName){var r=n.dispatchConfig.registrationName,o=v(e,r);o&&(n._dispatchListeners=d(n._dispatchListeners,o),n._dispatchIDs=d(n._dispatchIDs,e))}}function a(e){e&&e.dispatchConfig.registrationName&&i(e.dispatchMarker,null,e)}function s(e){f(e,o)}function u(e,t,n,r){p.injection.getInstanceHandle().traverseEnterLeave(n,r,i,e,t)}function c(e){f(e,a)}var l=e("./EventConstants"),p=e("./EventPluginHub"),d=e("./accumulate"),f=e("./forEachAccumulated"),h=l.PropagationPhases,v=p.getListener,m={accumulateTwoPhaseDispatches:s,accumulateDirectDispatches:c,accumulateEnterLeaveDispatches:u};t.exports=m},{"./EventConstants":16,"./EventPluginHub":18,"./accumulate":103,"./forEachAccumulated":118}],22:[function(e,t){"use strict";var n=!("undefined"==typeof window||!window.document||!window.document.createElement),r={canUseDOM:n,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:n&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:n&&!!window.screen,isInWorker:!n};t.exports=r},{}],23:[function(e,t){"use strict";var n,r=e("./DOMProperty"),o=e("./ExecutionEnvironment"),i=r.injection.MUST_USE_ATTRIBUTE,a=r.injection.MUST_USE_PROPERTY,s=r.injection.HAS_BOOLEAN_VALUE,u=r.injection.HAS_SIDE_EFFECTS,c=r.injection.HAS_NUMERIC_VALUE,l=r.injection.HAS_POSITIVE_NUMERIC_VALUE,p=r.injection.HAS_OVERLOADED_BOOLEAN_VALUE;if(o.canUseDOM){var d=document.implementation;n=d&&d.hasFeature&&d.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}var f={isCustomAttribute:RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/),Properties:{accept:null,accessKey:null,action:null,allowFullScreen:i|s,allowTransparency:i,alt:null,async:s,autoComplete:null,autoPlay:s,cellPadding:null,cellSpacing:null,charSet:i,checked:a|s,className:n?i:a,cols:i|l,colSpan:null,content:null,contentEditable:null,contextMenu:i,controls:a|s,coords:null,crossOrigin:null,data:null,dateTime:i,defer:s,dir:null,disabled:i|s,download:p,draggable:null,encType:null,form:i,formNoValidate:s,frameBorder:i,height:i,hidden:i|s,href:null,hrefLang:null,htmlFor:null,httpEquiv:null,icon:null,id:a,label:null,lang:null,list:null,loop:a|s,max:null,maxLength:i,mediaGroup:null,method:null,min:null,multiple:a|s,muted:a|s,name:null,noValidate:s,pattern:null,placeholder:null,poster:null,preload:null,radioGroup:null,readOnly:a|s,rel:null,required:s,role:i,rows:i|l,rowSpan:null,sandbox:null,scope:null,scrollLeft:a,scrolling:null,scrollTop:a,seamless:i|s,selected:a|s,shape:null,size:i|l,span:l,spellCheck:null,src:null,srcDoc:a,srcSet:null,start:c,step:null,style:null,tabIndex:null,target:null,title:null,type:null,useMap:null,value:a|u,width:i,wmode:i,autoCapitalize:null,autoCorrect:null,itemProp:i,itemScope:i|s,itemType:i,property:null},DOMAttributeNames:{className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{autoCapitalize:"autocapitalize",autoComplete:"autocomplete",autoCorrect:"autocorrect",autoFocus:"autofocus",autoPlay:"autoplay",encType:"enctype",hrefLang:"hreflang",radioGroup:"radiogroup",spellCheck:"spellcheck",srcDoc:"srcdoc",srcSet:"srcset"}};t.exports=f},{"./DOMProperty":11,"./ExecutionEnvironment":22}],24:[function(e,t){"use strict";var n=e("./ReactLink"),r=e("./ReactStateSetters"),o={linkState:function(e){return new n(this.state[e],r.createStateKeySetter(this,e))}};t.exports=o},{"./ReactLink":63,"./ReactStateSetters":79}],25:[function(e,t){"use strict";function n(e){u(null==e.props.checkedLink||null==e.props.valueLink)}function r(e){n(e),u(null==e.props.value&&null==e.props.onChange)}function o(e){n(e),u(null==e.props.checked&&null==e.props.onChange)}function i(e){this.props.valueLink.requestChange(e.target.value)}function a(e){this.props.checkedLink.requestChange(e.target.checked)}var s=e("./ReactPropTypes"),u=e("./invariant"),c={button:!0,checkbox:!0,image:!0,hidden:!0,radio:!0,reset:!0,submit:!0},l={Mixin:{propTypes:{value:function(e,t){return!e[t]||c[e.type]||e.onChange||e.readOnly||e.disabled?void 0:new Error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.")},checked:function(e,t){return!e[t]||e.onChange||e.readOnly||e.disabled?void 0:new Error("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.")},onChange:s.func}},getValue:function(e){return e.props.valueLink?(r(e),e.props.valueLink.value):e.props.value},getChecked:function(e){return e.props.checkedLink?(o(e),e.props.checkedLink.value):e.props.checked},getOnChange:function(e){return e.props.valueLink?(r(e),i):e.props.checkedLink?(o(e),a):e.props.onChange}};t.exports=l},{"./ReactPropTypes":73,"./invariant":131}],26:[function(e,t){"use strict";function n(e){e.remove()}var r=e("./ReactBrowserEventEmitter"),o=e("./accumulate"),i=e("./forEachAccumulated"),a=e("./invariant"),s={trapBubbledEvent:function(e,t){a(this.isMounted());var n=r.trapBubbledEvent(e,t,this.getDOMNode());this._localEventListeners=o(this._localEventListeners,n)},componentWillUnmount:function(){this._localEventListeners&&i(this._localEventListeners,n)}};t.exports=s},{"./ReactBrowserEventEmitter":31,"./accumulate":103,"./forEachAccumulated":118,"./invariant":131}],27:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./emptyFunction"),o=n.topLevelTypes,i={eventTypes:null,extractEvents:function(e,t,n,i){if(e===o.topTouchStart){var a=i.target;a&&!a.onclick&&(a.onclick=r)}}};t.exports=i},{"./EventConstants":16,"./emptyFunction":113}],28:[function(e,t){"use strict";var n=e("./invariant"),r=function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)},o=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},i=function(e,t,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,e,t,n),o}return new r(e,t,n)},a=function(e,t,n,r,o){var i=this;if(i.instancePool.length){var a=i.instancePool.pop();return i.call(a,e,t,n,r,o),a}return new i(e,t,n,r,o)},s=function(e){var t=this;n(e instanceof t),e.destructor&&e.destructor(),t.instancePool.length<t.poolSize&&t.instancePool.push(e)},u=10,c=r,l=function(e,t){var n=e;return n.instancePool=[],n.getPooled=t||c,n.poolSize||(n.poolSize=u),n.release=s,n},p={addPoolingTo:l,oneArgumentPooler:r,twoArgumentPooler:o,threeArgumentPooler:i,fiveArgumentPooler:a};t.exports=p},{"./invariant":131}],29:[function(e,t){"use strict";var n=e("./DOMPropertyOperations"),r=e("./EventPluginUtils"),o=e("./ReactChildren"),i=e("./ReactComponent"),a=e("./ReactCompositeComponent"),s=e("./ReactContext"),u=e("./ReactCurrentOwner"),c=e("./ReactDescriptor"),l=e("./ReactDOM"),p=e("./ReactDOMComponent"),d=e("./ReactDefaultInjection"),f=e("./ReactInstanceHandles"),h=e("./ReactMount"),v=e("./ReactMultiChild"),m=e("./ReactPerf"),g=e("./ReactPropTypes"),y=e("./ReactServerRendering"),C=e("./ReactTextComponent"),E=e("./onlyChild");d.inject();var R={Children:{map:o.map,forEach:o.forEach,count:o.count,only:E},DOM:l,PropTypes:g,initializeTouchEvents:function(e){r.useTouchEvents=e},createClass:a.createClass,createDescriptor:function(e){var t=Array.prototype.slice.call(arguments,1);return e.apply(null,t)},constructAndRenderComponent:h.constructAndRenderComponent,constructAndRenderComponentByID:h.constructAndRenderComponentByID,renderComponent:m.measure("React","renderComponent",h.renderComponent),renderComponentToString:y.renderComponentToString,renderComponentToStaticMarkup:y.renderComponentToStaticMarkup,unmountComponentAtNode:h.unmountComponentAtNode,isValidClass:c.isValidFactory,isValidComponent:c.isValidDescriptor,withContext:s.withContext,__internals:{Component:i,CurrentOwner:u,DOMComponent:p,DOMPropertyOperations:n,InstanceHandles:f,Mount:h,MultiChild:v,TextComponent:C}};R.version="0.11.1",t.exports=R},{"./DOMPropertyOperations":12,"./EventPluginUtils":20,"./ReactChildren":34,"./ReactComponent":35,"./ReactCompositeComponent":38,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactDOM":41,"./ReactDOMComponent":43,"./ReactDefaultInjection":53,"./ReactDescriptor":54,"./ReactInstanceHandles":62,"./ReactMount":65,"./ReactMultiChild":66,"./ReactPerf":69,"./ReactPropTypes":73,"./ReactServerRendering":77,"./ReactTextComponent":80,"./onlyChild":146}],30:[function(e,t){"use strict"; -var n=e("./ReactEmptyComponent"),r=e("./ReactMount"),o=e("./invariant"),i={getDOMNode:function(){return o(this.isMounted()),n.isNullComponentID(this._rootNodeID)?null:r.getNode(this._rootNodeID)}};t.exports=i},{"./ReactEmptyComponent":56,"./ReactMount":65,"./invariant":131}],31:[function(e,t){"use strict";function n(e){return Object.prototype.hasOwnProperty.call(e,h)||(e[h]=d++,l[e[h]]={}),l[e[h]]}var r=e("./EventConstants"),o=e("./EventPluginHub"),i=e("./EventPluginRegistry"),a=e("./ReactEventEmitterMixin"),s=e("./ViewportMetrics"),u=e("./isEventSupported"),c=e("./merge"),l={},p=!1,d=0,f={topBlur:"blur",topChange:"change",topClick:"click",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy",topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topFocus:"focus",topInput:"input",topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topScroll:"scroll",topSelectionChange:"selectionchange",topTextInput:"textInput",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove",topTouchStart:"touchstart",topWheel:"wheel"},h="_reactListenersID"+String(Math.random()).slice(2),v=c(a,{ReactEventListener:null,injection:{injectReactEventListener:function(e){e.setHandleTopLevel(v.handleTopLevel),v.ReactEventListener=e}},setEnabled:function(e){v.ReactEventListener&&v.ReactEventListener.setEnabled(e)},isEnabled:function(){return!(!v.ReactEventListener||!v.ReactEventListener.isEnabled())},listenTo:function(e,t){for(var o=t,a=n(o),s=i.registrationNameDependencies[e],c=r.topLevelTypes,l=0,p=s.length;p>l;l++){var d=s[l];a.hasOwnProperty(d)&&a[d]||(d===c.topWheel?u("wheel")?v.ReactEventListener.trapBubbledEvent(c.topWheel,"wheel",o):u("mousewheel")?v.ReactEventListener.trapBubbledEvent(c.topWheel,"mousewheel",o):v.ReactEventListener.trapBubbledEvent(c.topWheel,"DOMMouseScroll",o):d===c.topScroll?u("scroll",!0)?v.ReactEventListener.trapCapturedEvent(c.topScroll,"scroll",o):v.ReactEventListener.trapBubbledEvent(c.topScroll,"scroll",v.ReactEventListener.WINDOW_HANDLE):d===c.topFocus||d===c.topBlur?(u("focus",!0)?(v.ReactEventListener.trapCapturedEvent(c.topFocus,"focus",o),v.ReactEventListener.trapCapturedEvent(c.topBlur,"blur",o)):u("focusin")&&(v.ReactEventListener.trapBubbledEvent(c.topFocus,"focusin",o),v.ReactEventListener.trapBubbledEvent(c.topBlur,"focusout",o)),a[c.topBlur]=!0,a[c.topFocus]=!0):f.hasOwnProperty(d)&&v.ReactEventListener.trapBubbledEvent(d,f[d],o),a[d]=!0)}},trapBubbledEvent:function(e,t,n){return v.ReactEventListener.trapBubbledEvent(e,t,n)},trapCapturedEvent:function(e,t,n){return v.ReactEventListener.trapCapturedEvent(e,t,n)},ensureScrollValueMonitoring:function(){if(!p){var e=s.refreshScrollValues;v.ReactEventListener.monitorScrollValue(e),p=!0}},eventNameDispatchConfigs:o.eventNameDispatchConfigs,registrationNameModules:o.registrationNameModules,putListener:o.putListener,getListener:o.getListener,deleteListener:o.deleteListener,deleteAllListeners:o.deleteAllListeners});t.exports=v},{"./EventConstants":16,"./EventPluginHub":18,"./EventPluginRegistry":19,"./ReactEventEmitterMixin":58,"./ViewportMetrics":102,"./isEventSupported":132,"./merge":141}],32:[function(e,t){"use strict";var n=e("./React"),r=e("./ReactTransitionGroup"),o=e("./ReactCSSTransitionGroupChild"),i=n.createClass({displayName:"ReactCSSTransitionGroup",propTypes:{transitionName:n.PropTypes.string.isRequired,transitionEnter:n.PropTypes.bool,transitionLeave:n.PropTypes.bool},getDefaultProps:function(){return{transitionEnter:!0,transitionLeave:!0}},_wrapChild:function(e){return o({name:this.props.transitionName,enter:this.props.transitionEnter,leave:this.props.transitionLeave},e)},render:function(){return this.transferPropsTo(r({childFactory:this._wrapChild},this.props.children))}});t.exports=i},{"./React":29,"./ReactCSSTransitionGroupChild":33,"./ReactTransitionGroup":83}],33:[function(e,t){"use strict";var n=e("./React"),r=e("./CSSCore"),o=e("./ReactTransitionEvents"),i=e("./onlyChild"),a=17,s=n.createClass({displayName:"ReactCSSTransitionGroupChild",transition:function(e,t){var n=this.getDOMNode(),i=this.props.name+"-"+e,a=i+"-active",s=function(){r.removeClass(n,i),r.removeClass(n,a),o.removeEndEventListener(n,s),t&&t()};o.addEndEventListener(n,s),r.addClass(n,i),this.queueClass(a)},queueClass:function(e){this.classNameQueue.push(e),this.timeout||(this.timeout=setTimeout(this.flushClassNameQueue,a))},flushClassNameQueue:function(){this.isMounted()&&this.classNameQueue.forEach(r.addClass.bind(r,this.getDOMNode())),this.classNameQueue.length=0,this.timeout=null},componentWillMount:function(){this.classNameQueue=[]},componentWillUnmount:function(){this.timeout&&clearTimeout(this.timeout)},componentWillEnter:function(e){this.props.enter?this.transition("enter",e):e()},componentWillLeave:function(e){this.props.leave?this.transition("leave",e):e()},render:function(){return i(this.props.children)}});t.exports=s},{"./CSSCore":3,"./React":29,"./ReactTransitionEvents":82,"./onlyChild":146}],34:[function(e,t){"use strict";function n(e,t){this.forEachFunction=e,this.forEachContext=t}function r(e,t,n,r){var o=e;o.forEachFunction.call(o.forEachContext,t,r)}function o(e,t,o){if(null==e)return e;var i=n.getPooled(t,o);p(e,r,i),n.release(i)}function i(e,t,n){this.mapResult=e,this.mapFunction=t,this.mapContext=n}function a(e,t,n,r){var o=e,i=o.mapResult,a=!i.hasOwnProperty(n);if(a){var s=o.mapFunction.call(o.mapContext,t,r);i[n]=s}}function s(e,t,n){if(null==e)return e;var r={},o=i.getPooled(r,t,n);return p(e,a,o),i.release(o),r}function u(){return null}function c(e){return p(e,u,null)}var l=e("./PooledClass"),p=e("./traverseAllChildren"),d=(e("./warning"),l.twoArgumentPooler),f=l.threeArgumentPooler;l.addPoolingTo(n,d),l.addPoolingTo(i,f);var h={forEach:o,map:s,count:c};t.exports=h},{"./PooledClass":28,"./traverseAllChildren":151,"./warning":153}],35:[function(e,t){"use strict";var n=e("./ReactDescriptor"),r=e("./ReactOwner"),o=e("./ReactUpdates"),i=e("./invariant"),a=e("./keyMirror"),s=e("./merge"),u=a({MOUNTED:null,UNMOUNTED:null}),c=!1,l=null,p=null,d={injection:{injectEnvironment:function(e){i(!c),p=e.mountImageIntoNode,l=e.unmountIDFromEnvironment,d.BackendIDOperations=e.BackendIDOperations,c=!0}},LifeCycle:u,BackendIDOperations:null,Mixin:{isMounted:function(){return this._lifeCycleState===u.MOUNTED},setProps:function(e,t){var n=this._pendingDescriptor||this._descriptor;this.replaceProps(s(n.props,e),t)},replaceProps:function(e,t){i(this.isMounted()),i(0===this._mountDepth),this._pendingDescriptor=n.cloneAndReplaceProps(this._pendingDescriptor||this._descriptor,e),o.enqueueUpdate(this,t)},_setPropsInternal:function(e,t){var r=this._pendingDescriptor||this._descriptor;this._pendingDescriptor=n.cloneAndReplaceProps(r,s(r.props,e)),o.enqueueUpdate(this,t)},construct:function(e){this.props=e.props,this._owner=e._owner,this._lifeCycleState=u.UNMOUNTED,this._pendingCallbacks=null,this._descriptor=e,this._pendingDescriptor=null},mountComponent:function(e,t,n){i(!this.isMounted());var o=this._descriptor.props;if(null!=o.ref){var a=this._descriptor._owner;r.addComponentAsRefTo(this,o.ref,a)}this._rootNodeID=e,this._lifeCycleState=u.MOUNTED,this._mountDepth=n},unmountComponent:function(){i(this.isMounted());var e=this.props;null!=e.ref&&r.removeComponentAsRefFrom(this,e.ref,this._owner),l(this._rootNodeID),this._rootNodeID=null,this._lifeCycleState=u.UNMOUNTED},receiveComponent:function(e,t){i(this.isMounted()),this._pendingDescriptor=e,this.performUpdateIfNecessary(t)},performUpdateIfNecessary:function(e){if(null!=this._pendingDescriptor){var t=this._descriptor,n=this._pendingDescriptor;this._descriptor=n,this.props=n.props,this._owner=n._owner,this._pendingDescriptor=null,this.updateComponent(e,t)}},updateComponent:function(e,t){var n=this._descriptor;(n._owner!==t._owner||n.props.ref!==t.props.ref)&&(null!=t.props.ref&&r.removeComponentAsRefFrom(this,t.props.ref,t._owner),null!=n.props.ref&&r.addComponentAsRefTo(this,n.props.ref,n._owner))},mountComponentIntoNode:function(e,t,n){var r=o.ReactReconcileTransaction.getPooled();r.perform(this._mountComponentIntoNode,this,e,t,r,n),o.ReactReconcileTransaction.release(r)},_mountComponentIntoNode:function(e,t,n,r){var o=this.mountComponent(e,n,0);p(o,t,r)},isOwnedBy:function(e){return this._owner===e},getSiblingByRef:function(e){var t=this._owner;return t&&t.refs?t.refs[e]:null}}};t.exports=d},{"./ReactDescriptor":54,"./ReactOwner":68,"./ReactUpdates":84,"./invariant":131,"./keyMirror":137,"./merge":141}],36:[function(e,t){"use strict";var n=e("./ReactDOMIDOperations"),r=e("./ReactMarkupChecksum"),o=e("./ReactMount"),i=e("./ReactPerf"),a=e("./ReactReconcileTransaction"),s=e("./getReactRootElementInContainer"),u=e("./invariant"),c=e("./setInnerHTML"),l=1,p=9,d={ReactReconcileTransaction:a,BackendIDOperations:n,unmountIDFromEnvironment:function(e){o.purgeID(e)},mountImageIntoNode:i.measure("ReactComponentBrowserEnvironment","mountImageIntoNode",function(e,t,n){if(u(t&&(t.nodeType===l||t.nodeType===p)),n){if(r.canReuseMarkup(e,s(t)))return;u(t.nodeType!==p)}u(t.nodeType!==p),c(t,e)})};t.exports=d},{"./ReactDOMIDOperations":45,"./ReactMarkupChecksum":64,"./ReactMount":65,"./ReactPerf":69,"./ReactReconcileTransaction":75,"./getReactRootElementInContainer":125,"./invariant":131,"./setInnerHTML":147}],37:[function(e,t){"use strict";var n=e("./shallowEqual"),r={shouldComponentUpdate:function(e,t){return!n(this.props,e)||!n(this.state,t)}};t.exports=r},{"./shallowEqual":148}],38:[function(e,t){"use strict";function n(e){var t=e._owner||null;return t&&t.constructor&&t.constructor.displayName?" Check the render method of `"+t.constructor.displayName+"`.":""}function r(e,t){for(var n in t)t.hasOwnProperty(n)&&D("function"==typeof t[n])}function o(e,t){var n=_.hasOwnProperty(t)?_[t]:null;k.hasOwnProperty(t)&&D(n===S.OVERRIDE_BASE),e.hasOwnProperty(t)&&D(n===S.DEFINE_MANY||n===S.DEFINE_MANY_MERGED)}function i(e){var t=e._compositeLifeCycleState;D(e.isMounted()||t===N.MOUNTING),D(t!==N.RECEIVING_STATE),D(t!==N.UNMOUNTING)}function a(e,t){D(!h.isValidFactory(t)),D(!h.isValidDescriptor(t));var n=e.prototype;for(var r in t){var i=t[r];if(t.hasOwnProperty(r))if(o(n,r),I.hasOwnProperty(r))I[r](e,i);else{var a=_.hasOwnProperty(r),s=n.hasOwnProperty(r),u=i&&i.__reactDontBind,p="function"==typeof i,d=p&&!a&&!s&&!u;if(d)n.__reactAutoBindMap||(n.__reactAutoBindMap={}),n.__reactAutoBindMap[r]=i,n[r]=i;else if(s){var f=_[r];D(a&&(f===S.DEFINE_MANY_MERGED||f===S.DEFINE_MANY)),f===S.DEFINE_MANY_MERGED?n[r]=c(n[r],i):f===S.DEFINE_MANY&&(n[r]=l(n[r],i))}else n[r]=i}}}function s(e,t){if(t)for(var n in t){var r=t[n];if(t.hasOwnProperty(n)){var o=n in e,i=r;if(o){var a=e[n],s=typeof a,u=typeof r;D("function"===s&&"function"===u),i=l(a,r)}e[n]=i}}}function u(e,t){return D(e&&t&&"object"==typeof e&&"object"==typeof t),P(t,function(t,n){D(void 0===e[n]),e[n]=t}),e}function c(e,t){return function(){var n=e.apply(this,arguments),r=t.apply(this,arguments);return null==n?r:null==r?n:u(n,r)}}function l(e,t){return function(){e.apply(this,arguments),t.apply(this,arguments)}}var p=e("./ReactComponent"),d=e("./ReactContext"),f=e("./ReactCurrentOwner"),h=e("./ReactDescriptor"),v=(e("./ReactDescriptorValidator"),e("./ReactEmptyComponent")),m=e("./ReactErrorUtils"),g=e("./ReactOwner"),y=e("./ReactPerf"),C=e("./ReactPropTransferer"),E=e("./ReactPropTypeLocations"),R=(e("./ReactPropTypeLocationNames"),e("./ReactUpdates")),M=e("./instantiateReactComponent"),D=e("./invariant"),x=e("./keyMirror"),b=e("./merge"),O=e("./mixInto"),P=(e("./monitorCodeUse"),e("./mapObject")),T=e("./shouldUpdateReactComponent"),S=(e("./warning"),x({DEFINE_ONCE:null,DEFINE_MANY:null,OVERRIDE_BASE:null,DEFINE_MANY_MERGED:null})),w=[],_={mixins:S.DEFINE_MANY,statics:S.DEFINE_MANY,propTypes:S.DEFINE_MANY,contextTypes:S.DEFINE_MANY,childContextTypes:S.DEFINE_MANY,getDefaultProps:S.DEFINE_MANY_MERGED,getInitialState:S.DEFINE_MANY_MERGED,getChildContext:S.DEFINE_MANY_MERGED,render:S.DEFINE_ONCE,componentWillMount:S.DEFINE_MANY,componentDidMount:S.DEFINE_MANY,componentWillReceiveProps:S.DEFINE_MANY,shouldComponentUpdate:S.DEFINE_ONCE,componentWillUpdate:S.DEFINE_MANY,componentDidUpdate:S.DEFINE_MANY,componentWillUnmount:S.DEFINE_MANY,updateComponent:S.OVERRIDE_BASE},I={displayName:function(e,t){e.displayName=t},mixins:function(e,t){if(t)for(var n=0;n<t.length;n++)a(e,t[n])},childContextTypes:function(e,t){r(e,t,E.childContext),e.childContextTypes=b(e.childContextTypes,t)},contextTypes:function(e,t){r(e,t,E.context),e.contextTypes=b(e.contextTypes,t)},getDefaultProps:function(e,t){e.getDefaultProps=e.getDefaultProps?c(e.getDefaultProps,t):t},propTypes:function(e,t){r(e,t,E.prop),e.propTypes=b(e.propTypes,t)},statics:function(e,t){s(e,t)}},N=x({MOUNTING:null,UNMOUNTING:null,RECEIVING_PROPS:null,RECEIVING_STATE:null}),k={construct:function(){p.Mixin.construct.apply(this,arguments),g.Mixin.construct.apply(this,arguments),this.state=null,this._pendingState=null,this.context=null,this._compositeLifeCycleState=null},isMounted:function(){return p.Mixin.isMounted.call(this)&&this._compositeLifeCycleState!==N.MOUNTING},mountComponent:y.measure("ReactCompositeComponent","mountComponent",function(e,t,n){p.Mixin.mountComponent.call(this,e,t,n),this._compositeLifeCycleState=N.MOUNTING,this.__reactAutoBindMap&&this._bindAutoBindMethods(),this.context=this._processContext(this._descriptor._context),this.props=this._processProps(this.props),this.state=this.getInitialState?this.getInitialState():null,D("object"==typeof this.state&&!Array.isArray(this.state)),this._pendingState=null,this._pendingForceUpdate=!1,this.componentWillMount&&(this.componentWillMount(),this._pendingState&&(this.state=this._pendingState,this._pendingState=null)),this._renderedComponent=M(this._renderValidatedComponent()),this._compositeLifeCycleState=null;var r=this._renderedComponent.mountComponent(e,t,n+1);return this.componentDidMount&&t.getReactMountReady().enqueue(this.componentDidMount,this),r}),unmountComponent:function(){this._compositeLifeCycleState=N.UNMOUNTING,this.componentWillUnmount&&this.componentWillUnmount(),this._compositeLifeCycleState=null,this._renderedComponent.unmountComponent(),this._renderedComponent=null,p.Mixin.unmountComponent.call(this)},setState:function(e,t){D("object"==typeof e||null==e),this.replaceState(b(this._pendingState||this.state,e),t)},replaceState:function(e,t){i(this),this._pendingState=e,this._compositeLifeCycleState!==N.MOUNTING&&R.enqueueUpdate(this,t)},_processContext:function(e){var t=null,n=this.constructor.contextTypes;if(n){t={};for(var r in n)t[r]=e[r]}return t},_processChildContext:function(e){var t=this.getChildContext&&this.getChildContext();if(this.constructor.displayName||"ReactCompositeComponent",t){D("object"==typeof this.constructor.childContextTypes);for(var n in t)D(n in this.constructor.childContextTypes);return b(e,t)}return e},_processProps:function(e){var t,n=this.constructor.defaultProps;if(n){t=b(e);for(var r in n)"undefined"==typeof t[r]&&(t[r]=n[r])}else t=e;return t},_checkPropTypes:function(e,t,r){var o=this.constructor.displayName;for(var i in e)if(e.hasOwnProperty(i)){var a=e[i](t,i,o,r);a instanceof Error&&n(this)}},performUpdateIfNecessary:function(e){var t=this._compositeLifeCycleState;if(t!==N.MOUNTING&&t!==N.RECEIVING_PROPS&&(null!=this._pendingDescriptor||null!=this._pendingState||this._pendingForceUpdate)){var n=this.context,r=this.props,o=this._descriptor;null!=this._pendingDescriptor&&(o=this._pendingDescriptor,n=this._processContext(o._context),r=this._processProps(o.props),this._pendingDescriptor=null,this._compositeLifeCycleState=N.RECEIVING_PROPS,this.componentWillReceiveProps&&this.componentWillReceiveProps(r,n)),this._compositeLifeCycleState=N.RECEIVING_STATE;var i=this._pendingState||this.state;this._pendingState=null;try{var a=this._pendingForceUpdate||!this.shouldComponentUpdate||this.shouldComponentUpdate(r,i,n);a?(this._pendingForceUpdate=!1,this._performComponentUpdate(o,r,i,n,e)):(this._descriptor=o,this.props=r,this.state=i,this.context=n,this._owner=o._owner)}finally{this._compositeLifeCycleState=null}}},_performComponentUpdate:function(e,t,n,r,o){var i=this._descriptor,a=this.props,s=this.state,u=this.context;this.componentWillUpdate&&this.componentWillUpdate(t,n,r),this._descriptor=e,this.props=t,this.state=n,this.context=r,this._owner=e._owner,this.updateComponent(o,i),this.componentDidUpdate&&o.getReactMountReady().enqueue(this.componentDidUpdate.bind(this,a,s,u),this)},receiveComponent:function(e,t){(e!==this._descriptor||null==e._owner)&&p.Mixin.receiveComponent.call(this,e,t)},updateComponent:y.measure("ReactCompositeComponent","updateComponent",function(e,t){p.Mixin.updateComponent.call(this,e,t);var n=this._renderedComponent,r=n._descriptor,o=this._renderValidatedComponent();if(T(r,o))n.receiveComponent(o,e);else{var i=this._rootNodeID,a=n._rootNodeID;n.unmountComponent(),this._renderedComponent=M(o);var s=this._renderedComponent.mountComponent(i,e,this._mountDepth+1);p.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(a,s)}}),forceUpdate:function(e){var t=this._compositeLifeCycleState;D(this.isMounted()||t===N.MOUNTING),D(t!==N.RECEIVING_STATE&&t!==N.UNMOUNTING),this._pendingForceUpdate=!0,R.enqueueUpdate(this,e)},_renderValidatedComponent:y.measure("ReactCompositeComponent","_renderValidatedComponent",function(){var e,t=d.current;d.current=this._processChildContext(this._descriptor._context),f.current=this;try{e=this.render(),null===e||e===!1?(e=v.getEmptyComponent(),v.registerNullComponentID(this._rootNodeID)):v.deregisterNullComponentID(this._rootNodeID)}finally{d.current=t,f.current=null}return D(h.isValidDescriptor(e)),e}),_bindAutoBindMethods:function(){for(var e in this.__reactAutoBindMap)if(this.__reactAutoBindMap.hasOwnProperty(e)){var t=this.__reactAutoBindMap[e];this[e]=this._bindAutoBindMethod(m.guard(t,this.constructor.displayName+"."+e))}},_bindAutoBindMethod:function(e){var t=this,n=function(){return e.apply(t,arguments)};return n}},A=function(){};O(A,p.Mixin),O(A,g.Mixin),O(A,C.Mixin),O(A,k);var L={LifeCycle:N,Base:A,createClass:function(e){var t=function(e,t){this.construct(e,t)};t.prototype=new A,t.prototype.constructor=t,w.forEach(a.bind(null,t)),a(t,e),t.getDefaultProps&&(t.defaultProps=t.getDefaultProps()),D(t.prototype.render);for(var n in _)t.prototype[n]||(t.prototype[n]=null);var r=h.createFactory(t);return r},injection:{injectMixin:function(e){w.push(e)}}};t.exports=L},{"./ReactComponent":35,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactDescriptor":54,"./ReactDescriptorValidator":55,"./ReactEmptyComponent":56,"./ReactErrorUtils":57,"./ReactOwner":68,"./ReactPerf":69,"./ReactPropTransferer":70,"./ReactPropTypeLocationNames":71,"./ReactPropTypeLocations":72,"./ReactUpdates":84,"./instantiateReactComponent":130,"./invariant":131,"./keyMirror":137,"./mapObject":139,"./merge":141,"./mixInto":144,"./monitorCodeUse":145,"./shouldUpdateReactComponent":149,"./warning":153}],39:[function(e,t){"use strict";var n=e("./merge"),r={current:{},withContext:function(e,t){var o,i=r.current;r.current=n(i,e);try{o=t()}finally{r.current=i}return o}};t.exports=r},{"./merge":141}],40:[function(e,t){"use strict";var n={current:null};t.exports=n},{}],41:[function(e,t){"use strict";function n(e,t){var n=function(e){this.construct(e)};n.prototype=new o(t,e),n.prototype.constructor=n,n.displayName=t;var i=r.createFactory(n);return i}var r=e("./ReactDescriptor"),o=(e("./ReactDescriptorValidator"),e("./ReactDOMComponent")),i=e("./mergeInto"),a=e("./mapObject"),s=a({a:!1,abbr:!1,address:!1,area:!0,article:!1,aside:!1,audio:!1,b:!1,base:!0,bdi:!1,bdo:!1,big:!1,blockquote:!1,body:!1,br:!0,button:!1,canvas:!1,caption:!1,cite:!1,code:!1,col:!0,colgroup:!1,data:!1,datalist:!1,dd:!1,del:!1,details:!1,dfn:!1,div:!1,dl:!1,dt:!1,em:!1,embed:!0,fieldset:!1,figcaption:!1,figure:!1,footer:!1,form:!1,h1:!1,h2:!1,h3:!1,h4:!1,h5:!1,h6:!1,head:!1,header:!1,hr:!0,html:!1,i:!1,iframe:!1,img:!0,input:!0,ins:!1,kbd:!1,keygen:!0,label:!1,legend:!1,li:!1,link:!0,main:!1,map:!1,mark:!1,menu:!1,menuitem:!1,meta:!0,meter:!1,nav:!1,noscript:!1,object:!1,ol:!1,optgroup:!1,option:!1,output:!1,p:!1,param:!0,pre:!1,progress:!1,q:!1,rp:!1,rt:!1,ruby:!1,s:!1,samp:!1,script:!1,section:!1,select:!1,small:!1,source:!0,span:!1,strong:!1,style:!1,sub:!1,summary:!1,sup:!1,table:!1,tbody:!1,td:!1,textarea:!1,tfoot:!1,th:!1,thead:!1,time:!1,title:!1,tr:!1,track:!0,u:!1,ul:!1,"var":!1,video:!1,wbr:!0,circle:!1,defs:!1,ellipse:!1,g:!1,line:!1,linearGradient:!1,mask:!1,path:!1,pattern:!1,polygon:!1,polyline:!1,radialGradient:!1,rect:!1,stop:!1,svg:!1,text:!1,tspan:!1},n),u={injectComponentClasses:function(e){i(s,e)}};s.injection=u,t.exports=s},{"./ReactDOMComponent":43,"./ReactDescriptor":54,"./ReactDescriptorValidator":55,"./mapObject":139,"./mergeInto":143}],42:[function(e,t){"use strict";var n=e("./AutoFocusMixin"),r=e("./ReactBrowserComponentMixin"),o=e("./ReactCompositeComponent"),i=e("./ReactDOM"),a=e("./keyMirror"),s=i.button,u=a({onClick:!0,onDoubleClick:!0,onMouseDown:!0,onMouseMove:!0,onMouseUp:!0,onClickCapture:!0,onDoubleClickCapture:!0,onMouseDownCapture:!0,onMouseMoveCapture:!0,onMouseUpCapture:!0}),c=o.createClass({displayName:"ReactDOMButton",mixins:[n,r],render:function(){var e={};for(var t in this.props)!this.props.hasOwnProperty(t)||this.props.disabled&&u[t]||(e[t]=this.props[t]);return s(e,this.props.children)}});t.exports=c},{"./AutoFocusMixin":1,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./keyMirror":137}],43:[function(e,t){"use strict";function n(e){e&&(v(null==e.children||null==e.dangerouslySetInnerHTML),v(null==e.style||"object"==typeof e.style))}function r(e,t,n,r){var o=p.findReactContainerForID(e);if(o){var i=o.nodeType===x?o.ownerDocument:o;E(t,i)}r.getPutListenerQueue().enqueuePutListener(e,t,n)}function o(e,t){this._tagOpen="<"+e,this._tagClose=t?"":"</"+e+">",this.tagName=e.toUpperCase()}var i=e("./CSSPropertyOperations"),a=e("./DOMProperty"),s=e("./DOMPropertyOperations"),u=e("./ReactBrowserComponentMixin"),c=e("./ReactComponent"),l=e("./ReactBrowserEventEmitter"),p=e("./ReactMount"),d=e("./ReactMultiChild"),f=e("./ReactPerf"),h=e("./escapeTextForBrowser"),v=e("./invariant"),m=e("./keyOf"),g=e("./merge"),y=e("./mixInto"),C=l.deleteListener,E=l.listenTo,R=l.registrationNameModules,M={string:!0,number:!0},D=m({style:null}),x=1;o.Mixin={mountComponent:f.measure("ReactDOMComponent","mountComponent",function(e,t,r){return c.Mixin.mountComponent.call(this,e,t,r),n(this.props),this._createOpenTagMarkupAndPutListeners(t)+this._createContentMarkup(t)+this._tagClose}),_createOpenTagMarkupAndPutListeners:function(e){var t=this.props,n=this._tagOpen;for(var o in t)if(t.hasOwnProperty(o)){var a=t[o];if(null!=a)if(R.hasOwnProperty(o))r(this._rootNodeID,o,a,e);else{o===D&&(a&&(a=t.style=g(t.style)),a=i.createMarkupForStyles(a));var u=s.createMarkupForProperty(o,a);u&&(n+=" "+u)}}if(e.renderToStaticMarkup)return n+">";var c=s.createMarkupForID(this._rootNodeID);return n+" "+c+">"},_createContentMarkup:function(e){var t=this.props.dangerouslySetInnerHTML;if(null!=t){if(null!=t.__html)return t.__html}else{var n=M[typeof this.props.children]?this.props.children:null,r=null!=n?null:this.props.children;if(null!=n)return h(n);if(null!=r){var o=this.mountChildren(r,e);return o.join("")}}return""},receiveComponent:function(e,t){(e!==this._descriptor||null==e._owner)&&c.Mixin.receiveComponent.call(this,e,t)},updateComponent:f.measure("ReactDOMComponent","updateComponent",function(e,t){n(this._descriptor.props),c.Mixin.updateComponent.call(this,e,t),this._updateDOMProperties(t.props,e),this._updateDOMChildren(t.props,e)}),_updateDOMProperties:function(e,t){var n,o,i,s=this.props;for(n in e)if(!s.hasOwnProperty(n)&&e.hasOwnProperty(n))if(n===D){var u=e[n];for(o in u)u.hasOwnProperty(o)&&(i=i||{},i[o]="")}else R.hasOwnProperty(n)?C(this._rootNodeID,n):(a.isStandardName[n]||a.isCustomAttribute(n))&&c.BackendIDOperations.deletePropertyByID(this._rootNodeID,n);for(n in s){var l=s[n],p=e[n];if(s.hasOwnProperty(n)&&l!==p)if(n===D)if(l&&(l=s.style=g(l)),p){for(o in p)!p.hasOwnProperty(o)||l&&l.hasOwnProperty(o)||(i=i||{},i[o]="");for(o in l)l.hasOwnProperty(o)&&p[o]!==l[o]&&(i=i||{},i[o]=l[o])}else i=l;else R.hasOwnProperty(n)?r(this._rootNodeID,n,l,t):(a.isStandardName[n]||a.isCustomAttribute(n))&&c.BackendIDOperations.updatePropertyByID(this._rootNodeID,n,l)}i&&c.BackendIDOperations.updateStylesByID(this._rootNodeID,i)},_updateDOMChildren:function(e,t){var n=this.props,r=M[typeof e.children]?e.children:null,o=M[typeof n.children]?n.children:null,i=e.dangerouslySetInnerHTML&&e.dangerouslySetInnerHTML.__html,a=n.dangerouslySetInnerHTML&&n.dangerouslySetInnerHTML.__html,s=null!=r?null:e.children,u=null!=o?null:n.children,l=null!=r||null!=i,p=null!=o||null!=a;null!=s&&null==u?this.updateChildren(null,t):l&&!p&&this.updateTextContent(""),null!=o?r!==o&&this.updateTextContent(""+o):null!=a?i!==a&&c.BackendIDOperations.updateInnerHTMLByID(this._rootNodeID,a):null!=u&&this.updateChildren(u,t)},unmountComponent:function(){this.unmountChildren(),l.deleteAllListeners(this._rootNodeID),c.Mixin.unmountComponent.call(this)}},y(o,c.Mixin),y(o,o.Mixin),y(o,d.Mixin),y(o,u),t.exports=o},{"./CSSPropertyOperations":5,"./DOMProperty":11,"./DOMPropertyOperations":12,"./ReactBrowserComponentMixin":30,"./ReactBrowserEventEmitter":31,"./ReactComponent":35,"./ReactMount":65,"./ReactMultiChild":66,"./ReactPerf":69,"./escapeTextForBrowser":115,"./invariant":131,"./keyOf":138,"./merge":141,"./mixInto":144}],44:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./LocalEventTrapMixin"),o=e("./ReactBrowserComponentMixin"),i=e("./ReactCompositeComponent"),a=e("./ReactDOM"),s=a.form,u=i.createClass({displayName:"ReactDOMForm",mixins:[o,r],render:function(){return this.transferPropsTo(s(null,this.props.children))},componentDidMount:function(){this.trapBubbledEvent(n.topLevelTypes.topReset,"reset"),this.trapBubbledEvent(n.topLevelTypes.topSubmit,"submit")}});t.exports=u},{"./EventConstants":16,"./LocalEventTrapMixin":26,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41}],45:[function(e,t){"use strict";var n=e("./CSSPropertyOperations"),r=e("./DOMChildrenOperations"),o=e("./DOMPropertyOperations"),i=e("./ReactMount"),a=e("./ReactPerf"),s=e("./invariant"),u=e("./setInnerHTML"),c={dangerouslySetInnerHTML:"`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.",style:"`style` must be set using `updateStylesByID()`."},l={updatePropertyByID:a.measure("ReactDOMIDOperations","updatePropertyByID",function(e,t,n){var r=i.getNode(e);s(!c.hasOwnProperty(t)),null!=n?o.setValueForProperty(r,t,n):o.deleteValueForProperty(r,t)}),deletePropertyByID:a.measure("ReactDOMIDOperations","deletePropertyByID",function(e,t,n){var r=i.getNode(e);s(!c.hasOwnProperty(t)),o.deleteValueForProperty(r,t,n)}),updateStylesByID:a.measure("ReactDOMIDOperations","updateStylesByID",function(e,t){var r=i.getNode(e);n.setValueForStyles(r,t)}),updateInnerHTMLByID:a.measure("ReactDOMIDOperations","updateInnerHTMLByID",function(e,t){var n=i.getNode(e);u(n,t)}),updateTextContentByID:a.measure("ReactDOMIDOperations","updateTextContentByID",function(e,t){var n=i.getNode(e);r.updateTextContent(n,t)}),dangerouslyReplaceNodeWithMarkupByID:a.measure("ReactDOMIDOperations","dangerouslyReplaceNodeWithMarkupByID",function(e,t){var n=i.getNode(e);r.dangerouslyReplaceNodeWithMarkup(n,t)}),dangerouslyProcessChildrenUpdates:a.measure("ReactDOMIDOperations","dangerouslyProcessChildrenUpdates",function(e,t){for(var n=0;n<e.length;n++)e[n].parentNode=i.getNode(e[n].parentID);r.processUpdates(e,t)})};t.exports=l},{"./CSSPropertyOperations":5,"./DOMChildrenOperations":10,"./DOMPropertyOperations":12,"./ReactMount":65,"./ReactPerf":69,"./invariant":131,"./setInnerHTML":147}],46:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./LocalEventTrapMixin"),o=e("./ReactBrowserComponentMixin"),i=e("./ReactCompositeComponent"),a=e("./ReactDOM"),s=a.img,u=i.createClass({displayName:"ReactDOMImg",tagName:"IMG",mixins:[o,r],render:function(){return s(this.props)},componentDidMount:function(){this.trapBubbledEvent(n.topLevelTypes.topLoad,"load"),this.trapBubbledEvent(n.topLevelTypes.topError,"error")}});t.exports=u},{"./EventConstants":16,"./LocalEventTrapMixin":26,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41}],47:[function(e,t){"use strict";var n=e("./AutoFocusMixin"),r=e("./DOMPropertyOperations"),o=e("./LinkedValueUtils"),i=e("./ReactBrowserComponentMixin"),a=e("./ReactCompositeComponent"),s=e("./ReactDOM"),u=e("./ReactMount"),c=e("./invariant"),l=e("./merge"),p=s.input,d={},f=a.createClass({displayName:"ReactDOMInput",mixins:[n,o.Mixin,i],getInitialState:function(){var e=this.props.defaultValue;return{checked:this.props.defaultChecked||!1,value:null!=e?e:null}},shouldComponentUpdate:function(){return!this._isChanging},render:function(){var e=l(this.props);e.defaultChecked=null,e.defaultValue=null;var t=o.getValue(this);e.value=null!=t?t:this.state.value;var n=o.getChecked(this);return e.checked=null!=n?n:this.state.checked,e.onChange=this._handleChange,p(e,this.props.children)},componentDidMount:function(){var e=u.getID(this.getDOMNode());d[e]=this},componentWillUnmount:function(){var e=this.getDOMNode(),t=u.getID(e);delete d[t]},componentDidUpdate:function(){var e=this.getDOMNode();null!=this.props.checked&&r.setValueForProperty(e,"checked",this.props.checked||!1);var t=o.getValue(this);null!=t&&r.setValueForProperty(e,"value",""+t)},_handleChange:function(e){var t,n=o.getOnChange(this);n&&(this._isChanging=!0,t=n.call(this,e),this._isChanging=!1),this.setState({checked:e.target.checked,value:e.target.value});var r=this.props.name;if("radio"===this.props.type&&null!=r){for(var i=this.getDOMNode(),a=i;a.parentNode;)a=a.parentNode;for(var s=a.querySelectorAll("input[name="+JSON.stringify(""+r)+'][type="radio"]'),l=0,p=s.length;p>l;l++){var f=s[l];if(f!==i&&f.form===i.form){var h=u.getID(f);c(h);var v=d[h];c(v),v.setState({checked:!1})}}}return t}});t.exports=f},{"./AutoFocusMixin":1,"./DOMPropertyOperations":12,"./LinkedValueUtils":25,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./ReactMount":65,"./invariant":131,"./merge":141}],48:[function(e,t){"use strict";var n=e("./ReactBrowserComponentMixin"),r=e("./ReactCompositeComponent"),o=e("./ReactDOM"),i=(e("./warning"),o.option),a=r.createClass({displayName:"ReactDOMOption",mixins:[n],componentWillMount:function(){},render:function(){return i(this.props,this.props.children)}});t.exports=a},{"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./warning":153}],49:[function(e,t){"use strict";function n(e,t){if(null!=e[t])if(e.multiple){if(!Array.isArray(e[t]))return new Error("The `"+t+"` prop supplied to <select> must be an array if `multiple` is true.")}else if(Array.isArray(e[t]))return new Error("The `"+t+"` prop supplied to <select> must be a scalar value if `multiple` is false.")}function r(e,t){var n,r,o,i=e.props.multiple,a=null!=t?t:e.state.value,s=e.getDOMNode().options;if(i)for(n={},r=0,o=a.length;o>r;++r)n[""+a[r]]=!0;else n=""+a;for(r=0,o=s.length;o>r;r++){var u=i?n.hasOwnProperty(s[r].value):s[r].value===n;u!==s[r].selected&&(s[r].selected=u)}}var o=e("./AutoFocusMixin"),i=e("./LinkedValueUtils"),a=e("./ReactBrowserComponentMixin"),s=e("./ReactCompositeComponent"),u=e("./ReactDOM"),c=e("./merge"),l=u.select,p=s.createClass({displayName:"ReactDOMSelect",mixins:[o,i.Mixin,a],propTypes:{defaultValue:n,value:n},getInitialState:function(){return{value:this.props.defaultValue||(this.props.multiple?[]:"")} +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.React=e()}}(function(){return function e(t,n,r){function o(a,s){if(!n[a]){if(!t[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);throw new Error("Cannot find module '"+a+"'")}var c=n[a]={exports:{}};t[a][0].call(c.exports,function(e){var n=t[a][1][e];return o(n?n:e)},c,c.exports,e,t,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a<r.length;a++)o(r[a]);return o}({1:[function(e,t){"use strict";var n=e("./focusNode"),r={componentDidMount:function(){this.props.autoFocus&&n(this.getDOMNode())}};t.exports=r},{"./focusNode":117}],2:[function(e,t){"use strict";function n(){var e=window.opera;return"object"==typeof e&&"function"==typeof e.version&&parseInt(e.version(),10)<=12}function r(e){return(e.ctrlKey||e.altKey||e.metaKey)&&!(e.ctrlKey&&e.altKey)}var o=e("./EventConstants"),i=e("./EventPropagators"),a=e("./ExecutionEnvironment"),s=e("./SyntheticInputEvent"),u=e("./keyOf"),c=a.canUseDOM&&"TextEvent"in window&&!("documentMode"in document||n()),l=32,p=String.fromCharCode(l),d=o.topLevelTypes,f={beforeInput:{phasedRegistrationNames:{bubbled:u({onBeforeInput:null}),captured:u({onBeforeInputCapture:null})},dependencies:[d.topCompositionEnd,d.topKeyPress,d.topTextInput,d.topPaste]}},h=null,v={eventTypes:f,extractEvents:function(e,t,n,o){var a;if(c)switch(e){case d.topKeyPress:var u=o.which;if(u!==l)return;a=String.fromCharCode(u);break;case d.topTextInput:if(a=o.data,a===p)return;break;default:return}else{switch(e){case d.topPaste:h=null;break;case d.topKeyPress:o.which&&!r(o)&&(h=String.fromCharCode(o.which));break;case d.topCompositionEnd:h=o.data}if(null===h)return;a=h}if(a){var v=s.getPooled(f.beforeInput,n,o);return v.data=a,h=null,i.accumulateTwoPhaseDispatches(v),v}}};t.exports=v},{"./EventConstants":16,"./EventPropagators":21,"./ExecutionEnvironment":22,"./SyntheticInputEvent":95,"./keyOf":138}],3:[function(e,t){var n=e("./invariant"),r={addClass:function(e,t){return n(!/\s/.test(t)),t&&(e.classList?e.classList.add(t):r.hasClass(e,t)||(e.className=e.className+" "+t)),e},removeClass:function(e,t){return n(!/\s/.test(t)),t&&(e.classList?e.classList.remove(t):r.hasClass(e,t)&&(e.className=e.className.replace(new RegExp("(^|\\s)"+t+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,""))),e},conditionClass:function(e,t,n){return(n?r.addClass:r.removeClass)(e,t)},hasClass:function(e,t){return n(!/\s/.test(t)),e.classList?!!t&&e.classList.contains(t):(" "+e.className+" ").indexOf(" "+t+" ")>-1}};t.exports=r},{"./invariant":131}],4:[function(e,t){"use strict";function n(e,t){return e+t.charAt(0).toUpperCase()+t.substring(1)}var r={columnCount:!0,fillOpacity:!0,flex:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},o=["Webkit","ms","Moz","O"];Object.keys(r).forEach(function(e){o.forEach(function(t){r[n(t,e)]=r[e]})});var i={background:{backgroundImage:!0,backgroundPosition:!0,backgroundRepeat:!0,backgroundColor:!0},border:{borderWidth:!0,borderStyle:!0,borderColor:!0},borderBottom:{borderBottomWidth:!0,borderBottomStyle:!0,borderBottomColor:!0},borderLeft:{borderLeftWidth:!0,borderLeftStyle:!0,borderLeftColor:!0},borderRight:{borderRightWidth:!0,borderRightStyle:!0,borderRightColor:!0},borderTop:{borderTopWidth:!0,borderTopStyle:!0,borderTopColor:!0},font:{fontStyle:!0,fontVariant:!0,fontWeight:!0,fontSize:!0,lineHeight:!0,fontFamily:!0}},a={isUnitlessNumber:r,shorthandPropertyExpansions:i};t.exports=a},{}],5:[function(e,t){"use strict";var n=e("./CSSProperty"),r=e("./dangerousStyleValue"),o=e("./hyphenateStyleName"),i=e("./memoizeStringOnly"),a=i(function(e){return o(e)}),s={createMarkupForStyles:function(e){var t="";for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];null!=o&&(t+=a(n)+":",t+=r(n,o)+";")}return t||null},setValueForStyles:function(e,t){var o=e.style;for(var i in t)if(t.hasOwnProperty(i)){var a=r(i,t[i]);if(a)o[i]=a;else{var s=n.shorthandPropertyExpansions[i];if(s)for(var u in s)o[u]="";else o[i]=""}}}};t.exports=s},{"./CSSProperty":4,"./dangerousStyleValue":112,"./hyphenateStyleName":129,"./memoizeStringOnly":140}],6:[function(e,t){"use strict";function n(){this._callbacks=null,this._contexts=null}var r=e("./PooledClass"),o=e("./invariant"),i=e("./mixInto");i(n,{enqueue:function(e,t){this._callbacks=this._callbacks||[],this._contexts=this._contexts||[],this._callbacks.push(e),this._contexts.push(t)},notifyAll:function(){var e=this._callbacks,t=this._contexts;if(e){o(e.length===t.length),this._callbacks=null,this._contexts=null;for(var n=0,r=e.length;r>n;n++)e[n].call(t[n]);e.length=0,t.length=0}},reset:function(){this._callbacks=null,this._contexts=null},destructor:function(){this.reset()}}),r.addPoolingTo(n),t.exports=n},{"./PooledClass":28,"./invariant":131,"./mixInto":144}],7:[function(e,t){"use strict";function n(e){return"SELECT"===e.nodeName||"INPUT"===e.nodeName&&"file"===e.type}function r(e){var t=M.getPooled(P.change,S,e);C.accumulateTwoPhaseDispatches(t),R.batchedUpdates(o,t)}function o(e){y.enqueueEvents(e),y.processEventQueue()}function i(e,t){T=e,S=t,T.attachEvent("onchange",r)}function a(){T&&(T.detachEvent("onchange",r),T=null,S=null)}function s(e,t,n){return e===O.topChange?n:void 0}function u(e,t,n){e===O.topFocus?(a(),i(t,n)):e===O.topBlur&&a()}function c(e,t){T=e,S=t,w=e.value,_=Object.getOwnPropertyDescriptor(e.constructor.prototype,"value"),Object.defineProperty(T,"value",k),T.attachEvent("onpropertychange",p)}function l(){T&&(delete T.value,T.detachEvent("onpropertychange",p),T=null,S=null,w=null,_=null)}function p(e){if("value"===e.propertyName){var t=e.srcElement.value;t!==w&&(w=t,r(e))}}function d(e,t,n){return e===O.topInput?n:void 0}function f(e,t,n){e===O.topFocus?(l(),c(t,n)):e===O.topBlur&&l()}function h(e){return e!==O.topSelectionChange&&e!==O.topKeyUp&&e!==O.topKeyDown||!T||T.value===w?void 0:(w=T.value,S)}function v(e){return"INPUT"===e.nodeName&&("checkbox"===e.type||"radio"===e.type)}function m(e,t,n){return e===O.topClick?n:void 0}var g=e("./EventConstants"),y=e("./EventPluginHub"),C=e("./EventPropagators"),E=e("./ExecutionEnvironment"),R=e("./ReactUpdates"),M=e("./SyntheticEvent"),D=e("./isEventSupported"),x=e("./isTextInputElement"),b=e("./keyOf"),O=g.topLevelTypes,P={change:{phasedRegistrationNames:{bubbled:b({onChange:null}),captured:b({onChangeCapture:null})},dependencies:[O.topBlur,O.topChange,O.topClick,O.topFocus,O.topInput,O.topKeyDown,O.topKeyUp,O.topSelectionChange]}},T=null,S=null,w=null,_=null,I=!1;E.canUseDOM&&(I=D("change")&&(!("documentMode"in document)||document.documentMode>8));var N=!1;E.canUseDOM&&(N=D("input")&&(!("documentMode"in document)||document.documentMode>9));var k={get:function(){return _.get.call(this)},set:function(e){w=""+e,_.set.call(this,e)}},A={eventTypes:P,extractEvents:function(e,t,r,o){var i,a;if(n(t)?I?i=s:a=u:x(t)?N?i=d:(i=h,a=f):v(t)&&(i=m),i){var c=i(e,t,r);if(c){var l=M.getPooled(P.change,c,o);return C.accumulateTwoPhaseDispatches(l),l}}a&&a(e,t,r)}};t.exports=A},{"./EventConstants":16,"./EventPluginHub":18,"./EventPropagators":21,"./ExecutionEnvironment":22,"./ReactUpdates":84,"./SyntheticEvent":93,"./isEventSupported":132,"./isTextInputElement":134,"./keyOf":138}],8:[function(e,t){"use strict";var n=0,r={createReactRootIndex:function(){return n++}};t.exports=r},{}],9:[function(e,t){"use strict";function n(e){switch(e){case g.topCompositionStart:return C.compositionStart;case g.topCompositionEnd:return C.compositionEnd;case g.topCompositionUpdate:return C.compositionUpdate}}function r(e,t){return e===g.topKeyDown&&t.keyCode===h}function o(e,t){switch(e){case g.topKeyUp:return-1!==f.indexOf(t.keyCode);case g.topKeyDown:return t.keyCode!==h;case g.topKeyPress:case g.topMouseDown:case g.topBlur:return!0;default:return!1}}function i(e){this.root=e,this.startSelection=c.getSelection(e),this.startValue=this.getText()}var a=e("./EventConstants"),s=e("./EventPropagators"),u=e("./ExecutionEnvironment"),c=e("./ReactInputSelection"),l=e("./SyntheticCompositionEvent"),p=e("./getTextContentAccessor"),d=e("./keyOf"),f=[9,13,27,32],h=229,v=u.canUseDOM&&"CompositionEvent"in window,m=!v||"documentMode"in document&&document.documentMode>8&&document.documentMode<=11,g=a.topLevelTypes,y=null,C={compositionEnd:{phasedRegistrationNames:{bubbled:d({onCompositionEnd:null}),captured:d({onCompositionEndCapture:null})},dependencies:[g.topBlur,g.topCompositionEnd,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]},compositionStart:{phasedRegistrationNames:{bubbled:d({onCompositionStart:null}),captured:d({onCompositionStartCapture:null})},dependencies:[g.topBlur,g.topCompositionStart,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]},compositionUpdate:{phasedRegistrationNames:{bubbled:d({onCompositionUpdate:null}),captured:d({onCompositionUpdateCapture:null})},dependencies:[g.topBlur,g.topCompositionUpdate,g.topKeyDown,g.topKeyPress,g.topKeyUp,g.topMouseDown]}};i.prototype.getText=function(){return this.root.value||this.root[p()]},i.prototype.getData=function(){var e=this.getText(),t=this.startSelection.start,n=this.startValue.length-this.startSelection.end;return e.substr(t,e.length-n-t)};var E={eventTypes:C,extractEvents:function(e,t,a,u){var c,p;if(v?c=n(e):y?o(e,u)&&(c=C.compositionEnd):r(e,u)&&(c=C.compositionStart),m&&(y||c!==C.compositionStart?c===C.compositionEnd&&y&&(p=y.getData(),y=null):y=new i(t)),c){var d=l.getPooled(c,a,u);return p&&(d.data=p),s.accumulateTwoPhaseDispatches(d),d}}};t.exports=E},{"./EventConstants":16,"./EventPropagators":21,"./ExecutionEnvironment":22,"./ReactInputSelection":61,"./SyntheticCompositionEvent":91,"./getTextContentAccessor":126,"./keyOf":138}],10:[function(e,t){"use strict";function n(e,t,n){e.insertBefore(t,e.childNodes[n]||null)}var r,o=e("./Danger"),i=e("./ReactMultiChildUpdateTypes"),a=e("./getTextContentAccessor"),s=e("./invariant"),u=a();r="textContent"===u?function(e,t){e.textContent=t}:function(e,t){for(;e.firstChild;)e.removeChild(e.firstChild);if(t){var n=e.ownerDocument||document;e.appendChild(n.createTextNode(t))}};var c={dangerouslyReplaceNodeWithMarkup:o.dangerouslyReplaceNodeWithMarkup,updateTextContent:r,processUpdates:function(e,t){for(var a,u=null,c=null,l=0;a=e[l];l++)if(a.type===i.MOVE_EXISTING||a.type===i.REMOVE_NODE){var p=a.fromIndex,d=a.parentNode.childNodes[p],f=a.parentID;s(d),u=u||{},u[f]=u[f]||[],u[f][p]=d,c=c||[],c.push(d)}var h=o.dangerouslyRenderMarkup(t);if(c)for(var v=0;v<c.length;v++)c[v].parentNode.removeChild(c[v]);for(var m=0;a=e[m];m++)switch(a.type){case i.INSERT_MARKUP:n(a.parentNode,h[a.markupIndex],a.toIndex);break;case i.MOVE_EXISTING:n(a.parentNode,u[a.parentID][a.fromIndex],a.toIndex);break;case i.TEXT_CONTENT:r(a.parentNode,a.textContent);break;case i.REMOVE_NODE:}}};t.exports=c},{"./Danger":13,"./ReactMultiChildUpdateTypes":67,"./getTextContentAccessor":126,"./invariant":131}],11:[function(e,t){"use strict";var n=e("./invariant"),r={MUST_USE_ATTRIBUTE:1,MUST_USE_PROPERTY:2,HAS_SIDE_EFFECTS:4,HAS_BOOLEAN_VALUE:8,HAS_NUMERIC_VALUE:16,HAS_POSITIVE_NUMERIC_VALUE:48,HAS_OVERLOADED_BOOLEAN_VALUE:64,injectDOMPropertyConfig:function(e){var t=e.Properties||{},o=e.DOMAttributeNames||{},a=e.DOMPropertyNames||{},s=e.DOMMutationMethods||{};e.isCustomAttribute&&i._isCustomAttributeFunctions.push(e.isCustomAttribute);for(var u in t){n(!i.isStandardName.hasOwnProperty(u)),i.isStandardName[u]=!0;var c=u.toLowerCase();if(i.getPossibleStandardName[c]=u,o.hasOwnProperty(u)){var l=o[u];i.getPossibleStandardName[l]=u,i.getAttributeName[u]=l}else i.getAttributeName[u]=c;i.getPropertyName[u]=a.hasOwnProperty(u)?a[u]:u,i.getMutationMethod[u]=s.hasOwnProperty(u)?s[u]:null;var p=t[u];i.mustUseAttribute[u]=p&r.MUST_USE_ATTRIBUTE,i.mustUseProperty[u]=p&r.MUST_USE_PROPERTY,i.hasSideEffects[u]=p&r.HAS_SIDE_EFFECTS,i.hasBooleanValue[u]=p&r.HAS_BOOLEAN_VALUE,i.hasNumericValue[u]=p&r.HAS_NUMERIC_VALUE,i.hasPositiveNumericValue[u]=p&r.HAS_POSITIVE_NUMERIC_VALUE,i.hasOverloadedBooleanValue[u]=p&r.HAS_OVERLOADED_BOOLEAN_VALUE,n(!i.mustUseAttribute[u]||!i.mustUseProperty[u]),n(i.mustUseProperty[u]||!i.hasSideEffects[u]),n(!!i.hasBooleanValue[u]+!!i.hasNumericValue[u]+!!i.hasOverloadedBooleanValue[u]<=1)}}},o={},i={ID_ATTRIBUTE_NAME:"data-reactid",isStandardName:{},getPossibleStandardName:{},getAttributeName:{},getPropertyName:{},getMutationMethod:{},mustUseAttribute:{},mustUseProperty:{},hasSideEffects:{},hasBooleanValue:{},hasNumericValue:{},hasPositiveNumericValue:{},hasOverloadedBooleanValue:{},_isCustomAttributeFunctions:[],isCustomAttribute:function(e){for(var t=0;t<i._isCustomAttributeFunctions.length;t++){var n=i._isCustomAttributeFunctions[t];if(n(e))return!0}return!1},getDefaultValueForProperty:function(e,t){var n,r=o[e];return r||(o[e]=r={}),t in r||(n=document.createElement(e),r[t]=n[t]),r[t]},injection:r};t.exports=i},{"./invariant":131}],12:[function(e,t){"use strict";function n(e,t){return null==t||r.hasBooleanValue[e]&&!t||r.hasNumericValue[e]&&isNaN(t)||r.hasPositiveNumericValue[e]&&1>t||r.hasOverloadedBooleanValue[e]&&t===!1}var r=e("./DOMProperty"),o=e("./escapeTextForBrowser"),i=e("./memoizeStringOnly"),a=(e("./warning"),i(function(e){return o(e)+'="'})),s={createMarkupForID:function(e){return a(r.ID_ATTRIBUTE_NAME)+o(e)+'"'},createMarkupForProperty:function(e,t){if(r.isStandardName.hasOwnProperty(e)&&r.isStandardName[e]){if(n(e,t))return"";var i=r.getAttributeName[e];return r.hasBooleanValue[e]||r.hasOverloadedBooleanValue[e]&&t===!0?o(i):a(i)+o(t)+'"'}return r.isCustomAttribute(e)?null==t?"":a(e)+o(t)+'"':null},setValueForProperty:function(e,t,o){if(r.isStandardName.hasOwnProperty(t)&&r.isStandardName[t]){var i=r.getMutationMethod[t];if(i)i(e,o);else if(n(t,o))this.deleteValueForProperty(e,t);else if(r.mustUseAttribute[t])e.setAttribute(r.getAttributeName[t],""+o);else{var a=r.getPropertyName[t];r.hasSideEffects[t]&&e[a]===o||(e[a]=o)}}else r.isCustomAttribute(t)&&(null==o?e.removeAttribute(t):e.setAttribute(t,""+o))},deleteValueForProperty:function(e,t){if(r.isStandardName.hasOwnProperty(t)&&r.isStandardName[t]){var n=r.getMutationMethod[t];if(n)n(e,void 0);else if(r.mustUseAttribute[t])e.removeAttribute(r.getAttributeName[t]);else{var o=r.getPropertyName[t],i=r.getDefaultValueForProperty(e.nodeName,o);r.hasSideEffects[t]&&e[o]===i||(e[o]=i)}}else r.isCustomAttribute(t)&&e.removeAttribute(t)}};t.exports=s},{"./DOMProperty":11,"./escapeTextForBrowser":115,"./memoizeStringOnly":140,"./warning":153}],13:[function(e,t){"use strict";function n(e){return e.substring(1,e.indexOf(" "))}var r=e("./ExecutionEnvironment"),o=e("./createNodesFromMarkup"),i=e("./emptyFunction"),a=e("./getMarkupWrap"),s=e("./invariant"),u=/^(<[^ \/>]+)/,c="data-danger-index",l={dangerouslyRenderMarkup:function(e){s(r.canUseDOM);for(var t,l={},p=0;p<e.length;p++)s(e[p]),t=n(e[p]),t=a(t)?t:"*",l[t]=l[t]||[],l[t][p]=e[p];var d=[],f=0;for(t in l)if(l.hasOwnProperty(t)){var h=l[t];for(var v in h)if(h.hasOwnProperty(v)){var m=h[v];h[v]=m.replace(u,"$1 "+c+'="'+v+'" ')}var g=o(h.join(""),i);for(p=0;p<g.length;++p){var y=g[p];y.hasAttribute&&y.hasAttribute(c)&&(v=+y.getAttribute(c),y.removeAttribute(c),s(!d.hasOwnProperty(v)),d[v]=y,f+=1)}}return s(f===d.length),s(d.length===e.length),d},dangerouslyReplaceNodeWithMarkup:function(e,t){s(r.canUseDOM),s(t),s("html"!==e.tagName.toLowerCase());var n=o(t,i)[0];e.parentNode.replaceChild(n,e)}};t.exports=l},{"./ExecutionEnvironment":22,"./createNodesFromMarkup":110,"./emptyFunction":113,"./getMarkupWrap":123,"./invariant":131}],14:[function(e,t){"use strict";var n=e("./keyOf"),r=[n({ResponderEventPlugin:null}),n({SimpleEventPlugin:null}),n({TapEventPlugin:null}),n({EnterLeaveEventPlugin:null}),n({ChangeEventPlugin:null}),n({SelectEventPlugin:null}),n({CompositionEventPlugin:null}),n({BeforeInputEventPlugin:null}),n({AnalyticsEventPlugin:null}),n({MobileSafariClickEventPlugin:null})];t.exports=r},{"./keyOf":138}],15:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./EventPropagators"),o=e("./SyntheticMouseEvent"),i=e("./ReactMount"),a=e("./keyOf"),s=n.topLevelTypes,u=i.getFirstReactDOM,c={mouseEnter:{registrationName:a({onMouseEnter:null}),dependencies:[s.topMouseOut,s.topMouseOver]},mouseLeave:{registrationName:a({onMouseLeave:null}),dependencies:[s.topMouseOut,s.topMouseOver]}},l=[null,null],p={eventTypes:c,extractEvents:function(e,t,n,a){if(e===s.topMouseOver&&(a.relatedTarget||a.fromElement))return null;if(e!==s.topMouseOut&&e!==s.topMouseOver)return null;var p;if(t.window===t)p=t;else{var d=t.ownerDocument;p=d?d.defaultView||d.parentWindow:window}var f,h;if(e===s.topMouseOut?(f=t,h=u(a.relatedTarget||a.toElement)||p):(f=p,h=t),f===h)return null;var v=f?i.getID(f):"",m=h?i.getID(h):"",g=o.getPooled(c.mouseLeave,v,a);g.type="mouseleave",g.target=f,g.relatedTarget=h;var y=o.getPooled(c.mouseEnter,m,a);return y.type="mouseenter",y.target=h,y.relatedTarget=f,r.accumulateEnterLeaveDispatches(g,y,v,m),l[0]=g,l[1]=y,l}};t.exports=p},{"./EventConstants":16,"./EventPropagators":21,"./ReactMount":65,"./SyntheticMouseEvent":97,"./keyOf":138}],16:[function(e,t){"use strict";var n=e("./keyMirror"),r=n({bubbled:null,captured:null}),o=n({topBlur:null,topChange:null,topClick:null,topCompositionEnd:null,topCompositionStart:null,topCompositionUpdate:null,topContextMenu:null,topCopy:null,topCut:null,topDoubleClick:null,topDrag:null,topDragEnd:null,topDragEnter:null,topDragExit:null,topDragLeave:null,topDragOver:null,topDragStart:null,topDrop:null,topError:null,topFocus:null,topInput:null,topKeyDown:null,topKeyPress:null,topKeyUp:null,topLoad:null,topMouseDown:null,topMouseMove:null,topMouseOut:null,topMouseOver:null,topMouseUp:null,topPaste:null,topReset:null,topScroll:null,topSelectionChange:null,topSubmit:null,topTextInput:null,topTouchCancel:null,topTouchEnd:null,topTouchMove:null,topTouchStart:null,topWheel:null}),i={topLevelTypes:o,PropagationPhases:r};t.exports=i},{"./keyMirror":137}],17:[function(e,t){var n=e("./emptyFunction"),r={listen:function(e,t,n){return e.addEventListener?(e.addEventListener(t,n,!1),{remove:function(){e.removeEventListener(t,n,!1)}}):e.attachEvent?(e.attachEvent("on"+t,n),{remove:function(){e.detachEvent("on"+t,n)}}):void 0},capture:function(e,t,r){return e.addEventListener?(e.addEventListener(t,r,!0),{remove:function(){e.removeEventListener(t,r,!0)}}):{remove:n}},registerDefault:function(){}};t.exports=r},{"./emptyFunction":113}],18:[function(e,t){"use strict";var n=e("./EventPluginRegistry"),r=e("./EventPluginUtils"),o=e("./accumulate"),i=e("./forEachAccumulated"),a=e("./invariant"),s=(e("./isEventSupported"),e("./monitorCodeUse"),{}),u=null,c=function(e){if(e){var t=r.executeDispatch,o=n.getPluginModuleForEvent(e);o&&o.executeDispatch&&(t=o.executeDispatch),r.executeDispatchesInOrder(e,t),e.isPersistent()||e.constructor.release(e)}},l=null,p={injection:{injectMount:r.injection.injectMount,injectInstanceHandle:function(e){l=e},getInstanceHandle:function(){return l},injectEventPluginOrder:n.injectEventPluginOrder,injectEventPluginsByName:n.injectEventPluginsByName},eventNameDispatchConfigs:n.eventNameDispatchConfigs,registrationNameModules:n.registrationNameModules,putListener:function(e,t,n){a(!n||"function"==typeof n);var r=s[t]||(s[t]={});r[e]=n},getListener:function(e,t){var n=s[t];return n&&n[e]},deleteListener:function(e,t){var n=s[t];n&&delete n[e]},deleteAllListeners:function(e){for(var t in s)delete s[t][e]},extractEvents:function(e,t,r,i){for(var a,s=n.plugins,u=0,c=s.length;c>u;u++){var l=s[u];if(l){var p=l.extractEvents(e,t,r,i);p&&(a=o(a,p))}}return a},enqueueEvents:function(e){e&&(u=o(u,e))},processEventQueue:function(){var e=u;u=null,i(e,c),a(!u)},__purge:function(){s={}},__getListenerBank:function(){return s}};t.exports=p},{"./EventPluginRegistry":19,"./EventPluginUtils":20,"./accumulate":103,"./forEachAccumulated":118,"./invariant":131,"./isEventSupported":132,"./monitorCodeUse":145}],19:[function(e,t){"use strict";function n(){if(a)for(var e in s){var t=s[e],n=a.indexOf(e);if(i(n>-1),!u.plugins[n]){i(t.extractEvents),u.plugins[n]=t;var o=t.eventTypes;for(var c in o)i(r(o[c],t,c))}}}function r(e,t,n){i(!u.eventNameDispatchConfigs.hasOwnProperty(n)),u.eventNameDispatchConfigs[n]=e;var r=e.phasedRegistrationNames;if(r){for(var a in r)if(r.hasOwnProperty(a)){var s=r[a];o(s,t,n)}return!0}return e.registrationName?(o(e.registrationName,t,n),!0):!1}function o(e,t,n){i(!u.registrationNameModules[e]),u.registrationNameModules[e]=t,u.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var i=e("./invariant"),a=null,s={},u={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},injectEventPluginOrder:function(e){i(!a),a=Array.prototype.slice.call(e),n()},injectEventPluginsByName:function(e){var t=!1;for(var r in e)if(e.hasOwnProperty(r)){var o=e[r];s.hasOwnProperty(r)&&s[r]===o||(i(!s[r]),s[r]=o,t=!0)}t&&n()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return u.registrationNameModules[t.registrationName]||null;for(var n in t.phasedRegistrationNames)if(t.phasedRegistrationNames.hasOwnProperty(n)){var r=u.registrationNameModules[t.phasedRegistrationNames[n]];if(r)return r}return null},_resetEventPlugins:function(){a=null;for(var e in s)s.hasOwnProperty(e)&&delete s[e];u.plugins.length=0;var t=u.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=u.registrationNameModules;for(var o in r)r.hasOwnProperty(o)&&delete r[o]}};t.exports=u},{"./invariant":131}],20:[function(e,t){"use strict";function n(e){return e===v.topMouseUp||e===v.topTouchEnd||e===v.topTouchCancel}function r(e){return e===v.topMouseMove||e===v.topTouchMove}function o(e){return e===v.topMouseDown||e===v.topTouchStart}function i(e,t){var n=e._dispatchListeners,r=e._dispatchIDs;if(Array.isArray(n))for(var o=0;o<n.length&&!e.isPropagationStopped();o++)t(e,n[o],r[o]);else n&&t(e,n,r)}function a(e,t,n){e.currentTarget=h.Mount.getNode(n);var r=t(e,n);return e.currentTarget=null,r}function s(e,t){i(e,t),e._dispatchListeners=null,e._dispatchIDs=null}function u(e){var t=e._dispatchListeners,n=e._dispatchIDs;if(Array.isArray(t)){for(var r=0;r<t.length&&!e.isPropagationStopped();r++)if(t[r](e,n[r]))return n[r]}else if(t&&t(e,n))return n;return null}function c(e){var t=u(e);return e._dispatchIDs=null,e._dispatchListeners=null,t}function l(e){var t=e._dispatchListeners,n=e._dispatchIDs;f(!Array.isArray(t));var r=t?t(e,n):null;return e._dispatchListeners=null,e._dispatchIDs=null,r}function p(e){return!!e._dispatchListeners}var d=e("./EventConstants"),f=e("./invariant"),h={Mount:null,injectMount:function(e){h.Mount=e}},v=d.topLevelTypes,m={isEndish:n,isMoveish:r,isStartish:o,executeDirectDispatch:l,executeDispatch:a,executeDispatchesInOrder:s,executeDispatchesInOrderStopAtTrue:c,hasDispatches:p,injection:h,useTouchEvents:!1};t.exports=m},{"./EventConstants":16,"./invariant":131}],21:[function(e,t){"use strict";function n(e,t,n){var r=t.dispatchConfig.phasedRegistrationNames[n];return v(e,r)}function r(e,t,r){var o=t?h.bubbled:h.captured,i=n(e,r,o);i&&(r._dispatchListeners=d(r._dispatchListeners,i),r._dispatchIDs=d(r._dispatchIDs,e))}function o(e){e&&e.dispatchConfig.phasedRegistrationNames&&p.injection.getInstanceHandle().traverseTwoPhase(e.dispatchMarker,r,e)}function i(e,t,n){if(n&&n.dispatchConfig.registrationName){var r=n.dispatchConfig.registrationName,o=v(e,r);o&&(n._dispatchListeners=d(n._dispatchListeners,o),n._dispatchIDs=d(n._dispatchIDs,e))}}function a(e){e&&e.dispatchConfig.registrationName&&i(e.dispatchMarker,null,e)}function s(e){f(e,o)}function u(e,t,n,r){p.injection.getInstanceHandle().traverseEnterLeave(n,r,i,e,t)}function c(e){f(e,a)}var l=e("./EventConstants"),p=e("./EventPluginHub"),d=e("./accumulate"),f=e("./forEachAccumulated"),h=l.PropagationPhases,v=p.getListener,m={accumulateTwoPhaseDispatches:s,accumulateDirectDispatches:c,accumulateEnterLeaveDispatches:u};t.exports=m},{"./EventConstants":16,"./EventPluginHub":18,"./accumulate":103,"./forEachAccumulated":118}],22:[function(e,t){"use strict";var n=!("undefined"==typeof window||!window.document||!window.document.createElement),r={canUseDOM:n,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:n&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:n&&!!window.screen,isInWorker:!n};t.exports=r},{}],23:[function(e,t){"use strict";var n,r=e("./DOMProperty"),o=e("./ExecutionEnvironment"),i=r.injection.MUST_USE_ATTRIBUTE,a=r.injection.MUST_USE_PROPERTY,s=r.injection.HAS_BOOLEAN_VALUE,u=r.injection.HAS_SIDE_EFFECTS,c=r.injection.HAS_NUMERIC_VALUE,l=r.injection.HAS_POSITIVE_NUMERIC_VALUE,p=r.injection.HAS_OVERLOADED_BOOLEAN_VALUE;if(o.canUseDOM){var d=document.implementation;n=d&&d.hasFeature&&d.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}var f={isCustomAttribute:RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/),Properties:{accept:null,accessKey:null,action:null,allowFullScreen:i|s,allowTransparency:i,alt:null,async:s,autoComplete:null,autoPlay:s,cellPadding:null,cellSpacing:null,charSet:i,checked:a|s,className:n?i:a,cols:i|l,colSpan:null,content:null,contentEditable:null,contextMenu:i,controls:a|s,coords:null,crossOrigin:null,data:null,dateTime:i,defer:s,dir:null,disabled:i|s,download:p,draggable:null,encType:null,form:i,formNoValidate:s,frameBorder:i,height:i,hidden:i|s,href:null,hrefLang:null,htmlFor:null,httpEquiv:null,icon:null,id:a,label:null,lang:null,list:null,loop:a|s,max:null,maxLength:i,media:i,mediaGroup:null,method:null,min:null,multiple:a|s,muted:a|s,name:null,noValidate:s,open:null,pattern:null,placeholder:null,poster:null,preload:null,radioGroup:null,readOnly:a|s,rel:null,required:s,role:i,rows:i|l,rowSpan:null,sandbox:null,scope:null,scrollLeft:a,scrolling:null,scrollTop:a,seamless:i|s,selected:a|s,shape:null,size:i|l,sizes:i,span:l,spellCheck:null,src:null,srcDoc:a,srcSet:i,start:c,step:null,style:null,tabIndex:null,target:null,title:null,type:null,useMap:null,value:a|u,width:i,wmode:i,autoCapitalize:null,autoCorrect:null,itemProp:i,itemScope:i|s,itemType:i,property:null},DOMAttributeNames:{className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{autoCapitalize:"autocapitalize",autoComplete:"autocomplete",autoCorrect:"autocorrect",autoFocus:"autofocus",autoPlay:"autoplay",encType:"enctype",hrefLang:"hreflang",radioGroup:"radiogroup",spellCheck:"spellcheck",srcDoc:"srcdoc",srcSet:"srcset"}};t.exports=f},{"./DOMProperty":11,"./ExecutionEnvironment":22}],24:[function(e,t){"use strict";var n=e("./ReactLink"),r=e("./ReactStateSetters"),o={linkState:function(e){return new n(this.state[e],r.createStateKeySetter(this,e))}};t.exports=o},{"./ReactLink":63,"./ReactStateSetters":79}],25:[function(e,t){"use strict";function n(e){u(null==e.props.checkedLink||null==e.props.valueLink)}function r(e){n(e),u(null==e.props.value&&null==e.props.onChange)}function o(e){n(e),u(null==e.props.checked&&null==e.props.onChange)}function i(e){this.props.valueLink.requestChange(e.target.value)}function a(e){this.props.checkedLink.requestChange(e.target.checked)}var s=e("./ReactPropTypes"),u=e("./invariant"),c={button:!0,checkbox:!0,image:!0,hidden:!0,radio:!0,reset:!0,submit:!0},l={Mixin:{propTypes:{value:function(e,t){return!e[t]||c[e.type]||e.onChange||e.readOnly||e.disabled?void 0:new Error("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.")},checked:function(e,t){return!e[t]||e.onChange||e.readOnly||e.disabled?void 0:new Error("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.")},onChange:s.func}},getValue:function(e){return e.props.valueLink?(r(e),e.props.valueLink.value):e.props.value},getChecked:function(e){return e.props.checkedLink?(o(e),e.props.checkedLink.value):e.props.checked},getOnChange:function(e){return e.props.valueLink?(r(e),i):e.props.checkedLink?(o(e),a):e.props.onChange}};t.exports=l},{"./ReactPropTypes":73,"./invariant":131}],26:[function(e,t){"use strict";function n(e){e.remove()}var r=e("./ReactBrowserEventEmitter"),o=e("./accumulate"),i=e("./forEachAccumulated"),a=e("./invariant"),s={trapBubbledEvent:function(e,t){a(this.isMounted());var n=r.trapBubbledEvent(e,t,this.getDOMNode());this._localEventListeners=o(this._localEventListeners,n)},componentWillUnmount:function(){this._localEventListeners&&i(this._localEventListeners,n)}};t.exports=s},{"./ReactBrowserEventEmitter":31,"./accumulate":103,"./forEachAccumulated":118,"./invariant":131}],27:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./emptyFunction"),o=n.topLevelTypes,i={eventTypes:null,extractEvents:function(e,t,n,i){if(e===o.topTouchStart){var a=i.target;a&&!a.onclick&&(a.onclick=r)}}};t.exports=i},{"./EventConstants":16,"./emptyFunction":113}],28:[function(e,t){"use strict";var n=e("./invariant"),r=function(e){var t=this;if(t.instancePool.length){var n=t.instancePool.pop();return t.call(n,e),n}return new t(e)},o=function(e,t){var n=this;if(n.instancePool.length){var r=n.instancePool.pop();return n.call(r,e,t),r}return new n(e,t)},i=function(e,t,n){var r=this;if(r.instancePool.length){var o=r.instancePool.pop();return r.call(o,e,t,n),o}return new r(e,t,n)},a=function(e,t,n,r,o){var i=this;if(i.instancePool.length){var a=i.instancePool.pop();return i.call(a,e,t,n,r,o),a}return new i(e,t,n,r,o)},s=function(e){var t=this;n(e instanceof t),e.destructor&&e.destructor(),t.instancePool.length<t.poolSize&&t.instancePool.push(e)},u=10,c=r,l=function(e,t){var n=e;return n.instancePool=[],n.getPooled=t||c,n.poolSize||(n.poolSize=u),n.release=s,n},p={addPoolingTo:l,oneArgumentPooler:r,twoArgumentPooler:o,threeArgumentPooler:i,fiveArgumentPooler:a};t.exports=p},{"./invariant":131}],29:[function(e,t){"use strict";function n(e){var t=Array.prototype.slice.call(arguments,1);return e.apply(null,t)}{var r=e("./DOMPropertyOperations"),o=e("./EventPluginUtils"),i=e("./ReactChildren"),a=e("./ReactComponent"),s=e("./ReactCompositeComponent"),u=e("./ReactContext"),c=e("./ReactCurrentOwner"),l=e("./ReactDescriptor"),p=e("./ReactDOM"),d=e("./ReactDOMComponent"),f=e("./ReactDefaultInjection"),h=e("./ReactInstanceHandles"),v=e("./ReactMount"),m=e("./ReactMultiChild"),g=e("./ReactPerf"),y=e("./ReactPropTypes"),C=e("./ReactServerRendering"),E=e("./ReactTextComponent"),R=e("./onlyChild");e("./warning")}f.inject();var M={Children:{map:i.map,forEach:i.forEach,count:i.count,only:R},DOM:p,PropTypes:y,initializeTouchEvents:function(e){o.useTouchEvents=e},createClass:s.createClass,createDescriptor:function(){return n.apply(this,arguments)},createElement:n,constructAndRenderComponent:v.constructAndRenderComponent,constructAndRenderComponentByID:v.constructAndRenderComponentByID,renderComponent:g.measure("React","renderComponent",v.renderComponent),renderComponentToString:C.renderComponentToString,renderComponentToStaticMarkup:C.renderComponentToStaticMarkup,unmountComponentAtNode:v.unmountComponentAtNode,isValidClass:l.isValidFactory,isValidComponent:l.isValidDescriptor,withContext:u.withContext,__internals:{Component:a,CurrentOwner:c,DOMComponent:d,DOMPropertyOperations:r,InstanceHandles:h,Mount:v,MultiChild:m,TextComponent:E}};M.version="0.11.2",t.exports=M},{"./DOMPropertyOperations":12,"./EventPluginUtils":20,"./ReactChildren":34,"./ReactComponent":35,"./ReactCompositeComponent":38,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactDOM":41,"./ReactDOMComponent":43,"./ReactDefaultInjection":53,"./ReactDescriptor":54,"./ReactInstanceHandles":62,"./ReactMount":65,"./ReactMultiChild":66,"./ReactPerf":69,"./ReactPropTypes":73,"./ReactServerRendering":77,"./ReactTextComponent":80,"./onlyChild":146,"./warning":153}],30:[function(e,t){"use strict"; +var n=e("./ReactEmptyComponent"),r=e("./ReactMount"),o=e("./invariant"),i={getDOMNode:function(){return o(this.isMounted()),n.isNullComponentID(this._rootNodeID)?null:r.getNode(this._rootNodeID)}};t.exports=i},{"./ReactEmptyComponent":56,"./ReactMount":65,"./invariant":131}],31:[function(e,t){"use strict";function n(e){return Object.prototype.hasOwnProperty.call(e,h)||(e[h]=d++,l[e[h]]={}),l[e[h]]}var r=e("./EventConstants"),o=e("./EventPluginHub"),i=e("./EventPluginRegistry"),a=e("./ReactEventEmitterMixin"),s=e("./ViewportMetrics"),u=e("./isEventSupported"),c=e("./merge"),l={},p=!1,d=0,f={topBlur:"blur",topChange:"change",topClick:"click",topCompositionEnd:"compositionend",topCompositionStart:"compositionstart",topCompositionUpdate:"compositionupdate",topContextMenu:"contextmenu",topCopy:"copy",topCut:"cut",topDoubleClick:"dblclick",topDrag:"drag",topDragEnd:"dragend",topDragEnter:"dragenter",topDragExit:"dragexit",topDragLeave:"dragleave",topDragOver:"dragover",topDragStart:"dragstart",topDrop:"drop",topFocus:"focus",topInput:"input",topKeyDown:"keydown",topKeyPress:"keypress",topKeyUp:"keyup",topMouseDown:"mousedown",topMouseMove:"mousemove",topMouseOut:"mouseout",topMouseOver:"mouseover",topMouseUp:"mouseup",topPaste:"paste",topScroll:"scroll",topSelectionChange:"selectionchange",topTextInput:"textInput",topTouchCancel:"touchcancel",topTouchEnd:"touchend",topTouchMove:"touchmove",topTouchStart:"touchstart",topWheel:"wheel"},h="_reactListenersID"+String(Math.random()).slice(2),v=c(a,{ReactEventListener:null,injection:{injectReactEventListener:function(e){e.setHandleTopLevel(v.handleTopLevel),v.ReactEventListener=e}},setEnabled:function(e){v.ReactEventListener&&v.ReactEventListener.setEnabled(e)},isEnabled:function(){return!(!v.ReactEventListener||!v.ReactEventListener.isEnabled())},listenTo:function(e,t){for(var o=t,a=n(o),s=i.registrationNameDependencies[e],c=r.topLevelTypes,l=0,p=s.length;p>l;l++){var d=s[l];a.hasOwnProperty(d)&&a[d]||(d===c.topWheel?u("wheel")?v.ReactEventListener.trapBubbledEvent(c.topWheel,"wheel",o):u("mousewheel")?v.ReactEventListener.trapBubbledEvent(c.topWheel,"mousewheel",o):v.ReactEventListener.trapBubbledEvent(c.topWheel,"DOMMouseScroll",o):d===c.topScroll?u("scroll",!0)?v.ReactEventListener.trapCapturedEvent(c.topScroll,"scroll",o):v.ReactEventListener.trapBubbledEvent(c.topScroll,"scroll",v.ReactEventListener.WINDOW_HANDLE):d===c.topFocus||d===c.topBlur?(u("focus",!0)?(v.ReactEventListener.trapCapturedEvent(c.topFocus,"focus",o),v.ReactEventListener.trapCapturedEvent(c.topBlur,"blur",o)):u("focusin")&&(v.ReactEventListener.trapBubbledEvent(c.topFocus,"focusin",o),v.ReactEventListener.trapBubbledEvent(c.topBlur,"focusout",o)),a[c.topBlur]=!0,a[c.topFocus]=!0):f.hasOwnProperty(d)&&v.ReactEventListener.trapBubbledEvent(d,f[d],o),a[d]=!0)}},trapBubbledEvent:function(e,t,n){return v.ReactEventListener.trapBubbledEvent(e,t,n)},trapCapturedEvent:function(e,t,n){return v.ReactEventListener.trapCapturedEvent(e,t,n)},ensureScrollValueMonitoring:function(){if(!p){var e=s.refreshScrollValues;v.ReactEventListener.monitorScrollValue(e),p=!0}},eventNameDispatchConfigs:o.eventNameDispatchConfigs,registrationNameModules:o.registrationNameModules,putListener:o.putListener,getListener:o.getListener,deleteListener:o.deleteListener,deleteAllListeners:o.deleteAllListeners});t.exports=v},{"./EventConstants":16,"./EventPluginHub":18,"./EventPluginRegistry":19,"./ReactEventEmitterMixin":58,"./ViewportMetrics":102,"./isEventSupported":132,"./merge":141}],32:[function(e,t){"use strict";var n=e("./React"),r=e("./ReactTransitionGroup"),o=e("./ReactCSSTransitionGroupChild"),i=n.createClass({displayName:"ReactCSSTransitionGroup",propTypes:{transitionName:n.PropTypes.string.isRequired,transitionEnter:n.PropTypes.bool,transitionLeave:n.PropTypes.bool},getDefaultProps:function(){return{transitionEnter:!0,transitionLeave:!0}},_wrapChild:function(e){return o({name:this.props.transitionName,enter:this.props.transitionEnter,leave:this.props.transitionLeave},e)},render:function(){return this.transferPropsTo(r({childFactory:this._wrapChild},this.props.children))}});t.exports=i},{"./React":29,"./ReactCSSTransitionGroupChild":33,"./ReactTransitionGroup":83}],33:[function(e,t){"use strict";var n=e("./React"),r=e("./CSSCore"),o=e("./ReactTransitionEvents"),i=e("./onlyChild"),a=17,s=n.createClass({displayName:"ReactCSSTransitionGroupChild",transition:function(e,t){var n=this.getDOMNode(),i=this.props.name+"-"+e,a=i+"-active",s=function(){r.removeClass(n,i),r.removeClass(n,a),o.removeEndEventListener(n,s),t&&t()};o.addEndEventListener(n,s),r.addClass(n,i),this.queueClass(a)},queueClass:function(e){this.classNameQueue.push(e),this.timeout||(this.timeout=setTimeout(this.flushClassNameQueue,a))},flushClassNameQueue:function(){this.isMounted()&&this.classNameQueue.forEach(r.addClass.bind(r,this.getDOMNode())),this.classNameQueue.length=0,this.timeout=null},componentWillMount:function(){this.classNameQueue=[]},componentWillUnmount:function(){this.timeout&&clearTimeout(this.timeout)},componentWillEnter:function(e){this.props.enter?this.transition("enter",e):e()},componentWillLeave:function(e){this.props.leave?this.transition("leave",e):e()},render:function(){return i(this.props.children)}});t.exports=s},{"./CSSCore":3,"./React":29,"./ReactTransitionEvents":82,"./onlyChild":146}],34:[function(e,t){"use strict";function n(e,t){this.forEachFunction=e,this.forEachContext=t}function r(e,t,n,r){var o=e;o.forEachFunction.call(o.forEachContext,t,r)}function o(e,t,o){if(null==e)return e;var i=n.getPooled(t,o);p(e,r,i),n.release(i)}function i(e,t,n){this.mapResult=e,this.mapFunction=t,this.mapContext=n}function a(e,t,n,r){var o=e,i=o.mapResult,a=!i.hasOwnProperty(n);if(a){var s=o.mapFunction.call(o.mapContext,t,r);i[n]=s}}function s(e,t,n){if(null==e)return e;var r={},o=i.getPooled(r,t,n);return p(e,a,o),i.release(o),r}function u(){return null}function c(e){return p(e,u,null)}var l=e("./PooledClass"),p=e("./traverseAllChildren"),d=(e("./warning"),l.twoArgumentPooler),f=l.threeArgumentPooler;l.addPoolingTo(n,d),l.addPoolingTo(i,f);var h={forEach:o,map:s,count:c};t.exports=h},{"./PooledClass":28,"./traverseAllChildren":151,"./warning":153}],35:[function(e,t){"use strict";var n=e("./ReactDescriptor"),r=e("./ReactOwner"),o=e("./ReactUpdates"),i=e("./invariant"),a=e("./keyMirror"),s=e("./merge"),u=a({MOUNTED:null,UNMOUNTED:null}),c=!1,l=null,p=null,d={injection:{injectEnvironment:function(e){i(!c),p=e.mountImageIntoNode,l=e.unmountIDFromEnvironment,d.BackendIDOperations=e.BackendIDOperations,c=!0}},LifeCycle:u,BackendIDOperations:null,Mixin:{isMounted:function(){return this._lifeCycleState===u.MOUNTED},setProps:function(e,t){var n=this._pendingDescriptor||this._descriptor;this.replaceProps(s(n.props,e),t)},replaceProps:function(e,t){i(this.isMounted()),i(0===this._mountDepth),this._pendingDescriptor=n.cloneAndReplaceProps(this._pendingDescriptor||this._descriptor,e),o.enqueueUpdate(this,t)},_setPropsInternal:function(e,t){var r=this._pendingDescriptor||this._descriptor;this._pendingDescriptor=n.cloneAndReplaceProps(r,s(r.props,e)),o.enqueueUpdate(this,t)},construct:function(e){this.props=e.props,this._owner=e._owner,this._lifeCycleState=u.UNMOUNTED,this._pendingCallbacks=null,this._descriptor=e,this._pendingDescriptor=null},mountComponent:function(e,t,n){i(!this.isMounted());var o=this._descriptor.props;if(null!=o.ref){var a=this._descriptor._owner;r.addComponentAsRefTo(this,o.ref,a)}this._rootNodeID=e,this._lifeCycleState=u.MOUNTED,this._mountDepth=n},unmountComponent:function(){i(this.isMounted());var e=this.props;null!=e.ref&&r.removeComponentAsRefFrom(this,e.ref,this._owner),l(this._rootNodeID),this._rootNodeID=null,this._lifeCycleState=u.UNMOUNTED},receiveComponent:function(e,t){i(this.isMounted()),this._pendingDescriptor=e,this.performUpdateIfNecessary(t)},performUpdateIfNecessary:function(e){if(null!=this._pendingDescriptor){var t=this._descriptor,n=this._pendingDescriptor;this._descriptor=n,this.props=n.props,this._owner=n._owner,this._pendingDescriptor=null,this.updateComponent(e,t)}},updateComponent:function(e,t){var n=this._descriptor;(n._owner!==t._owner||n.props.ref!==t.props.ref)&&(null!=t.props.ref&&r.removeComponentAsRefFrom(this,t.props.ref,t._owner),null!=n.props.ref&&r.addComponentAsRefTo(this,n.props.ref,n._owner))},mountComponentIntoNode:function(e,t,n){var r=o.ReactReconcileTransaction.getPooled();r.perform(this._mountComponentIntoNode,this,e,t,r,n),o.ReactReconcileTransaction.release(r)},_mountComponentIntoNode:function(e,t,n,r){var o=this.mountComponent(e,n,0);p(o,t,r)},isOwnedBy:function(e){return this._owner===e},getSiblingByRef:function(e){var t=this._owner;return t&&t.refs?t.refs[e]:null}}};t.exports=d},{"./ReactDescriptor":54,"./ReactOwner":68,"./ReactUpdates":84,"./invariant":131,"./keyMirror":137,"./merge":141}],36:[function(e,t){"use strict";var n=e("./ReactDOMIDOperations"),r=e("./ReactMarkupChecksum"),o=e("./ReactMount"),i=e("./ReactPerf"),a=e("./ReactReconcileTransaction"),s=e("./getReactRootElementInContainer"),u=e("./invariant"),c=e("./setInnerHTML"),l=1,p=9,d={ReactReconcileTransaction:a,BackendIDOperations:n,unmountIDFromEnvironment:function(e){o.purgeID(e)},mountImageIntoNode:i.measure("ReactComponentBrowserEnvironment","mountImageIntoNode",function(e,t,n){if(u(t&&(t.nodeType===l||t.nodeType===p)),n){if(r.canReuseMarkup(e,s(t)))return;u(t.nodeType!==p)}u(t.nodeType!==p),c(t,e)})};t.exports=d},{"./ReactDOMIDOperations":45,"./ReactMarkupChecksum":64,"./ReactMount":65,"./ReactPerf":69,"./ReactReconcileTransaction":75,"./getReactRootElementInContainer":125,"./invariant":131,"./setInnerHTML":147}],37:[function(e,t){"use strict";var n=e("./shallowEqual"),r={shouldComponentUpdate:function(e,t){return!n(this.props,e)||!n(this.state,t)}};t.exports=r},{"./shallowEqual":148}],38:[function(e,t){"use strict";function n(e){var t=e._owner||null;return t&&t.constructor&&t.constructor.displayName?" Check the render method of `"+t.constructor.displayName+"`.":""}function r(e,t){for(var n in t)t.hasOwnProperty(n)&&D("function"==typeof t[n])}function o(e,t){var n=_.hasOwnProperty(t)?_[t]:null;k.hasOwnProperty(t)&&D(n===S.OVERRIDE_BASE),e.hasOwnProperty(t)&&D(n===S.DEFINE_MANY||n===S.DEFINE_MANY_MERGED)}function i(e){var t=e._compositeLifeCycleState;D(e.isMounted()||t===N.MOUNTING),D(t!==N.RECEIVING_STATE),D(t!==N.UNMOUNTING)}function a(e,t){D(!h.isValidFactory(t)),D(!h.isValidDescriptor(t));var n=e.prototype;for(var r in t){var i=t[r];if(t.hasOwnProperty(r))if(o(n,r),I.hasOwnProperty(r))I[r](e,i);else{var a=_.hasOwnProperty(r),s=n.hasOwnProperty(r),u=i&&i.__reactDontBind,p="function"==typeof i,d=p&&!a&&!s&&!u;if(d)n.__reactAutoBindMap||(n.__reactAutoBindMap={}),n.__reactAutoBindMap[r]=i,n[r]=i;else if(s){var f=_[r];D(a&&(f===S.DEFINE_MANY_MERGED||f===S.DEFINE_MANY)),f===S.DEFINE_MANY_MERGED?n[r]=c(n[r],i):f===S.DEFINE_MANY&&(n[r]=l(n[r],i))}else n[r]=i}}}function s(e,t){if(t)for(var n in t){var r=t[n];if(t.hasOwnProperty(n)){var o=n in e,i=r;if(o){var a=e[n],s=typeof a,u=typeof r;D("function"===s&&"function"===u),i=l(a,r)}e[n]=i}}}function u(e,t){return D(e&&t&&"object"==typeof e&&"object"==typeof t),P(t,function(t,n){D(void 0===e[n]),e[n]=t}),e}function c(e,t){return function(){var n=e.apply(this,arguments),r=t.apply(this,arguments);return null==n?r:null==r?n:u(n,r)}}function l(e,t){return function(){e.apply(this,arguments),t.apply(this,arguments)}}var p=e("./ReactComponent"),d=e("./ReactContext"),f=e("./ReactCurrentOwner"),h=e("./ReactDescriptor"),v=(e("./ReactDescriptorValidator"),e("./ReactEmptyComponent")),m=e("./ReactErrorUtils"),g=e("./ReactOwner"),y=e("./ReactPerf"),C=e("./ReactPropTransferer"),E=e("./ReactPropTypeLocations"),R=(e("./ReactPropTypeLocationNames"),e("./ReactUpdates")),M=e("./instantiateReactComponent"),D=e("./invariant"),x=e("./keyMirror"),b=e("./merge"),O=e("./mixInto"),P=(e("./monitorCodeUse"),e("./mapObject")),T=e("./shouldUpdateReactComponent"),S=(e("./warning"),x({DEFINE_ONCE:null,DEFINE_MANY:null,OVERRIDE_BASE:null,DEFINE_MANY_MERGED:null})),w=[],_={mixins:S.DEFINE_MANY,statics:S.DEFINE_MANY,propTypes:S.DEFINE_MANY,contextTypes:S.DEFINE_MANY,childContextTypes:S.DEFINE_MANY,getDefaultProps:S.DEFINE_MANY_MERGED,getInitialState:S.DEFINE_MANY_MERGED,getChildContext:S.DEFINE_MANY_MERGED,render:S.DEFINE_ONCE,componentWillMount:S.DEFINE_MANY,componentDidMount:S.DEFINE_MANY,componentWillReceiveProps:S.DEFINE_MANY,shouldComponentUpdate:S.DEFINE_ONCE,componentWillUpdate:S.DEFINE_MANY,componentDidUpdate:S.DEFINE_MANY,componentWillUnmount:S.DEFINE_MANY,updateComponent:S.OVERRIDE_BASE},I={displayName:function(e,t){e.displayName=t},mixins:function(e,t){if(t)for(var n=0;n<t.length;n++)a(e,t[n])},childContextTypes:function(e,t){r(e,t,E.childContext),e.childContextTypes=b(e.childContextTypes,t)},contextTypes:function(e,t){r(e,t,E.context),e.contextTypes=b(e.contextTypes,t)},getDefaultProps:function(e,t){e.getDefaultProps=e.getDefaultProps?c(e.getDefaultProps,t):t},propTypes:function(e,t){r(e,t,E.prop),e.propTypes=b(e.propTypes,t)},statics:function(e,t){s(e,t)}},N=x({MOUNTING:null,UNMOUNTING:null,RECEIVING_PROPS:null,RECEIVING_STATE:null}),k={construct:function(){p.Mixin.construct.apply(this,arguments),g.Mixin.construct.apply(this,arguments),this.state=null,this._pendingState=null,this.context=null,this._compositeLifeCycleState=null},isMounted:function(){return p.Mixin.isMounted.call(this)&&this._compositeLifeCycleState!==N.MOUNTING},mountComponent:y.measure("ReactCompositeComponent","mountComponent",function(e,t,n){p.Mixin.mountComponent.call(this,e,t,n),this._compositeLifeCycleState=N.MOUNTING,this.__reactAutoBindMap&&this._bindAutoBindMethods(),this.context=this._processContext(this._descriptor._context),this.props=this._processProps(this.props),this.state=this.getInitialState?this.getInitialState():null,D("object"==typeof this.state&&!Array.isArray(this.state)),this._pendingState=null,this._pendingForceUpdate=!1,this.componentWillMount&&(this.componentWillMount(),this._pendingState&&(this.state=this._pendingState,this._pendingState=null)),this._renderedComponent=M(this._renderValidatedComponent()),this._compositeLifeCycleState=null;var r=this._renderedComponent.mountComponent(e,t,n+1);return this.componentDidMount&&t.getReactMountReady().enqueue(this.componentDidMount,this),r}),unmountComponent:function(){this._compositeLifeCycleState=N.UNMOUNTING,this.componentWillUnmount&&this.componentWillUnmount(),this._compositeLifeCycleState=null,this._renderedComponent.unmountComponent(),this._renderedComponent=null,p.Mixin.unmountComponent.call(this)},setState:function(e,t){D("object"==typeof e||null==e),this.replaceState(b(this._pendingState||this.state,e),t)},replaceState:function(e,t){i(this),this._pendingState=e,this._compositeLifeCycleState!==N.MOUNTING&&R.enqueueUpdate(this,t)},_processContext:function(e){var t=null,n=this.constructor.contextTypes;if(n){t={};for(var r in n)t[r]=e[r]}return t},_processChildContext:function(e){var t=this.getChildContext&&this.getChildContext();if(this.constructor.displayName||"ReactCompositeComponent",t){D("object"==typeof this.constructor.childContextTypes);for(var n in t)D(n in this.constructor.childContextTypes);return b(e,t)}return e},_processProps:function(e){var t,n=this.constructor.defaultProps;if(n){t=b(e);for(var r in n)"undefined"==typeof t[r]&&(t[r]=n[r])}else t=e;return t},_checkPropTypes:function(e,t,r){var o=this.constructor.displayName;for(var i in e)if(e.hasOwnProperty(i)){var a=e[i](t,i,o,r);a instanceof Error&&n(this)}},performUpdateIfNecessary:function(e){var t=this._compositeLifeCycleState;if(t!==N.MOUNTING&&t!==N.RECEIVING_PROPS&&(null!=this._pendingDescriptor||null!=this._pendingState||this._pendingForceUpdate)){var n=this.context,r=this.props,o=this._descriptor;null!=this._pendingDescriptor&&(o=this._pendingDescriptor,n=this._processContext(o._context),r=this._processProps(o.props),this._pendingDescriptor=null,this._compositeLifeCycleState=N.RECEIVING_PROPS,this.componentWillReceiveProps&&this.componentWillReceiveProps(r,n)),this._compositeLifeCycleState=N.RECEIVING_STATE;var i=this._pendingState||this.state;this._pendingState=null;try{var a=this._pendingForceUpdate||!this.shouldComponentUpdate||this.shouldComponentUpdate(r,i,n);a?(this._pendingForceUpdate=!1,this._performComponentUpdate(o,r,i,n,e)):(this._descriptor=o,this.props=r,this.state=i,this.context=n,this._owner=o._owner)}finally{this._compositeLifeCycleState=null}}},_performComponentUpdate:function(e,t,n,r,o){var i=this._descriptor,a=this.props,s=this.state,u=this.context;this.componentWillUpdate&&this.componentWillUpdate(t,n,r),this._descriptor=e,this.props=t,this.state=n,this.context=r,this._owner=e._owner,this.updateComponent(o,i),this.componentDidUpdate&&o.getReactMountReady().enqueue(this.componentDidUpdate.bind(this,a,s,u),this)},receiveComponent:function(e,t){(e!==this._descriptor||null==e._owner)&&p.Mixin.receiveComponent.call(this,e,t)},updateComponent:y.measure("ReactCompositeComponent","updateComponent",function(e,t){p.Mixin.updateComponent.call(this,e,t);var n=this._renderedComponent,r=n._descriptor,o=this._renderValidatedComponent();if(T(r,o))n.receiveComponent(o,e);else{var i=this._rootNodeID,a=n._rootNodeID;n.unmountComponent(),this._renderedComponent=M(o);var s=this._renderedComponent.mountComponent(i,e,this._mountDepth+1);p.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(a,s)}}),forceUpdate:function(e){var t=this._compositeLifeCycleState;D(this.isMounted()||t===N.MOUNTING),D(t!==N.RECEIVING_STATE&&t!==N.UNMOUNTING),this._pendingForceUpdate=!0,R.enqueueUpdate(this,e)},_renderValidatedComponent:y.measure("ReactCompositeComponent","_renderValidatedComponent",function(){var e,t=d.current;d.current=this._processChildContext(this._descriptor._context),f.current=this;try{e=this.render(),null===e||e===!1?(e=v.getEmptyComponent(),v.registerNullComponentID(this._rootNodeID)):v.deregisterNullComponentID(this._rootNodeID)}finally{d.current=t,f.current=null}return D(h.isValidDescriptor(e)),e}),_bindAutoBindMethods:function(){for(var e in this.__reactAutoBindMap)if(this.__reactAutoBindMap.hasOwnProperty(e)){var t=this.__reactAutoBindMap[e];this[e]=this._bindAutoBindMethod(m.guard(t,this.constructor.displayName+"."+e))}},_bindAutoBindMethod:function(e){var t=this,n=function(){return e.apply(t,arguments)};return n}},A=function(){};O(A,p.Mixin),O(A,g.Mixin),O(A,C.Mixin),O(A,k);var L={LifeCycle:N,Base:A,createClass:function(e){var t=function(e,t){this.construct(e,t)};t.prototype=new A,t.prototype.constructor=t,w.forEach(a.bind(null,t)),a(t,e),t.getDefaultProps&&(t.defaultProps=t.getDefaultProps()),D(t.prototype.render);for(var n in _)t.prototype[n]||(t.prototype[n]=null);var r=h.createFactory(t);return r},injection:{injectMixin:function(e){w.push(e)}}};t.exports=L},{"./ReactComponent":35,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactDescriptor":54,"./ReactDescriptorValidator":55,"./ReactEmptyComponent":56,"./ReactErrorUtils":57,"./ReactOwner":68,"./ReactPerf":69,"./ReactPropTransferer":70,"./ReactPropTypeLocationNames":71,"./ReactPropTypeLocations":72,"./ReactUpdates":84,"./instantiateReactComponent":130,"./invariant":131,"./keyMirror":137,"./mapObject":139,"./merge":141,"./mixInto":144,"./monitorCodeUse":145,"./shouldUpdateReactComponent":149,"./warning":153}],39:[function(e,t){"use strict";var n=e("./merge"),r={current:{},withContext:function(e,t){var o,i=r.current;r.current=n(i,e);try{o=t()}finally{r.current=i}return o}};t.exports=r},{"./merge":141}],40:[function(e,t){"use strict";var n={current:null};t.exports=n},{}],41:[function(e,t){"use strict";function n(e,t){var n=function(e){this.construct(e)};n.prototype=new o(t,e),n.prototype.constructor=n,n.displayName=t;var i=r.createFactory(n);return i}var r=e("./ReactDescriptor"),o=(e("./ReactDescriptorValidator"),e("./ReactDOMComponent")),i=e("./mergeInto"),a=e("./mapObject"),s=a({a:!1,abbr:!1,address:!1,area:!0,article:!1,aside:!1,audio:!1,b:!1,base:!0,bdi:!1,bdo:!1,big:!1,blockquote:!1,body:!1,br:!0,button:!1,canvas:!1,caption:!1,cite:!1,code:!1,col:!0,colgroup:!1,data:!1,datalist:!1,dd:!1,del:!1,details:!1,dfn:!1,dialog:!1,div:!1,dl:!1,dt:!1,em:!1,embed:!0,fieldset:!1,figcaption:!1,figure:!1,footer:!1,form:!1,h1:!1,h2:!1,h3:!1,h4:!1,h5:!1,h6:!1,head:!1,header:!1,hr:!0,html:!1,i:!1,iframe:!1,img:!0,input:!0,ins:!1,kbd:!1,keygen:!0,label:!1,legend:!1,li:!1,link:!0,main:!1,map:!1,mark:!1,menu:!1,menuitem:!1,meta:!0,meter:!1,nav:!1,noscript:!1,object:!1,ol:!1,optgroup:!1,option:!1,output:!1,p:!1,param:!0,picture:!1,pre:!1,progress:!1,q:!1,rp:!1,rt:!1,ruby:!1,s:!1,samp:!1,script:!1,section:!1,select:!1,small:!1,source:!0,span:!1,strong:!1,style:!1,sub:!1,summary:!1,sup:!1,table:!1,tbody:!1,td:!1,textarea:!1,tfoot:!1,th:!1,thead:!1,time:!1,title:!1,tr:!1,track:!0,u:!1,ul:!1,"var":!1,video:!1,wbr:!0,circle:!1,defs:!1,ellipse:!1,g:!1,line:!1,linearGradient:!1,mask:!1,path:!1,pattern:!1,polygon:!1,polyline:!1,radialGradient:!1,rect:!1,stop:!1,svg:!1,text:!1,tspan:!1},n),u={injectComponentClasses:function(e){i(s,e)}};s.injection=u,t.exports=s},{"./ReactDOMComponent":43,"./ReactDescriptor":54,"./ReactDescriptorValidator":55,"./mapObject":139,"./mergeInto":143}],42:[function(e,t){"use strict";var n=e("./AutoFocusMixin"),r=e("./ReactBrowserComponentMixin"),o=e("./ReactCompositeComponent"),i=e("./ReactDOM"),a=e("./keyMirror"),s=i.button,u=a({onClick:!0,onDoubleClick:!0,onMouseDown:!0,onMouseMove:!0,onMouseUp:!0,onClickCapture:!0,onDoubleClickCapture:!0,onMouseDownCapture:!0,onMouseMoveCapture:!0,onMouseUpCapture:!0}),c=o.createClass({displayName:"ReactDOMButton",mixins:[n,r],render:function(){var e={};for(var t in this.props)!this.props.hasOwnProperty(t)||this.props.disabled&&u[t]||(e[t]=this.props[t]);return s(e,this.props.children)}});t.exports=c},{"./AutoFocusMixin":1,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./keyMirror":137}],43:[function(e,t){"use strict";function n(e){e&&(v(null==e.children||null==e.dangerouslySetInnerHTML),v(null==e.style||"object"==typeof e.style))}function r(e,t,n,r){var o=p.findReactContainerForID(e);if(o){var i=o.nodeType===x?o.ownerDocument:o;E(t,i)}r.getPutListenerQueue().enqueuePutListener(e,t,n)}function o(e,t){this._tagOpen="<"+e,this._tagClose=t?"":"</"+e+">",this.tagName=e.toUpperCase()}var i=e("./CSSPropertyOperations"),a=e("./DOMProperty"),s=e("./DOMPropertyOperations"),u=e("./ReactBrowserComponentMixin"),c=e("./ReactComponent"),l=e("./ReactBrowserEventEmitter"),p=e("./ReactMount"),d=e("./ReactMultiChild"),f=e("./ReactPerf"),h=e("./escapeTextForBrowser"),v=e("./invariant"),m=e("./keyOf"),g=e("./merge"),y=e("./mixInto"),C=l.deleteListener,E=l.listenTo,R=l.registrationNameModules,M={string:!0,number:!0},D=m({style:null}),x=1;o.Mixin={mountComponent:f.measure("ReactDOMComponent","mountComponent",function(e,t,r){return c.Mixin.mountComponent.call(this,e,t,r),n(this.props),this._createOpenTagMarkupAndPutListeners(t)+this._createContentMarkup(t)+this._tagClose}),_createOpenTagMarkupAndPutListeners:function(e){var t=this.props,n=this._tagOpen;for(var o in t)if(t.hasOwnProperty(o)){var a=t[o];if(null!=a)if(R.hasOwnProperty(o))r(this._rootNodeID,o,a,e);else{o===D&&(a&&(a=t.style=g(t.style)),a=i.createMarkupForStyles(a));var u=s.createMarkupForProperty(o,a);u&&(n+=" "+u)}}if(e.renderToStaticMarkup)return n+">";var c=s.createMarkupForID(this._rootNodeID);return n+" "+c+">"},_createContentMarkup:function(e){var t=this.props.dangerouslySetInnerHTML;if(null!=t){if(null!=t.__html)return t.__html}else{var n=M[typeof this.props.children]?this.props.children:null,r=null!=n?null:this.props.children;if(null!=n)return h(n);if(null!=r){var o=this.mountChildren(r,e);return o.join("")}}return""},receiveComponent:function(e,t){(e!==this._descriptor||null==e._owner)&&c.Mixin.receiveComponent.call(this,e,t)},updateComponent:f.measure("ReactDOMComponent","updateComponent",function(e,t){n(this._descriptor.props),c.Mixin.updateComponent.call(this,e,t),this._updateDOMProperties(t.props,e),this._updateDOMChildren(t.props,e)}),_updateDOMProperties:function(e,t){var n,o,i,s=this.props;for(n in e)if(!s.hasOwnProperty(n)&&e.hasOwnProperty(n))if(n===D){var u=e[n];for(o in u)u.hasOwnProperty(o)&&(i=i||{},i[o]="")}else R.hasOwnProperty(n)?C(this._rootNodeID,n):(a.isStandardName[n]||a.isCustomAttribute(n))&&c.BackendIDOperations.deletePropertyByID(this._rootNodeID,n);for(n in s){var l=s[n],p=e[n];if(s.hasOwnProperty(n)&&l!==p)if(n===D)if(l&&(l=s.style=g(l)),p){for(o in p)!p.hasOwnProperty(o)||l&&l.hasOwnProperty(o)||(i=i||{},i[o]="");for(o in l)l.hasOwnProperty(o)&&p[o]!==l[o]&&(i=i||{},i[o]=l[o])}else i=l;else R.hasOwnProperty(n)?r(this._rootNodeID,n,l,t):(a.isStandardName[n]||a.isCustomAttribute(n))&&c.BackendIDOperations.updatePropertyByID(this._rootNodeID,n,l)}i&&c.BackendIDOperations.updateStylesByID(this._rootNodeID,i)},_updateDOMChildren:function(e,t){var n=this.props,r=M[typeof e.children]?e.children:null,o=M[typeof n.children]?n.children:null,i=e.dangerouslySetInnerHTML&&e.dangerouslySetInnerHTML.__html,a=n.dangerouslySetInnerHTML&&n.dangerouslySetInnerHTML.__html,s=null!=r?null:e.children,u=null!=o?null:n.children,l=null!=r||null!=i,p=null!=o||null!=a;null!=s&&null==u?this.updateChildren(null,t):l&&!p&&this.updateTextContent(""),null!=o?r!==o&&this.updateTextContent(""+o):null!=a?i!==a&&c.BackendIDOperations.updateInnerHTMLByID(this._rootNodeID,a):null!=u&&this.updateChildren(u,t)},unmountComponent:function(){this.unmountChildren(),l.deleteAllListeners(this._rootNodeID),c.Mixin.unmountComponent.call(this)}},y(o,c.Mixin),y(o,o.Mixin),y(o,d.Mixin),y(o,u),t.exports=o},{"./CSSPropertyOperations":5,"./DOMProperty":11,"./DOMPropertyOperations":12,"./ReactBrowserComponentMixin":30,"./ReactBrowserEventEmitter":31,"./ReactComponent":35,"./ReactMount":65,"./ReactMultiChild":66,"./ReactPerf":69,"./escapeTextForBrowser":115,"./invariant":131,"./keyOf":138,"./merge":141,"./mixInto":144}],44:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./LocalEventTrapMixin"),o=e("./ReactBrowserComponentMixin"),i=e("./ReactCompositeComponent"),a=e("./ReactDOM"),s=a.form,u=i.createClass({displayName:"ReactDOMForm",mixins:[o,r],render:function(){return this.transferPropsTo(s(null,this.props.children))},componentDidMount:function(){this.trapBubbledEvent(n.topLevelTypes.topReset,"reset"),this.trapBubbledEvent(n.topLevelTypes.topSubmit,"submit")}});t.exports=u},{"./EventConstants":16,"./LocalEventTrapMixin":26,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41}],45:[function(e,t){"use strict";var n=e("./CSSPropertyOperations"),r=e("./DOMChildrenOperations"),o=e("./DOMPropertyOperations"),i=e("./ReactMount"),a=e("./ReactPerf"),s=e("./invariant"),u=e("./setInnerHTML"),c={dangerouslySetInnerHTML:"`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.",style:"`style` must be set using `updateStylesByID()`."},l={updatePropertyByID:a.measure("ReactDOMIDOperations","updatePropertyByID",function(e,t,n){var r=i.getNode(e);s(!c.hasOwnProperty(t)),null!=n?o.setValueForProperty(r,t,n):o.deleteValueForProperty(r,t)}),deletePropertyByID:a.measure("ReactDOMIDOperations","deletePropertyByID",function(e,t,n){var r=i.getNode(e);s(!c.hasOwnProperty(t)),o.deleteValueForProperty(r,t,n)}),updateStylesByID:a.measure("ReactDOMIDOperations","updateStylesByID",function(e,t){var r=i.getNode(e);n.setValueForStyles(r,t)}),updateInnerHTMLByID:a.measure("ReactDOMIDOperations","updateInnerHTMLByID",function(e,t){var n=i.getNode(e);u(n,t)}),updateTextContentByID:a.measure("ReactDOMIDOperations","updateTextContentByID",function(e,t){var n=i.getNode(e);r.updateTextContent(n,t)}),dangerouslyReplaceNodeWithMarkupByID:a.measure("ReactDOMIDOperations","dangerouslyReplaceNodeWithMarkupByID",function(e,t){var n=i.getNode(e);r.dangerouslyReplaceNodeWithMarkup(n,t)}),dangerouslyProcessChildrenUpdates:a.measure("ReactDOMIDOperations","dangerouslyProcessChildrenUpdates",function(e,t){for(var n=0;n<e.length;n++)e[n].parentNode=i.getNode(e[n].parentID);r.processUpdates(e,t)})};t.exports=l},{"./CSSPropertyOperations":5,"./DOMChildrenOperations":10,"./DOMPropertyOperations":12,"./ReactMount":65,"./ReactPerf":69,"./invariant":131,"./setInnerHTML":147}],46:[function(e,t){"use strict";var n=e("./EventConstants"),r=e("./LocalEventTrapMixin"),o=e("./ReactBrowserComponentMixin"),i=e("./ReactCompositeComponent"),a=e("./ReactDOM"),s=a.img,u=i.createClass({displayName:"ReactDOMImg",tagName:"IMG",mixins:[o,r],render:function(){return s(this.props)},componentDidMount:function(){this.trapBubbledEvent(n.topLevelTypes.topLoad,"load"),this.trapBubbledEvent(n.topLevelTypes.topError,"error")}});t.exports=u},{"./EventConstants":16,"./LocalEventTrapMixin":26,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41}],47:[function(e,t){"use strict";var n=e("./AutoFocusMixin"),r=e("./DOMPropertyOperations"),o=e("./LinkedValueUtils"),i=e("./ReactBrowserComponentMixin"),a=e("./ReactCompositeComponent"),s=e("./ReactDOM"),u=e("./ReactMount"),c=e("./invariant"),l=e("./merge"),p=s.input,d={},f=a.createClass({displayName:"ReactDOMInput",mixins:[n,o.Mixin,i],getInitialState:function(){var e=this.props.defaultValue;return{checked:this.props.defaultChecked||!1,value:null!=e?e:null}},shouldComponentUpdate:function(){return!this._isChanging},render:function(){var e=l(this.props);e.defaultChecked=null,e.defaultValue=null;var t=o.getValue(this);e.value=null!=t?t:this.state.value;var n=o.getChecked(this);return e.checked=null!=n?n:this.state.checked,e.onChange=this._handleChange,p(e,this.props.children)},componentDidMount:function(){var e=u.getID(this.getDOMNode());d[e]=this},componentWillUnmount:function(){var e=this.getDOMNode(),t=u.getID(e);delete d[t]},componentDidUpdate:function(){var e=this.getDOMNode();null!=this.props.checked&&r.setValueForProperty(e,"checked",this.props.checked||!1);var t=o.getValue(this);null!=t&&r.setValueForProperty(e,"value",""+t)},_handleChange:function(e){var t,n=o.getOnChange(this);n&&(this._isChanging=!0,t=n.call(this,e),this._isChanging=!1),this.setState({checked:e.target.checked,value:e.target.value});var r=this.props.name;if("radio"===this.props.type&&null!=r){for(var i=this.getDOMNode(),a=i;a.parentNode;)a=a.parentNode;for(var s=a.querySelectorAll("input[name="+JSON.stringify(""+r)+'][type="radio"]'),l=0,p=s.length;p>l;l++){var f=s[l];if(f!==i&&f.form===i.form){var h=u.getID(f);c(h);var v=d[h];c(v),v.setState({checked:!1})}}}return t}});t.exports=f},{"./AutoFocusMixin":1,"./DOMPropertyOperations":12,"./LinkedValueUtils":25,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./ReactMount":65,"./invariant":131,"./merge":141}],48:[function(e,t){"use strict";var n=e("./ReactBrowserComponentMixin"),r=e("./ReactCompositeComponent"),o=e("./ReactDOM"),i=(e("./warning"),o.option),a=r.createClass({displayName:"ReactDOMOption",mixins:[n],componentWillMount:function(){},render:function(){return i(this.props,this.props.children)}});t.exports=a},{"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./warning":153}],49:[function(e,t){"use strict";function n(e,t){if(null!=e[t])if(e.multiple){if(!Array.isArray(e[t]))return new Error("The `"+t+"` prop supplied to <select> must be an array if `multiple` is true.")}else if(Array.isArray(e[t]))return new Error("The `"+t+"` prop supplied to <select> must be a scalar value if `multiple` is false.")}function r(e,t){var n,r,o,i=e.props.multiple,a=null!=t?t:e.state.value,s=e.getDOMNode().options;if(i)for(n={},r=0,o=a.length;o>r;++r)n[""+a[r]]=!0;else n=""+a;for(r=0,o=s.length;o>r;r++){var u=i?n.hasOwnProperty(s[r].value):s[r].value===n;u!==s[r].selected&&(s[r].selected=u)}}var o=e("./AutoFocusMixin"),i=e("./LinkedValueUtils"),a=e("./ReactBrowserComponentMixin"),s=e("./ReactCompositeComponent"),u=e("./ReactDOM"),c=e("./merge"),l=u.select,p=s.createClass({displayName:"ReactDOMSelect",mixins:[o,i.Mixin,a],propTypes:{defaultValue:n,value:n},getInitialState:function(){return{value:this.props.defaultValue||(this.props.multiple?[]:"")} },componentWillReceiveProps:function(e){!this.props.multiple&&e.multiple?this.setState({value:[this.state.value]}):this.props.multiple&&!e.multiple&&this.setState({value:this.state.value[0]})},shouldComponentUpdate:function(){return!this._isChanging},render:function(){var e=c(this.props);return e.onChange=this._handleChange,e.value=null,l(e,this.props.children)},componentDidMount:function(){r(this,i.getValue(this))},componentDidUpdate:function(e){var t=i.getValue(this),n=!!e.multiple,o=!!this.props.multiple;(null!=t||n!==o)&&r(this,t)},_handleChange:function(e){var t,n=i.getOnChange(this);n&&(this._isChanging=!0,t=n.call(this,e),this._isChanging=!1);var r;if(this.props.multiple){r=[];for(var o=e.target.options,a=0,s=o.length;s>a;a++)o[a].selected&&r.push(o[a].value)}else r=e.target.value;return this.setState({value:r}),t}});t.exports=p},{"./AutoFocusMixin":1,"./LinkedValueUtils":25,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./merge":141}],50:[function(e,t){"use strict";function n(e,t,n,r){return e===n&&t===r}function r(e){var t=document.selection,n=t.createRange(),r=n.text.length,o=n.duplicate();o.moveToElementText(e),o.setEndPoint("EndToStart",n);var i=o.text.length,a=i+r;return{start:i,end:a}}function o(e){var t=window.getSelection();if(0===t.rangeCount)return null;var r=t.anchorNode,o=t.anchorOffset,i=t.focusNode,a=t.focusOffset,s=t.getRangeAt(0),u=n(t.anchorNode,t.anchorOffset,t.focusNode,t.focusOffset),c=u?0:s.toString().length,l=s.cloneRange();l.selectNodeContents(e),l.setEnd(s.startContainer,s.startOffset);var p=n(l.startContainer,l.startOffset,l.endContainer,l.endOffset),d=p?0:l.toString().length,f=d+c,h=document.createRange();h.setStart(r,o),h.setEnd(i,a);var v=h.collapsed;return h.detach(),{start:v?f:d,end:v?d:f}}function i(e,t){var n,r,o=document.selection.createRange().duplicate();"undefined"==typeof t.end?(n=t.start,r=n):t.start>t.end?(n=t.end,r=t.start):(n=t.start,r=t.end),o.moveToElementText(e),o.moveStart("character",n),o.setEndPoint("EndToStart",o),o.moveEnd("character",r-n),o.select()}function a(e,t){var n=window.getSelection(),r=e[c()].length,o=Math.min(t.start,r),i="undefined"==typeof t.end?o:Math.min(t.end,r);if(!n.extend&&o>i){var a=i;i=o,o=a}var s=u(e,o),l=u(e,i);if(s&&l){var p=document.createRange();p.setStart(s.node,s.offset),n.removeAllRanges(),o>i?(n.addRange(p),n.extend(l.node,l.offset)):(p.setEnd(l.node,l.offset),n.addRange(p)),p.detach()}}var s=e("./ExecutionEnvironment"),u=e("./getNodeForCharacterOffset"),c=e("./getTextContentAccessor"),l=s.canUseDOM&&document.selection,p={getOffsets:l?r:o,setOffsets:l?i:a};t.exports=p},{"./ExecutionEnvironment":22,"./getNodeForCharacterOffset":124,"./getTextContentAccessor":126}],51:[function(e,t){"use strict";var n=e("./AutoFocusMixin"),r=e("./DOMPropertyOperations"),o=e("./LinkedValueUtils"),i=e("./ReactBrowserComponentMixin"),a=e("./ReactCompositeComponent"),s=e("./ReactDOM"),u=e("./invariant"),c=e("./merge"),l=(e("./warning"),s.textarea),p=a.createClass({displayName:"ReactDOMTextarea",mixins:[n,o.Mixin,i],getInitialState:function(){var e=this.props.defaultValue,t=this.props.children;null!=t&&(u(null==e),Array.isArray(t)&&(u(t.length<=1),t=t[0]),e=""+t),null==e&&(e="");var n=o.getValue(this);return{initialValue:""+(null!=n?n:e)}},shouldComponentUpdate:function(){return!this._isChanging},render:function(){var e=c(this.props);return u(null==e.dangerouslySetInnerHTML),e.defaultValue=null,e.value=null,e.onChange=this._handleChange,l(e,this.state.initialValue)},componentDidUpdate:function(){var e=o.getValue(this);if(null!=e){var t=this.getDOMNode();r.setValueForProperty(t,"value",""+e)}},_handleChange:function(e){var t,n=o.getOnChange(this);return n&&(this._isChanging=!0,t=n.call(this,e),this._isChanging=!1),this.setState({value:e.target.value}),t}});t.exports=p},{"./AutoFocusMixin":1,"./DOMPropertyOperations":12,"./LinkedValueUtils":25,"./ReactBrowserComponentMixin":30,"./ReactCompositeComponent":38,"./ReactDOM":41,"./invariant":131,"./merge":141,"./warning":153}],52:[function(e,t){"use strict";function n(){this.reinitializeTransaction()}var r=e("./ReactUpdates"),o=e("./Transaction"),i=e("./emptyFunction"),a=e("./mixInto"),s={initialize:i,close:function(){p.isBatchingUpdates=!1}},u={initialize:i,close:r.flushBatchedUpdates.bind(r)},c=[u,s];a(n,o.Mixin),a(n,{getTransactionWrappers:function(){return c}});var l=new n,p={isBatchingUpdates:!1,batchedUpdates:function(e,t,n){var r=p.isBatchingUpdates;p.isBatchingUpdates=!0,r?e(t,n):l.perform(e,null,t,n)}};t.exports=p},{"./ReactUpdates":84,"./Transaction":101,"./emptyFunction":113,"./mixInto":144}],53:[function(e,t){"use strict";function n(){x.EventEmitter.injectReactEventListener(D),x.EventPluginHub.injectEventPluginOrder(s),x.EventPluginHub.injectInstanceHandle(b),x.EventPluginHub.injectMount(O),x.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:S,EnterLeaveEventPlugin:u,ChangeEventPlugin:o,CompositionEventPlugin:a,MobileSafariClickEventPlugin:p,SelectEventPlugin:P,BeforeInputEventPlugin:r}),x.DOM.injectComponentClasses({button:m,form:g,img:y,input:C,option:E,select:R,textarea:M,html:_(v.html),head:_(v.head),body:_(v.body)}),x.CompositeComponent.injectMixin(d),x.DOMProperty.injectDOMPropertyConfig(l),x.DOMProperty.injectDOMPropertyConfig(w),x.EmptyComponent.injectEmptyComponent(v.noscript),x.Updates.injectReconcileTransaction(f.ReactReconcileTransaction),x.Updates.injectBatchingStrategy(h),x.RootIndex.injectCreateReactRootIndex(c.canUseDOM?i.createReactRootIndex:T.createReactRootIndex),x.Component.injectEnvironment(f)}var r=e("./BeforeInputEventPlugin"),o=e("./ChangeEventPlugin"),i=e("./ClientReactRootIndex"),a=e("./CompositionEventPlugin"),s=e("./DefaultEventPluginOrder"),u=e("./EnterLeaveEventPlugin"),c=e("./ExecutionEnvironment"),l=e("./HTMLDOMPropertyConfig"),p=e("./MobileSafariClickEventPlugin"),d=e("./ReactBrowserComponentMixin"),f=e("./ReactComponentBrowserEnvironment"),h=e("./ReactDefaultBatchingStrategy"),v=e("./ReactDOM"),m=e("./ReactDOMButton"),g=e("./ReactDOMForm"),y=e("./ReactDOMImg"),C=e("./ReactDOMInput"),E=e("./ReactDOMOption"),R=e("./ReactDOMSelect"),M=e("./ReactDOMTextarea"),D=e("./ReactEventListener"),x=e("./ReactInjection"),b=e("./ReactInstanceHandles"),O=e("./ReactMount"),P=e("./SelectEventPlugin"),T=e("./ServerReactRootIndex"),S=e("./SimpleEventPlugin"),w=e("./SVGDOMPropertyConfig"),_=e("./createFullPageComponent");t.exports={inject:n}},{"./BeforeInputEventPlugin":2,"./ChangeEventPlugin":7,"./ClientReactRootIndex":8,"./CompositionEventPlugin":9,"./DefaultEventPluginOrder":14,"./EnterLeaveEventPlugin":15,"./ExecutionEnvironment":22,"./HTMLDOMPropertyConfig":23,"./MobileSafariClickEventPlugin":27,"./ReactBrowserComponentMixin":30,"./ReactComponentBrowserEnvironment":36,"./ReactDOM":41,"./ReactDOMButton":42,"./ReactDOMForm":44,"./ReactDOMImg":46,"./ReactDOMInput":47,"./ReactDOMOption":48,"./ReactDOMSelect":49,"./ReactDOMTextarea":51,"./ReactDefaultBatchingStrategy":52,"./ReactEventListener":59,"./ReactInjection":60,"./ReactInstanceHandles":62,"./ReactMount":65,"./SVGDOMPropertyConfig":86,"./SelectEventPlugin":87,"./ServerReactRootIndex":88,"./SimpleEventPlugin":89,"./createFullPageComponent":109}],54:[function(e,t){"use strict";function n(e,t){if("function"==typeof t)for(var n in t)if(t.hasOwnProperty(n)){var r=t[n];if("function"==typeof r){var o=r.bind(t);for(var i in r)r.hasOwnProperty(i)&&(o[i]=r[i]);e[n]=o}else e[n]=r}}var r=e("./ReactContext"),o=e("./ReactCurrentOwner"),i=e("./merge"),a=(e("./warning"),function(){});a.createFactory=function(e){var t=Object.create(a.prototype),s=function(e,n){null==e?e={}:"object"==typeof e&&(e=i(e));var a=arguments.length-1;if(1===a)e.children=n;else if(a>1){for(var s=Array(a),u=0;a>u;u++)s[u]=arguments[u+1];e.children=s}var c=Object.create(t);return c._owner=o.current,c._context=r.current,c.props=e,c};return s.prototype=t,s.type=e,t.type=e,n(s,e),t.constructor=s,s},a.cloneAndReplaceProps=function(e,t){var n=Object.create(e.constructor.prototype);return n._owner=e._owner,n._context=e._context,n.props=t,n},a.isValidFactory=function(e){return"function"==typeof e&&e.prototype instanceof a},a.isValidDescriptor=function(e){return e instanceof a},t.exports=a},{"./ReactContext":39,"./ReactCurrentOwner":40,"./merge":141,"./warning":153}],55:[function(e,t){"use strict";function n(){var e=p.current;return e&&e.constructor.displayName||void 0}function r(e,t){e._store.validated||null!=e.props.key||(e._store.validated=!0,i("react_key_warning",'Each child in an array should have a unique "key" prop.',e,t))}function o(e,t,n){m.test(e)&&i("react_numeric_key_warning","Child objects should have non-numeric keys so ordering is preserved.",t,n)}function i(e,t,r,o){var i=n(),a=o.displayName,s=i||a,u=f[e];if(!u.hasOwnProperty(s)){u[s]=!0,t+=i?" Check the render method of "+i+".":" Check the renderComponent call using <"+a+">.";var c=null;r._owner&&r._owner!==p.current&&(c=r._owner.constructor.displayName,t+=" It was passed a child from "+c+"."),t+=" See http://fb.me/react-warning-keys for more information.",d(e,{component:s,componentOwner:c}),console.warn(t)}}function a(){var e=n()||"";h.hasOwnProperty(e)||(h[e]=!0,d("react_object_map_children"))}function s(e,t){if(Array.isArray(e))for(var n=0;n<e.length;n++){var i=e[n];c.isValidDescriptor(i)&&r(i,t)}else if(c.isValidDescriptor(e))e._store.validated=!0;else if(e&&"object"==typeof e){a();for(var s in e)o(s,e[s],t)}}function u(e,t,n,r){for(var o in t)if(t.hasOwnProperty(o)){var i;try{i=t[o](n,o,e,r)}catch(a){i=a}i instanceof Error&&!(i.message in v)&&(v[i.message]=!0,d("react_failed_descriptor_type_check",{message:i.message}))}}var c=e("./ReactDescriptor"),l=e("./ReactPropTypeLocations"),p=e("./ReactCurrentOwner"),d=e("./monitorCodeUse"),f={react_key_warning:{},react_numeric_key_warning:{}},h={},v={},m=/^\d+$/,g={createFactory:function(e,t,n){var r=function(){for(var r=e.apply(this,arguments),o=1;o<arguments.length;o++)s(arguments[o],r.type);var i=r.type.displayName;return t&&u(i,t,r.props,l.prop),n&&u(i,n,r._context,l.context),r};r.prototype=e.prototype,r.type=e.type;for(var o in e)e.hasOwnProperty(o)&&(r[o]=e[o]);return r}};t.exports=g},{"./ReactCurrentOwner":40,"./ReactDescriptor":54,"./ReactPropTypeLocations":72,"./monitorCodeUse":145}],56:[function(e,t){"use strict";function n(){return s(a),a()}function r(e){u[e]=!0}function o(e){delete u[e]}function i(e){return u[e]}var a,s=e("./invariant"),u={},c={injectEmptyComponent:function(e){a=e}},l={deregisterNullComponentID:o,getEmptyComponent:n,injection:c,isNullComponentID:i,registerNullComponentID:r};t.exports=l},{"./invariant":131}],57:[function(e,t){"use strict";var n={guard:function(e){return e}};t.exports=n},{}],58:[function(e,t){"use strict";function n(e){r.enqueueEvents(e),r.processEventQueue()}var r=e("./EventPluginHub"),o={handleTopLevel:function(e,t,o,i){var a=r.extractEvents(e,t,o,i);n(a)}};t.exports=o},{"./EventPluginHub":18}],59:[function(e,t){"use strict";function n(e){var t=l.getID(e),n=c.getReactRootIDFromNodeID(t),r=l.findReactContainerForID(n),o=l.getFirstReactDOM(r);return o}function r(e,t){this.topLevelType=e,this.nativeEvent=t,this.ancestors=[]}function o(e){for(var t=l.getFirstReactDOM(d(e.nativeEvent))||window,r=t;r;)e.ancestors.push(r),r=n(r);for(var o=0,i=e.ancestors.length;i>o;o++){t=e.ancestors[o];var a=l.getID(t)||"";v._handleTopLevel(e.topLevelType,t,a,e.nativeEvent)}}function i(e){var t=f(window);e(t)}var a=e("./EventListener"),s=e("./ExecutionEnvironment"),u=e("./PooledClass"),c=e("./ReactInstanceHandles"),l=e("./ReactMount"),p=e("./ReactUpdates"),d=e("./getEventTarget"),f=e("./getUnboundedScrollPosition"),h=e("./mixInto");h(r,{destructor:function(){this.topLevelType=null,this.nativeEvent=null,this.ancestors.length=0}}),u.addPoolingTo(r,u.twoArgumentPooler);var v={_enabled:!0,_handleTopLevel:null,WINDOW_HANDLE:s.canUseDOM?window:null,setHandleTopLevel:function(e){v._handleTopLevel=e},setEnabled:function(e){v._enabled=!!e},isEnabled:function(){return v._enabled},trapBubbledEvent:function(e,t,n){var r=n;return r?a.listen(r,t,v.dispatchEvent.bind(null,e)):void 0},trapCapturedEvent:function(e,t,n){var r=n;return r?a.capture(r,t,v.dispatchEvent.bind(null,e)):void 0},monitorScrollValue:function(e){var t=i.bind(null,e);a.listen(window,"scroll",t),a.listen(window,"resize",t)},dispatchEvent:function(e,t){if(v._enabled){var n=r.getPooled(e,t);try{p.batchedUpdates(o,n)}finally{r.release(n)}}}};t.exports=v},{"./EventListener":17,"./ExecutionEnvironment":22,"./PooledClass":28,"./ReactInstanceHandles":62,"./ReactMount":65,"./ReactUpdates":84,"./getEventTarget":122,"./getUnboundedScrollPosition":127,"./mixInto":144}],60:[function(e,t){"use strict";var n=e("./DOMProperty"),r=e("./EventPluginHub"),o=e("./ReactComponent"),i=e("./ReactCompositeComponent"),a=e("./ReactDOM"),s=e("./ReactEmptyComponent"),u=e("./ReactBrowserEventEmitter"),c=e("./ReactPerf"),l=e("./ReactRootIndex"),p=e("./ReactUpdates"),d={Component:o.injection,CompositeComponent:i.injection,DOMProperty:n.injection,EmptyComponent:s.injection,EventPluginHub:r.injection,DOM:a.injection,EventEmitter:u.injection,Perf:c.injection,RootIndex:l.injection,Updates:p.injection};t.exports=d},{"./DOMProperty":11,"./EventPluginHub":18,"./ReactBrowserEventEmitter":31,"./ReactComponent":35,"./ReactCompositeComponent":38,"./ReactDOM":41,"./ReactEmptyComponent":56,"./ReactPerf":69,"./ReactRootIndex":76,"./ReactUpdates":84}],61:[function(e,t){"use strict";function n(e){return o(document.documentElement,e)}var r=e("./ReactDOMSelection"),o=e("./containsNode"),i=e("./focusNode"),a=e("./getActiveElement"),s={hasSelectionCapabilities:function(e){return e&&("INPUT"===e.nodeName&&"text"===e.type||"TEXTAREA"===e.nodeName||"true"===e.contentEditable)},getSelectionInformation:function(){var e=a();return{focusedElem:e,selectionRange:s.hasSelectionCapabilities(e)?s.getSelection(e):null}},restoreSelection:function(e){var t=a(),r=e.focusedElem,o=e.selectionRange;t!==r&&n(r)&&(s.hasSelectionCapabilities(r)&&s.setSelection(r,o),i(r))},getSelection:function(e){var t;if("selectionStart"in e)t={start:e.selectionStart,end:e.selectionEnd};else if(document.selection&&"INPUT"===e.nodeName){var n=document.selection.createRange();n.parentElement()===e&&(t={start:-n.moveStart("character",-e.value.length),end:-n.moveEnd("character",-e.value.length)})}else t=r.getOffsets(e);return t||{start:0,end:0}},setSelection:function(e,t){var n=t.start,o=t.end;if("undefined"==typeof o&&(o=n),"selectionStart"in e)e.selectionStart=n,e.selectionEnd=Math.min(o,e.value.length);else if(document.selection&&"INPUT"===e.nodeName){var i=e.createTextRange();i.collapse(!0),i.moveStart("character",n),i.moveEnd("character",o-n),i.select()}else r.setOffsets(e,t)}};t.exports=s},{"./ReactDOMSelection":50,"./containsNode":106,"./focusNode":117,"./getActiveElement":119}],62:[function(e,t){"use strict";function n(e){return d+e.toString(36)}function r(e,t){return e.charAt(t)===d||t===e.length}function o(e){return""===e||e.charAt(0)===d&&e.charAt(e.length-1)!==d}function i(e,t){return 0===t.indexOf(e)&&r(t,e.length)}function a(e){return e?e.substr(0,e.lastIndexOf(d)):""}function s(e,t){if(p(o(e)&&o(t)),p(i(e,t)),e===t)return e;for(var n=e.length+f,a=n;a<t.length&&!r(t,a);a++);return t.substr(0,a)}function u(e,t){var n=Math.min(e.length,t.length);if(0===n)return"";for(var i=0,a=0;n>=a;a++)if(r(e,a)&&r(t,a))i=a;else if(e.charAt(a)!==t.charAt(a))break;var s=e.substr(0,i);return p(o(s)),s}function c(e,t,n,r,o,u){e=e||"",t=t||"",p(e!==t);var c=i(t,e);p(c||i(e,t));for(var l=0,d=c?a:s,f=e;;f=d(f,t)){var v;if(o&&f===e||u&&f===t||(v=n(f,c,r)),v===!1||f===t)break;p(l++<h)}}var l=e("./ReactRootIndex"),p=e("./invariant"),d=".",f=d.length,h=100,v={createReactRootID:function(){return n(l.createReactRootIndex())},createReactID:function(e,t){return e+t},getReactRootIDFromNodeID:function(e){if(e&&e.charAt(0)===d&&e.length>1){var t=e.indexOf(d,1);return t>-1?e.substr(0,t):e}return null},traverseEnterLeave:function(e,t,n,r,o){var i=u(e,t);i!==e&&c(e,i,n,r,!1,!0),i!==t&&c(i,t,n,o,!0,!1)},traverseTwoPhase:function(e,t,n){e&&(c("",e,t,n,!0,!1),c(e,"",t,n,!1,!0))},traverseAncestors:function(e,t,n){c("",e,t,n,!0,!1)},_getFirstCommonAncestorID:u,_getNextDescendantID:s,isAncestorIDOf:i,SEPARATOR:d};t.exports=v},{"./ReactRootIndex":76,"./invariant":131}],63:[function(e,t){"use strict";function n(e,t){this.value=e,this.requestChange=t}function r(e){var t={value:"undefined"==typeof e?o.PropTypes.any.isRequired:e.isRequired,requestChange:o.PropTypes.func.isRequired};return o.PropTypes.shape(t)}var o=e("./React");n.PropTypes={link:r},t.exports=n},{"./React":29}],64:[function(e,t){"use strict";var n=e("./adler32"),r={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(e){var t=n(e);return e.replace(">"," "+r.CHECKSUM_ATTR_NAME+'="'+t+'">')},canReuseMarkup:function(e,t){var o=t.getAttribute(r.CHECKSUM_ATTR_NAME);o=o&&parseInt(o,10);var i=n(e);return i===o}};t.exports=r},{"./adler32":104}],65:[function(e,t){"use strict";function n(e){var t=g(e);return t&&w.getID(t)}function r(e){var t=o(e);if(t)if(D.hasOwnProperty(t)){var n=D[t];n!==e&&(C(!s(n,t)),D[t]=e)}else D[t]=e;return t}function o(e){return e&&e.getAttribute&&e.getAttribute(M)||""}function i(e,t){var n=o(e);n!==t&&delete D[n],e.setAttribute(M,t),D[t]=e}function a(e){return D.hasOwnProperty(e)&&s(D[e],e)||(D[e]=w.findReactNodeByID(e)),D[e]}function s(e,t){if(e){C(o(e)===t);var n=w.findReactContainerForID(t);if(n&&m(n,e))return!0}return!1}function u(e){delete D[e]}function c(e){var t=D[e];return t&&s(t,e)?void(S=t):!1}function l(e){S=null,h.traverseAncestors(e,c);var t=S;return S=null,t}var p=e("./DOMProperty"),d=e("./ReactBrowserEventEmitter"),f=(e("./ReactCurrentOwner"),e("./ReactDescriptor")),h=e("./ReactInstanceHandles"),v=e("./ReactPerf"),m=e("./containsNode"),g=e("./getReactRootElementInContainer"),y=e("./instantiateReactComponent"),C=e("./invariant"),E=e("./shouldUpdateReactComponent"),R=(e("./warning"),h.SEPARATOR),M=p.ID_ATTRIBUTE_NAME,D={},x=1,b=9,O={},P={},T=[],S=null,w={_instancesByReactRootID:O,scrollMonitor:function(e,t){t()},_updateRootComponent:function(e,t,n,r){var o=t.props;return w.scrollMonitor(n,function(){e.replaceProps(o,r)}),e},_registerComponent:function(e,t){C(t&&(t.nodeType===x||t.nodeType===b)),d.ensureScrollValueMonitoring();var n=w.registerContainer(t);return O[n]=e,n},_renderNewRootComponent:v.measure("ReactMount","_renderNewRootComponent",function(e,t,n){var r=y(e),o=w._registerComponent(r,t);return r.mountComponentIntoNode(o,t,n),r}),renderComponent:function(e,t,r){C(f.isValidDescriptor(e));var o=O[n(t)];if(o){var i=o._descriptor;if(E(i,e))return w._updateRootComponent(o,e,t,r);w.unmountComponentAtNode(t)}var a=g(t),s=a&&w.isRenderedByReact(a),u=s&&!o,c=w._renderNewRootComponent(e,t,u);return r&&r.call(c),c},constructAndRenderComponent:function(e,t,n){return w.renderComponent(e(t),n)},constructAndRenderComponentByID:function(e,t,n){var r=document.getElementById(n);return C(r),w.constructAndRenderComponent(e,t,r)},registerContainer:function(e){var t=n(e);return t&&(t=h.getReactRootIDFromNodeID(t)),t||(t=h.createReactRootID()),P[t]=e,t},unmountComponentAtNode:function(e){var t=n(e),r=O[t];return r?(w.unmountComponentFromNode(r,e),delete O[t],delete P[t],!0):!1},unmountComponentFromNode:function(e,t){for(e.unmountComponent(),t.nodeType===b&&(t=t.documentElement);t.lastChild;)t.removeChild(t.lastChild)},findReactContainerForID:function(e){var t=h.getReactRootIDFromNodeID(e),n=P[t];return n},findReactNodeByID:function(e){var t=w.findReactContainerForID(e);return w.findComponentRoot(t,e)},isRenderedByReact:function(e){if(1!==e.nodeType)return!1;var t=w.getID(e);return t?t.charAt(0)===R:!1},getFirstReactDOM:function(e){for(var t=e;t&&t.parentNode!==t;){if(w.isRenderedByReact(t))return t;t=t.parentNode}return null},findComponentRoot:function(e,t){var n=T,r=0,o=l(t)||e;for(n[0]=o.firstChild,n.length=1;r<n.length;){for(var i,a=n[r++];a;){var s=w.getID(a);s?t===s?i=a:h.isAncestorIDOf(s,t)&&(n.length=r=0,n.push(a.firstChild)):n.push(a.firstChild),a=a.nextSibling}if(i)return n.length=0,i}n.length=0,C(!1)},getReactRootID:n,getID:r,setID:i,getNode:a,purgeID:u};t.exports=w},{"./DOMProperty":11,"./ReactBrowserEventEmitter":31,"./ReactCurrentOwner":40,"./ReactDescriptor":54,"./ReactInstanceHandles":62,"./ReactPerf":69,"./containsNode":106,"./getReactRootElementInContainer":125,"./instantiateReactComponent":130,"./invariant":131,"./shouldUpdateReactComponent":149,"./warning":153}],66:[function(e,t){"use strict";function n(e,t,n){h.push({parentID:e,parentNode:null,type:c.INSERT_MARKUP,markupIndex:v.push(t)-1,textContent:null,fromIndex:null,toIndex:n})}function r(e,t,n){h.push({parentID:e,parentNode:null,type:c.MOVE_EXISTING,markupIndex:null,textContent:null,fromIndex:t,toIndex:n})}function o(e,t){h.push({parentID:e,parentNode:null,type:c.REMOVE_NODE,markupIndex:null,textContent:null,fromIndex:t,toIndex:null})}function i(e,t){h.push({parentID:e,parentNode:null,type:c.TEXT_CONTENT,markupIndex:null,textContent:t,fromIndex:null,toIndex:null})}function a(){h.length&&(u.BackendIDOperations.dangerouslyProcessChildrenUpdates(h,v),s())}function s(){h.length=0,v.length=0}var u=e("./ReactComponent"),c=e("./ReactMultiChildUpdateTypes"),l=e("./flattenChildren"),p=e("./instantiateReactComponent"),d=e("./shouldUpdateReactComponent"),f=0,h=[],v=[],m={Mixin:{mountChildren:function(e,t){var n=l(e),r=[],o=0;this._renderedChildren=n;for(var i in n){var a=n[i];if(n.hasOwnProperty(i)){var s=p(a);n[i]=s;var u=this._rootNodeID+i,c=s.mountComponent(u,t,this._mountDepth+1);s._mountIndex=o,r.push(c),o++}}return r},updateTextContent:function(e){f++;var t=!0;try{var n=this._renderedChildren;for(var r in n)n.hasOwnProperty(r)&&this._unmountChildByName(n[r],r);this.setTextContent(e),t=!1}finally{f--,f||(t?s():a())}},updateChildren:function(e,t){f++;var n=!0;try{this._updateChildren(e,t),n=!1}finally{f--,f||(n?s():a())}},_updateChildren:function(e,t){var n=l(e),r=this._renderedChildren;if(n||r){var o,i=0,a=0;for(o in n)if(n.hasOwnProperty(o)){var s=r&&r[o],u=s&&s._descriptor,c=n[o];if(d(u,c))this.moveChild(s,a,i),i=Math.max(s._mountIndex,i),s.receiveComponent(c,t),s._mountIndex=a;else{s&&(i=Math.max(s._mountIndex,i),this._unmountChildByName(s,o));var f=p(c);this._mountChildByNameAtIndex(f,o,a,t)}a++}for(o in r)!r.hasOwnProperty(o)||n&&n[o]||this._unmountChildByName(r[o],o)}},unmountChildren:function(){var e=this._renderedChildren;for(var t in e){var n=e[t];n.unmountComponent&&n.unmountComponent()}this._renderedChildren=null},moveChild:function(e,t,n){e._mountIndex<n&&r(this._rootNodeID,e._mountIndex,t)},createChild:function(e,t){n(this._rootNodeID,t,e._mountIndex)},removeChild:function(e){o(this._rootNodeID,e._mountIndex)},setTextContent:function(e){i(this._rootNodeID,e)},_mountChildByNameAtIndex:function(e,t,n,r){var o=this._rootNodeID+t,i=e.mountComponent(o,r,this._mountDepth+1);e._mountIndex=n,this.createChild(e,i),this._renderedChildren=this._renderedChildren||{},this._renderedChildren[t]=e},_unmountChildByName:function(e,t){this.removeChild(e),e._mountIndex=null,e.unmountComponent(),delete this._renderedChildren[t]}}};t.exports=m},{"./ReactComponent":35,"./ReactMultiChildUpdateTypes":67,"./flattenChildren":116,"./instantiateReactComponent":130,"./shouldUpdateReactComponent":149}],67:[function(e,t){"use strict";var n=e("./keyMirror"),r=n({INSERT_MARKUP:null,MOVE_EXISTING:null,REMOVE_NODE:null,TEXT_CONTENT:null});t.exports=r},{"./keyMirror":137}],68:[function(e,t){"use strict";var n=e("./emptyObject"),r=e("./invariant"),o={isValidOwner:function(e){return!(!e||"function"!=typeof e.attachRef||"function"!=typeof e.detachRef)},addComponentAsRefTo:function(e,t,n){r(o.isValidOwner(n)),n.attachRef(t,e)},removeComponentAsRefFrom:function(e,t,n){r(o.isValidOwner(n)),n.refs[t]===e&&n.detachRef(t)},Mixin:{construct:function(){this.refs=n},attachRef:function(e,t){r(t.isOwnedBy(this));var o=this.refs===n?this.refs={}:this.refs;o[e]=t},detachRef:function(e){delete this.refs[e]}}};t.exports=o},{"./emptyObject":114,"./invariant":131}],69:[function(e,t){"use strict";function n(e,t,n){return n}var r={enableMeasure:!1,storedMeasure:n,measure:function(e,t,n){return n},injection:{injectMeasure:function(e){r.storedMeasure=e}}};t.exports=r},{}],70:[function(e,t){"use strict";function n(e){return function(t,n,r){t[n]=t.hasOwnProperty(n)?e(t[n],r):r}}function r(e,t){for(var n in t)if(t.hasOwnProperty(n)){var r=c[n];r&&c.hasOwnProperty(n)?r(e,n,t[n]):e.hasOwnProperty(n)||(e[n]=t[n])}return e}var o=e("./emptyFunction"),i=e("./invariant"),a=e("./joinClasses"),s=e("./merge"),u=n(function(e,t){return s(t,e)}),c={children:o,className:n(a),key:o,ref:o,style:u},l={TransferStrategies:c,mergeProps:function(e,t){return r(s(e),t)},Mixin:{transferPropsTo:function(e){return i(e._owner===this),r(e.props,this.props),e}}};t.exports=l},{"./emptyFunction":113,"./invariant":131,"./joinClasses":136,"./merge":141}],71:[function(e,t){"use strict";var n={};t.exports=n},{}],72:[function(e,t){"use strict";var n=e("./keyMirror"),r=n({prop:null,context:null,childContext:null});t.exports=r},{"./keyMirror":137}],73:[function(e,t){"use strict";function n(e){function t(t,n,r,o,i){if(o=o||C,null!=n[r])return e(n,r,o,i);var a=g[i];return t?new Error("Required "+a+" `"+r+"` was not specified in "+("`"+o+"`.")):void 0}var n=t.bind(null,!1);return n.isRequired=t.bind(null,!0),n}function r(e){function t(t,n,r,o){var i=t[n],a=h(i);if(a!==e){var s=g[o],u=v(i);return new Error("Invalid "+s+" `"+n+"` of type `"+u+"` "+("supplied to `"+r+"`, expected `"+e+"`."))}}