diff --git a/docs-site/bundle.js b/docs-site/bundle.js index b0a8c2b2aa..c49a26626b 100644 --- a/docs-site/bundle.js +++ b/docs-site/bundle.js @@ -480,7 +480,11 @@ /***/ }, /* 6 */ +<<<<<<< HEAD [634, 7], +======= +[627, 7], +>>>>>>> After utcOffset property change, update date input value /* 7 */ /***/ function(module, exports) { @@ -550,10 +554,15 @@ * will remain to ensure logic does not differ in production. */ +<<<<<<< HEAD var validateFormat = function validateFormat(format) {}; if (false) { validateFormat = function validateFormat(format) { +======= + function invariant(condition, format, a, b, c, d, e, f) { + if (false) { +>>>>>>> After utcOffset property change, update date input value if (format === undefined) { throw new Error('invariant requires an error message argument'); } @@ -3110,7 +3119,11 @@ 'use strict'; +<<<<<<< HEAD module.exports = '15.4.2'; +======= + module.exports = '15.4.1'; +>>>>>>> After utcOffset property change, update date input value /***/ }, /* 28 */ @@ -3300,6 +3313,7 @@ var ReactDOMComponentFlags = __webpack_require__(34); var invariant = __webpack_require__(8); +<<<<<<< HEAD var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; var Flags = ReactDOMComponentFlags; @@ -3312,6 +3326,13 @@ function shouldPrecacheNode(node, nodeID) { return node.nodeType === 1 && node.getAttribute(ATTR_NAME) === String(nodeID) || node.nodeType === 8 && node.nodeValue === ' react-text: ' + nodeID + ' ' || node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' '; } +======= + + var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; + var Flags = ReactDOMComponentFlags; + + var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2); +>>>>>>> After utcOffset property change, update date input value /** * Drill down (through composites and empty components) until we get a host or @@ -3378,7 +3399,11 @@ } // We assume the child nodes are in the same order as the child instances. for (; childNode !== null; childNode = childNode.nextSibling) { +<<<<<<< HEAD if (shouldPrecacheNode(childNode, childID)) { +======= + if (childNode.nodeType === 1 && childNode.getAttribute(ATTR_NAME) === String(childID) || childNode.nodeType === 8 && childNode.nodeValue === ' react-text: ' + childID + ' ' || childNode.nodeType === 8 && childNode.nodeValue === ' react-empty: ' + childID + ' ') { +>>>>>>> After utcOffset property change, update date input value precacheNode(childInst, childNode); continue outer; } @@ -3919,6 +3944,7 @@ // directly represent `beforeInput`. The IE `textinput` event is not as // useful, so we don't use it. var canUseTextInputEvent = ExecutionEnvironment.canUseDOM && 'TextEvent' in window && !documentMode && !isPresto(); +<<<<<<< HEAD // In IE9+, we have access to composition events, but the data supplied // by the native compositionend event may be incorrect. Japanese ideographic @@ -3997,10 +4023,129 @@ return eventTypes.compositionEnd; case 'topCompositionUpdate': return eventTypes.compositionUpdate; +======= + + // In IE9+, we have access to composition events, but the data supplied + // by the native compositionend event may be incorrect. Japanese ideographic + // spaces, for instance (\u3000) are not recorded correctly. + var useFallbackCompositionData = ExecutionEnvironment.canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); + + /** + * Opera <= 12 includes TextEvent in window, but does not fire + * text input events. Rely on keypress instead. + */ + function isPresto() { + var opera = window.opera; + return typeof opera === 'object' && typeof opera.version === 'function' && parseInt(opera.version(), 10) <= 12; + } + + var SPACEBAR_CODE = 32; + var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + + // Events and their corresponding property names. + var eventTypes = { + beforeInput: { + phasedRegistrationNames: { + bubbled: 'onBeforeInput', + captured: 'onBeforeInputCapture' + }, + dependencies: ['topCompositionEnd', 'topKeyPress', 'topTextInput', 'topPaste'] + }, + compositionEnd: { + phasedRegistrationNames: { + bubbled: 'onCompositionEnd', + captured: 'onCompositionEndCapture' + }, + dependencies: ['topBlur', 'topCompositionEnd', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: 'onCompositionStart', + captured: 'onCompositionStartCapture' + }, + dependencies: ['topBlur', 'topCompositionStart', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: 'onCompositionUpdate', + captured: 'onCompositionUpdateCapture' + }, + dependencies: ['topBlur', 'topCompositionUpdate', 'topKeyDown', 'topKeyPress', 'topKeyUp', 'topMouseDown'] } + }; + + // Track whether we've ever handled a keypress on the space key. + var hasSpaceKeypress = false; + + /** + * Return whether a native keypress event is assumed to be a command. + * This is required because Firefox fires `keypress` events for key commands + * (cut, copy, select-all, etc.) even though no character is inserted. + */ + function isKeypressCommand(nativeEvent) { + return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && + // ctrlKey && altKey is equivalent to AltGr, and is not a command. + !(nativeEvent.ctrlKey && nativeEvent.altKey); } /** + * Translate native top level events into event types. + * + * @param {string} topLevelType + * @return {object} + */ + function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case 'topCompositionStart': + return eventTypes.compositionStart; + case 'topCompositionEnd': + return eventTypes.compositionEnd; + case 'topCompositionUpdate': + return eventTypes.compositionUpdate; + } + } + + /** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ + function isFallbackCompositionStart(topLevelType, nativeEvent) { + return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE; + } + + /** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ + function isFallbackCompositionEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case 'topKeyUp': + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; + case 'topKeyDown': + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; + case 'topKeyPress': + case 'topMouseDown': + case 'topBlur': + // Events are not possible without cancelling IME. + return true; + default: + return false; +>>>>>>> After utcOffset property change, update date input value + } + } + + /** +<<<<<<< HEAD * Does our fallback best-guess model think this event signifies that * composition has begun? * @@ -4104,6 +4249,73 @@ } } +======= + * Google Input Tools provides composition data via a CustomEvent, + * with the `data` property populated in the `detail` object. If this + * is available on the event object, use it. If not, this is a plain + * composition event and we have nothing special to extract. + * + * @param {object} nativeEvent + * @return {?string} + */ + function getDataFromCustomEvent(nativeEvent) { + var detail = nativeEvent.detail; + if (typeof detail === 'object' && 'data' in detail) { + return detail.data; + } + return null; + } + + // Track the current IME composition fallback object, if any. + var currentComposition = null; + + /** + * @return {?object} A SyntheticCompositionEvent. + */ + function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var eventType; + var fallbackData; + + if (canUseCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!currentComposition) { + if (isFallbackCompositionStart(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionStart; + } + } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + } + + if (!eventType) { + return null; + } + + if (useFallbackCompositionData) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!currentComposition && eventType === eventTypes.compositionStart) { + currentComposition = FallbackCompositionState.getPooled(nativeEventTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (currentComposition) { + fallbackData = currentComposition.getData(); + } + } + } + + var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); + + if (fallbackData) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = fallbackData; + } else { + var customData = getDataFromCustomEvent(nativeEvent); + if (customData !== null) { + event.data = customData; + } + } + +>>>>>>> After utcOffset property change, update date input value EventPropagators.accumulateTwoPhaseDispatches(event); return event; } @@ -5052,6 +5264,7 @@ var dispatchInstances = event._dispatchInstances; if (false) { validateEventDispatches(event); +<<<<<<< HEAD } if (Array.isArray(dispatchListeners)) { for (var i = 0; i < dispatchListeners.length; i++) { @@ -5064,6 +5277,20 @@ } else if (dispatchListeners) { executeDispatch(event, simulated, dispatchListeners, dispatchInstances); } +======= + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, simulated, dispatchListeners, dispatchInstances); + } +>>>>>>> After utcOffset property change, update date input value event._dispatchListeners = null; event._dispatchInstances = null; } @@ -5348,6 +5575,81 @@ * handling the case when there is exactly one item (and we do not need to * allocate an array). */ +<<<<<<< HEAD + + function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } + } + + module.exports = forEachAccumulated; + +/***/ }, +/* 45 */ +/***/ function(module, exports) { + + /** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + + /** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ + var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent), + + canUseViewport: canUseDOM && !!window.screen, + + isInWorker: !canUseDOM // For now, this is true - might change in the future. + + }; + + module.exports = ExecutionEnvironment; + +/***/ }, +/* 46 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + 'use strict'; + + var _assign = __webpack_require__(4); + + var PooledClass = __webpack_require__(47); + + var getTextContentAccessor = __webpack_require__(48); + +======= function forEachAccumulated(arr, cb, scope) { if (Array.isArray(arr)) { @@ -5421,6 +5723,7 @@ var getTextContentAccessor = __webpack_require__(48); +>>>>>>> After utcOffset property change, update date input value /** * This helper class stores information about text content of a target node, * allowing comparison of content before and after a given event. @@ -5500,7 +5803,11 @@ /***/ }, /* 47 */ +<<<<<<< HEAD [634, 32], +======= +[627, 32], +>>>>>>> After utcOffset property change, update date input value /* 48 */ /***/ function(module, exports, __webpack_require__) { @@ -5912,6 +6219,7 @@ var ReactDOMComponentTree = __webpack_require__(31); var ReactUpdates = __webpack_require__(53); var SyntheticEvent = __webpack_require__(50); +<<<<<<< HEAD var getEventTarget = __webpack_require__(61); var isEventSupported = __webpack_require__(62); @@ -5927,6 +6235,23 @@ } }; +======= + + var getEventTarget = __webpack_require__(61); + var isEventSupported = __webpack_require__(62); + var isTextInputElement = __webpack_require__(63); + + var eventTypes = { + change: { + phasedRegistrationNames: { + bubbled: 'onChange', + captured: 'onChangeCapture' + }, + dependencies: ['topBlur', 'topChange', 'topClick', 'topFocus', 'topInput', 'topKeyDown', 'topKeyUp', 'topSelectionChange'] + } + }; + +>>>>>>> After utcOffset property change, update date input value /** * For IE shims */ @@ -7721,6 +8046,7 @@ * Translation from modifier key to the associated property in the event. * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers */ +<<<<<<< HEAD var modifierKeyToProp = { 'Alt': 'altKey', @@ -7742,6 +8068,29 @@ return keyProp ? !!nativeEvent[keyProp] : false; } +======= + + var modifierKeyToProp = { + 'Alt': 'altKey', + 'Control': 'ctrlKey', + 'Meta': 'metaKey', + 'Shift': 'shiftKey' + }; + + // IE8 does not implement getModifierState so we simply map it to the only + // modifier keys exposed by the event itself, does not support Lock-keys. + // Currently, all major browsers except Chrome seems to support Lock-keys. + function modifierStateGetter(keyArg) { + var syntheticEvent = this; + var nativeEvent = syntheticEvent.nativeEvent; + if (nativeEvent.getModifierState) { + return nativeEvent.getModifierState(keyArg); + } + var keyProp = modifierKeyToProp[keyArg]; + return keyProp ? !!nativeEvent[keyProp] : false; + } + +>>>>>>> After utcOffset property change, update date input value function getEventModifierState(nativeEvent) { return modifierStateGetter; } @@ -8245,6 +8594,7 @@ var DOMNamespaces = __webpack_require__(74); var setInnerHTML = __webpack_require__(75); +<<<<<<< HEAD var createMicrosoftUnsafeLocalFunction = __webpack_require__(76); var setTextContent = __webpack_require__(77); @@ -8327,6 +8677,90 @@ } } +======= + + var createMicrosoftUnsafeLocalFunction = __webpack_require__(76); + var setTextContent = __webpack_require__(77); + + var ELEMENT_NODE_TYPE = 1; + var DOCUMENT_FRAGMENT_NODE_TYPE = 11; + + /** + * In IE (8-11) and Edge, appending nodes with no children is dramatically + * faster than appending a full subtree, so we essentially queue up the + * .appendChild calls here and apply them so each node is added to its parent + * before any children are added. + * + * In other browsers, doing so is slower or neutral compared to the other order + * (in Firefox, twice as slow) so we only do this inversion in IE. + * + * See https://github.com/spicyj/innerhtml-vs-createelement-vs-clonenode. + */ + var enableLazy = typeof document !== 'undefined' && typeof document.documentMode === 'number' || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && /\bEdge\/\d/.test(navigator.userAgent); + + function insertTreeChildren(tree) { + if (!enableLazy) { + return; + } + var node = tree.node; + var children = tree.children; + if (children.length) { + for (var i = 0; i < children.length; i++) { + insertTreeBefore(node, children[i], null); + } + } else if (tree.html != null) { + setInnerHTML(node, tree.html); + } else if (tree.text != null) { + setTextContent(node, tree.text); + } + } + + var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, tree, referenceNode) { + // DocumentFragments aren't actually part of the DOM after insertion so + // appending children won't update the DOM. We need to ensure the fragment + // is properly populated first, breaking out of our lazy approach for just + // this level. Also, some plugins (like Flash Player) will read + // nodes immediately upon insertion into the DOM, so + // must also be populated prior to insertion into the DOM. + if (tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || tree.node.nodeType === ELEMENT_NODE_TYPE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) { + insertTreeChildren(tree); + parentNode.insertBefore(tree.node, referenceNode); + } else { + parentNode.insertBefore(tree.node, referenceNode); + insertTreeChildren(tree); + } + }); + + function replaceChildWithTree(oldNode, newTree) { + oldNode.parentNode.replaceChild(newTree.node, oldNode); + insertTreeChildren(newTree); + } + + function queueChild(parentTree, childTree) { + if (enableLazy) { + parentTree.children.push(childTree); + } else { + parentTree.node.appendChild(childTree.node); + } + } + + function queueHTML(tree, html) { + if (enableLazy) { + tree.html = html; + } else { + setInnerHTML(tree.node, html); + } + } + + function queueText(tree, text) { + if (enableLazy) { + tree.text = text; + } else { + setTextContent(tree.node, text); + } + } + +>>>>>>> After utcOffset property change, update date input value function toString() { return this.node.nodeName; } @@ -8998,6 +9432,7 @@ * * In IE8, certain elements cannot render alone, so wrap all elements ('*'). */ +<<<<<<< HEAD var shouldWrap = {}; @@ -9019,11 +9454,78 @@ 'optgroup': selectWrap, 'option': selectWrap, +======= + + var shouldWrap = {}; + + var selectWrap = [1, '']; + var tableWrap = [1, '', '
']; + var trWrap = [3, '', '
']; + + var svgWrap = [1, '', '']; + + var markupWrap = { + '*': [1, '?
', '
'], + + 'area': [1, '', ''], + 'col': [2, '', '
'], + 'legend': [1, '
', '
'], + 'param': [1, '', ''], + 'tr': [2, '', '
'], + + 'optgroup': selectWrap, + 'option': selectWrap, + +>>>>>>> After utcOffset property change, update date input value 'caption': tableWrap, 'colgroup': tableWrap, 'tbody': tableWrap, 'tfoot': tableWrap, 'thead': tableWrap, +<<<<<<< HEAD + + 'td': trWrap, + 'th': trWrap + }; + + // Initialize the SVG elements since we know they'll always need to be wrapped + // consistently. If they are created inside a
they will be initialized in + // the wrong namespace (and will not display). + var svgElements = ['circle', 'clipPath', 'defs', 'ellipse', 'g', 'image', 'line', 'linearGradient', 'mask', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'text', 'tspan']; + svgElements.forEach(function (nodeName) { + markupWrap[nodeName] = svgWrap; + shouldWrap[nodeName] = true; + }); + + /** + * Gets the markup wrap configuration for the supplied `nodeName`. + * + * NOTE: This lazily detects which wraps are necessary for the current browser. + * + * @param {string} nodeName Lowercase `nodeName`. + * @return {?array} Markup wrap configuration, if applicable. + */ + function getMarkupWrap(nodeName) { + !!!dummyNode ? false ? invariant(false, 'Markup wrapping node not initialized') : invariant(false) : void 0; + if (!markupWrap.hasOwnProperty(nodeName)) { + nodeName = '*'; + } + if (!shouldWrap.hasOwnProperty(nodeName)) { + if (nodeName === '*') { + dummyNode.innerHTML = ''; + } else { + dummyNode.innerHTML = '<' + nodeName + '>'; + } + shouldWrap[nodeName] = !dummyNode.firstChild; + } + return shouldWrap[nodeName] ? markupWrap[nodeName] : null; + } + + module.exports = getMarkupWrap; + +/***/ }, +/* 83 */ +======= 'td': trWrap, 'th': trWrap @@ -9102,6 +9604,46 @@ module.exports = ReactDOMIDOperations; +/***/ }, +/* 84 */ +>>>>>>> After utcOffset property change, update date input value +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +<<<<<<< HEAD + 'use strict'; + + var DOMChildrenOperations = __webpack_require__(72); + var ReactDOMComponentTree = __webpack_require__(31); + + /** + * Operations used to process updates to DOM nodes. + */ + var ReactDOMIDOperations = { + + /** + * Updates a component's children by processing a series of updates. + * + * @param {array} updates List of update configurations. + * @internal + */ + dangerouslyProcessChildrenUpdates: function (parentInst, updates) { + var node = ReactDOMComponentTree.getNodeFromInstance(parentInst); + DOMChildrenOperations.processUpdates(node, updates); + } + }; + + module.exports = ReactDOMIDOperations; + /***/ }, /* 84 */ /***/ function(module, exports, __webpack_require__) { @@ -9170,6 +9712,62 @@ // Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE). var DOC_FRAGMENT_TYPE = 11; +======= + /* global hasOwnProperty:true */ + + 'use strict'; + + var _prodInvariant = __webpack_require__(32), + _assign = __webpack_require__(4); + + var AutoFocusUtils = __webpack_require__(85); + var CSSPropertyOperations = __webpack_require__(87); + var DOMLazyTree = __webpack_require__(73); + var DOMNamespaces = __webpack_require__(74); + var DOMProperty = __webpack_require__(33); + var DOMPropertyOperations = __webpack_require__(95); + var EventPluginHub = __webpack_require__(39); + var EventPluginRegistry = __webpack_require__(40); + var ReactBrowserEventEmitter = __webpack_require__(97); + var ReactDOMComponentFlags = __webpack_require__(34); + var ReactDOMComponentTree = __webpack_require__(31); + var ReactDOMInput = __webpack_require__(100); + var ReactDOMOption = __webpack_require__(103); + var ReactDOMSelect = __webpack_require__(104); + var ReactDOMTextarea = __webpack_require__(105); + var ReactInstrumentation = __webpack_require__(59); + var ReactMultiChild = __webpack_require__(106); + var ReactServerRenderingTransaction = __webpack_require__(125); + + var emptyFunction = __webpack_require__(12); + var escapeTextContentForBrowser = __webpack_require__(78); + var invariant = __webpack_require__(8); + var isEventSupported = __webpack_require__(62); + var shallowEqual = __webpack_require__(114); + var validateDOMNesting = __webpack_require__(128); + var warning = __webpack_require__(11); + + var Flags = ReactDOMComponentFlags; + var deleteListener = EventPluginHub.deleteListener; + var getNode = ReactDOMComponentTree.getNodeFromInstance; + var listenTo = ReactBrowserEventEmitter.listenTo; + var registrationNameModules = EventPluginRegistry.registrationNameModules; + + // For quickly matching children type, to test if can be treated as content. + var CONTENT_TYPES = { 'string': true, 'number': true }; + + var STYLE = 'style'; + var HTML = '__html'; + var RESERVED_PROPS = { + children: null, + dangerouslySetInnerHTML: null, + suppressContentEditableWarning: null + }; + + // Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE). + var DOC_FRAGMENT_TYPE = 11; + +>>>>>>> After utcOffset property change, update date input value function getDeclarationErrorAddendum(internalInstance) { if (internalInstance) { var owner = internalInstance._currentElement._owner || null; @@ -9515,6 +10113,7 @@ this._hostContainerInfo = hostContainerInfo; var props = this._currentElement.props; +<<<<<<< HEAD switch (this._tag) { case 'audio': @@ -9742,17 +10341,289 @@ _createContentMarkup: function (transaction, props, context) { var ret = ''; +======= + + switch (this._tag) { + case 'audio': + case 'form': + case 'iframe': + case 'img': + case 'link': + case 'object': + case 'source': + case 'video': + this._wrapperState = { + listeners: null + }; + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); + break; + case 'input': + ReactDOMInput.mountWrapper(this, props, hostParent); + props = ReactDOMInput.getHostProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); + break; + case 'option': + ReactDOMOption.mountWrapper(this, props, hostParent); + props = ReactDOMOption.getHostProps(this, props); + break; + case 'select': + ReactDOMSelect.mountWrapper(this, props, hostParent); + props = ReactDOMSelect.getHostProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); + break; + case 'textarea': + ReactDOMTextarea.mountWrapper(this, props, hostParent); + props = ReactDOMTextarea.getHostProps(this, props); + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); + break; + } + + assertValidProps(this, props); + + // We create tags in the namespace of their parent container, except HTML + // tags get no namespace. + var namespaceURI; + var parentTag; + if (hostParent != null) { + namespaceURI = hostParent._namespaceURI; + parentTag = hostParent._tag; + } else if (hostContainerInfo._tag) { + namespaceURI = hostContainerInfo._namespaceURI; + parentTag = hostContainerInfo._tag; + } + if (namespaceURI == null || namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject') { + namespaceURI = DOMNamespaces.html; + } + if (namespaceURI === DOMNamespaces.html) { + if (this._tag === 'svg') { + namespaceURI = DOMNamespaces.svg; + } else if (this._tag === 'math') { + namespaceURI = DOMNamespaces.mathml; + } + } + this._namespaceURI = namespaceURI; + + if (false) { + var parentInfo; + if (hostParent != null) { + parentInfo = hostParent._ancestorInfo; + } else if (hostContainerInfo._tag) { + parentInfo = hostContainerInfo._ancestorInfo; + } + if (parentInfo) { + // parentInfo should always be present except for the top-level + // component when server rendering + validateDOMNesting(this._tag, null, this, parentInfo); + } + this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this); + } + + var mountImage; + if (transaction.useCreateElement) { + var ownerDocument = hostContainerInfo._ownerDocument; + var el; + if (namespaceURI === DOMNamespaces.html) { + if (this._tag === 'script') { + // Create the script via .innerHTML so its "parser-inserted" flag is + // set to true and it does not execute + var div = ownerDocument.createElement('div'); + var type = this._currentElement.type; + div.innerHTML = '<' + type + '>'; + el = div.removeChild(div.firstChild); + } else if (props.is) { + el = ownerDocument.createElement(this._currentElement.type, props.is); + } else { + // Separate else branch instead of using `props.is || undefined` above becuase of a Firefox bug. + // See discussion in https://github.com/facebook/react/pull/6896 + // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 + el = ownerDocument.createElement(this._currentElement.type); + } + } else { + el = ownerDocument.createElementNS(namespaceURI, this._currentElement.type); + } + ReactDOMComponentTree.precacheNode(this, el); + this._flags |= Flags.hasCachedChildNodes; + if (!this._hostParent) { + DOMPropertyOperations.setAttributeForRoot(el); + } + this._updateDOMProperties(null, props, transaction); + var lazyTree = DOMLazyTree(el); + this._createInitialChildren(transaction, props, context, lazyTree); + mountImage = lazyTree; + } else { + var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props); + var tagContent = this._createContentMarkup(transaction, props, context); + if (!tagContent && omittedCloseTags[this._tag]) { + mountImage = tagOpen + '/>'; + } else { + mountImage = tagOpen + '>' + tagContent + ''; + } + } + + switch (this._tag) { + case 'input': + transaction.getReactMountReady().enqueue(inputPostMount, this); + if (props.autoFocus) { + transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this); + } + break; + case 'textarea': + transaction.getReactMountReady().enqueue(textareaPostMount, this); + if (props.autoFocus) { + transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this); + } + break; + case 'select': + if (props.autoFocus) { + transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this); + } + break; + case 'button': + if (props.autoFocus) { + transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this); + } + break; + case 'option': + transaction.getReactMountReady().enqueue(optionPostMount, this); + break; + } + + return mountImage; + }, + + /** + * Creates markup for the open tag and all attributes. + * + * This method has side effects because events get registered. + * + * Iterating over object properties is faster than iterating over arrays. + * @see http://jsperf.com/obj-vs-arr-iteration + * + * @private + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {object} props + * @return {string} Markup of opening tag. + */ + _createOpenTagMarkupAndPutListeners: function (transaction, props) { + var ret = '<' + this._currentElement.type; + + for (var propKey in props) { + if (!props.hasOwnProperty(propKey)) { + continue; + } + var propValue = props[propKey]; + if (propValue == null) { + continue; + } + if (registrationNameModules.hasOwnProperty(propKey)) { + if (propValue) { + enqueuePutListener(this, propKey, propValue, transaction); + } + } else { + if (propKey === STYLE) { + if (propValue) { + if (false) { + // See `_updateDOMProperties`. style block + this._previousStyle = propValue; + } + propValue = this._previousStyleCopy = _assign({}, props.style); + } + propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this); + } + var markup = null; + if (this._tag != null && isCustomComponent(this._tag, props)) { + if (!RESERVED_PROPS.hasOwnProperty(propKey)) { + markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue); + } + } else { + markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue); + } + if (markup) { + ret += ' ' + markup; + } + } + } + + // For static pages, no need to put React ID and checksum. Saves lots of + // bytes. + if (transaction.renderToStaticMarkup) { + return ret; + } + + if (!this._hostParent) { + ret += ' ' + DOMPropertyOperations.createMarkupForRoot(); + } + ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID); + return ret; + }, + + /** + * Creates markup for the content between the tags. + * + * @private + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {object} props + * @param {object} context + * @return {string} Content markup. + */ + _createContentMarkup: function (transaction, props, context) { + var ret = ''; + + // Intentional use of != to avoid catching zero/false. + var innerHTML = props.dangerouslySetInnerHTML; + if (innerHTML != null) { + if (innerHTML.__html != null) { + ret = innerHTML.__html; + } + } else { + var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null; + var childrenToUse = contentToUse != null ? null : props.children; + if (contentToUse != null) { + // TODO: Validate that text is allowed as a child of this node + ret = escapeTextContentForBrowser(contentToUse); + if (false) { + setAndValidateContentChildDev.call(this, contentToUse); + } + } else if (childrenToUse != null) { + var mountImages = this.mountChildren(childrenToUse, transaction, context); + ret = mountImages.join(''); + } + } + if (newlineEatingTags[this._tag] && ret.charAt(0) === '\n') { + // text/html ignores the first character in these tags if it's a newline + // Prefer to break application/xml over text/html (for now) by adding + // a newline specifically to get eaten by the parser. (Alternately for + // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first + // \r is normalized out by HTMLTextAreaElement#value.) + // See: + // See: + // See: + // See: Parsing of "textarea" "listing" and "pre" elements + // from + return '\n' + ret; + } else { + return ret; + } + }, + + _createInitialChildren: function (transaction, props, context, lazyTree) { +>>>>>>> After utcOffset property change, update date input value // Intentional use of != to avoid catching zero/false. var innerHTML = props.dangerouslySetInnerHTML; if (innerHTML != null) { if (innerHTML.__html != null) { +<<<<<<< HEAD ret = innerHTML.__html; +======= + DOMLazyTree.queueHTML(lazyTree, innerHTML.__html); +>>>>>>> After utcOffset property change, update date input value } } else { var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null; var childrenToUse = contentToUse != null ? null : props.children; if (contentToUse != null) { // TODO: Validate that text is allowed as a child of this node +<<<<<<< HEAD ret = escapeTextContentForBrowser(contentToUse); if (false) { setAndValidateContentChildDev.call(this, contentToUse); @@ -10097,50 +10968,352 @@ } }, - getPublicInstance: function () { - return getNode(this); - } - - }; +======= + if (false) { + setAndValidateContentChildDev.call(this, contentToUse); + } + DOMLazyTree.queueText(lazyTree, contentToUse); + } else if (childrenToUse != null) { + var mountImages = this.mountChildren(childrenToUse, transaction, context); + for (var i = 0; i < mountImages.length; i++) { + DOMLazyTree.queueChild(lazyTree, mountImages[i]); + } + } + } + }, - _assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin); + /** + * Receives a next element and updates the component. + * + * @internal + * @param {ReactElement} nextElement + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {object} context + */ + receiveComponent: function (nextElement, transaction, context) { + var prevElement = this._currentElement; + this._currentElement = nextElement; + this.updateComponent(transaction, prevElement, nextElement, context); + }, - module.exports = ReactDOMComponent; + /** + * Updates a DOM component after it has already been allocated and + * attached to the DOM. Reconciles the root DOM node, then recurses. + * + * @param {ReactReconcileTransaction} transaction + * @param {ReactElement} prevElement + * @param {ReactElement} nextElement + * @internal + * @overridable + */ + updateComponent: function (transaction, prevElement, nextElement, context) { + var lastProps = prevElement.props; + var nextProps = this._currentElement.props; -/***/ }, -/* 85 */ -/***/ function(module, exports, __webpack_require__) { + switch (this._tag) { + case 'input': + lastProps = ReactDOMInput.getHostProps(this, lastProps); + nextProps = ReactDOMInput.getHostProps(this, nextProps); + break; + case 'option': + lastProps = ReactDOMOption.getHostProps(this, lastProps); + nextProps = ReactDOMOption.getHostProps(this, nextProps); + break; + case 'select': + lastProps = ReactDOMSelect.getHostProps(this, lastProps); + nextProps = ReactDOMSelect.getHostProps(this, nextProps); + break; + case 'textarea': + lastProps = ReactDOMTextarea.getHostProps(this, lastProps); + nextProps = ReactDOMTextarea.getHostProps(this, nextProps); + break; + } - /** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ + assertValidProps(this, nextProps); + this._updateDOMProperties(lastProps, nextProps, transaction); + this._updateDOMChildren(lastProps, nextProps, transaction, context); - 'use strict'; + switch (this._tag) { + case 'input': + // Update the wrapper around inputs *after* updating props. This has to + // happen after `_updateDOMProperties`. Otherwise HTML5 input validations + // raise warnings and prevent the new value from being assigned. + ReactDOMInput.updateWrapper(this); + break; + case 'textarea': + ReactDOMTextarea.updateWrapper(this); + break; + case 'select': + // + + + + + + + + + + + } diff --git a/docs-site/style.css b/docs-site/style.css index b780d01f52..e09b56dac8 100644 --- a/docs-site/style.css +++ b/docs-site/style.css @@ -631,6 +631,9 @@ github.com style (c) Vasily Polovnyov font: inherit; color: #fff; } +.example__timezone-selector { + margin-left: 10px; } + .hero__content, .wrapper { max-width: 1100px; margin: 0 auto; } diff --git a/src/date_input.jsx b/src/date_input.jsx index 7835e75aed..c3b420087d 100644 --- a/src/date_input.jsx +++ b/src/date_input.jsx @@ -1,6 +1,6 @@ import moment from 'moment' import React from 'react' -import { isSameDay, isDayDisabled } from './date_utils' +import { isSameDay, isDayDisabled, isSameUtcOffset } from './date_utils' var DateInput = React.createClass({ displayName: 'DateInput', @@ -38,6 +38,7 @@ var DateInput = React.createClass({ componentWillReceiveProps (newProps) { if (!isSameDay(newProps.date, this.props.date) || + !isSameUtcOffset(newProps.date, this.props.date) || newProps.locale !== this.props.locale || newProps.dateFormat !== this.props.dateFormat) { this.setState({ diff --git a/src/date_utils.js b/src/date_utils.js index 2f7e92f0fa..69d81c5f60 100644 --- a/src/date_utils.js +++ b/src/date_utils.js @@ -8,6 +8,14 @@ export function isSameDay (moment1, moment2) { } } +export function isSameUtcOffset (moment1, moment2) { + if (moment1 && moment2) { + return moment1.utcOffset() === moment2.utcOffset() + } else { + return !moment1 && !moment2 + } +} + export function isDayInRange (day, startDate, endDate) { const before = startDate.clone().startOf('day').subtract(1, 'seconds') const after = endDate.clone().startOf('day').add(1, 'seconds') diff --git a/test/date_input_test.js b/test/date_input_test.js index 9963ae13c3..b5f57baab6 100644 --- a/test/date_input_test.js +++ b/test/date_input_test.js @@ -383,6 +383,25 @@ describe('DateInput', function () { }) }) + describe('utcOffsetChange', function () { + it('should rerender with correct date and time when utcOffset prop changes', function () { + var date = moment('2015-10-11T00:00:00Z') + var newDate = date.clone() + var dateFormat = 'YYYY-MM-DD HH:mm' + date.utcOffset(-5) + var dateInput = shallow( + + ) + expect(dateInput.find('input').prop('value')).to.equal('2015-10-10 19:00') + + newDate.utcOffset(5) + dateInput = shallow( + + ) + expect(dateInput.find('input').prop('value')).to.equal('2015-10-11 05:00') + }) + }) + it('should render custom input when customInput is passed as prop', function () { var date = moment() var dateFormat = 'YYYY-MM-DD' diff --git a/test/date_utils_test.js b/test/date_utils_test.js index 5097ca34e7..5155f8f4a2 100644 --- a/test/date_utils_test.js +++ b/test/date_utils_test.js @@ -1,5 +1,6 @@ import { isSameDay, + isSameUtcOffset, isDayDisabled, allDaysDisabledBefore, allDaysDisabledAfter, @@ -28,6 +29,29 @@ describe('date_utils', function () { }) }) + describe('isSameUtcOffset', function () { + it('should return true for null dates', function () { + expect(isSameUtcOffset(null, null)).to.be.true + }) + + it('should return false for a null and a non-null date', function () { + expect(isSameUtcOffset(moment(), null)).to.be.false + expect(isSameUtcOffset(null, moment())).to.be.false + }) + + it('should return true for non-equal utc offsets, but same dates', function () { + expect(isSameUtcOffset(moment('2016-02-10').utcOffset(-3), moment('2016-02-10').utcOffset(5))).to.be.false + expect(isSameUtcOffset(moment('2016-02-10').utcOffset(3), moment('2016-02-10').utcOffset(-5))).to.be.false + expect(isSameUtcOffset(moment('2016-02-10').utcOffset(180), moment('2016-02-10').utcOffset(-210))).to.be.false + }) + + it('should return true for equal utc offsets, regardless of dates', function () { + expect(isSameUtcOffset(moment('2016-02-10'), moment('2016-02-10'))).to.be.true + expect(isSameUtcOffset(moment('2016-02-10').utcOffset(-3), moment('2016-05-10').utcOffset(-3))).to.be.true + expect(isSameUtcOffset(moment('2016-12-10').utcOffset(6), moment('2016-02-15').utcOffset(6))).to.be.true + }) + }) + describe('isDayDisabled', function () { it('should be enabled by default', () => { const day = moment() diff --git a/test/datepicker_test.js b/test/datepicker_test.js index 9238c3a342..8227addcb7 100644 --- a/test/datepicker_test.js +++ b/test/datepicker_test.js @@ -6,6 +6,7 @@ import defer from 'lodash/defer' import DatePicker from '../src/datepicker.jsx' import Day from '../src/day' import TetherComponent from '../src/tether_component.jsx' +import TimezoneDatePicker from './timezone_date_picker.jsx' import moment from 'moment' describe('DatePicker', () => { @@ -425,4 +426,15 @@ describe('DatePicker', () => { TestUtils.Simulate.change(input) expect(cleared).to.be.true }) + it('should correctly update the date input when utcOffset is all that changes on the selected date', () => { + var date = moment('2016-11-22T00:00:00Z').utcOffset(-6) + var tmzDatePicker = mount() + tmzDatePicker.setState({startDate: date, utcOffset: -6}) + + expect(tmzDatePicker.find('input').prop('value')).to.equal('2016-11-21 18:00') + + tmzDatePicker.setState({utcOffset: 6, startDate: date.clone().utcOffset(6)}) + + expect(tmzDatePicker.find('input').prop('value')).to.equal('2016-11-22 06:00') + }) }) diff --git a/test/timezone_date_picker.jsx b/test/timezone_date_picker.jsx new file mode 100644 index 0000000000..91c1fd79cb --- /dev/null +++ b/test/timezone_date_picker.jsx @@ -0,0 +1,26 @@ +import React from 'react' +import DatePicker from '../src/datepicker.jsx' + +class TimezoneDatePicker extends React.Component { + constructor (props) { + super(props) + this.state = { startDate: null, utcOffset: -4 } + } + + handleChange (date) { + this.setState({ startDate: date }) + } + + render () { + var selected = this.state.startDate && + this.state.startDate.clone().utcOffset(this.state.utcOffset) + + return + } +} + +export default TimezoneDatePicker