UNPKG

5.26 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11'use strict';
12
13var _assign = require('object-assign');
14
15var CallbackQueue = require('./CallbackQueue');
16var PooledClass = require('./PooledClass');
17var ReactBrowserEventEmitter = require('./ReactBrowserEventEmitter');
18var ReactInputSelection = require('./ReactInputSelection');
19var ReactInstrumentation = require('./ReactInstrumentation');
20var Transaction = require('./Transaction');
21var ReactUpdateQueue = require('./ReactUpdateQueue');
22
23/**
24 * Ensures that, when possible, the selection range (currently selected text
25 * input) is not disturbed by performing the transaction.
26 */
27var SELECTION_RESTORATION = {
28 /**
29 * @return {Selection} Selection information.
30 */
31 initialize: ReactInputSelection.getSelectionInformation,
32 /**
33 * @param {Selection} sel Selection information returned from `initialize`.
34 */
35 close: ReactInputSelection.restoreSelection
36};
37
38/**
39 * Suppresses events (blur/focus) that could be inadvertently dispatched due to
40 * high level DOM manipulations (like temporarily removing a text input from the
41 * DOM).
42 */
43var EVENT_SUPPRESSION = {
44 /**
45 * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
46 * the reconciliation.
47 */
48 initialize: function () {
49 var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
50 ReactBrowserEventEmitter.setEnabled(false);
51 return currentlyEnabled;
52 },
53
54 /**
55 * @param {boolean} previouslyEnabled Enabled status of
56 * `ReactBrowserEventEmitter` before the reconciliation occurred. `close`
57 * restores the previous value.
58 */
59 close: function (previouslyEnabled) {
60 ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
61 }
62};
63
64/**
65 * Provides a queue for collecting `componentDidMount` and
66 * `componentDidUpdate` callbacks during the transaction.
67 */
68var ON_DOM_READY_QUEUEING = {
69 /**
70 * Initializes the internal `onDOMReady` queue.
71 */
72 initialize: function () {
73 this.reactMountReady.reset();
74 },
75
76 /**
77 * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
78 */
79 close: function () {
80 this.reactMountReady.notifyAll();
81 }
82};
83
84/**
85 * Executed within the scope of the `Transaction` instance. Consider these as
86 * being member methods, but with an implied ordering while being isolated from
87 * each other.
88 */
89var TRANSACTION_WRAPPERS = [SELECTION_RESTORATION, EVENT_SUPPRESSION, ON_DOM_READY_QUEUEING];
90
91if (process.env.NODE_ENV !== 'production') {
92 TRANSACTION_WRAPPERS.push({
93 initialize: ReactInstrumentation.debugTool.onBeginFlush,
94 close: ReactInstrumentation.debugTool.onEndFlush
95 });
96}
97
98/**
99 * Currently:
100 * - The order that these are listed in the transaction is critical:
101 * - Suppresses events.
102 * - Restores selection range.
103 *
104 * Future:
105 * - Restore document/overflow scroll positions that were unintentionally
106 * modified via DOM insertions above the top viewport boundary.
107 * - Implement/integrate with customized constraint based layout system and keep
108 * track of which dimensions must be remeasured.
109 *
110 * @class ReactReconcileTransaction
111 */
112function ReactReconcileTransaction(useCreateElement) {
113 this.reinitializeTransaction();
114 // Only server-side rendering really needs this option (see
115 // `ReactServerRendering`), but server-side uses
116 // `ReactServerRenderingTransaction` instead. This option is here so that it's
117 // accessible and defaults to false when `ReactDOMComponent` and
118 // `ReactDOMTextComponent` checks it in `mountComponent`.`
119 this.renderToStaticMarkup = false;
120 this.reactMountReady = CallbackQueue.getPooled(null);
121 this.useCreateElement = useCreateElement;
122}
123
124var Mixin = {
125 /**
126 * @see Transaction
127 * @abstract
128 * @final
129 * @return {array<object>} List of operation wrap procedures.
130 * TODO: convert to array<TransactionWrapper>
131 */
132 getTransactionWrappers: function () {
133 return TRANSACTION_WRAPPERS;
134 },
135
136 /**
137 * @return {object} The queue to collect `onDOMReady` callbacks with.
138 */
139 getReactMountReady: function () {
140 return this.reactMountReady;
141 },
142
143 /**
144 * @return {object} The queue to collect React async events.
145 */
146 getUpdateQueue: function () {
147 return ReactUpdateQueue;
148 },
149
150 /**
151 * Save current transaction state -- if the return value from this method is
152 * passed to `rollback`, the transaction will be reset to that state.
153 */
154 checkpoint: function () {
155 // reactMountReady is the our only stateful wrapper
156 return this.reactMountReady.checkpoint();
157 },
158
159 rollback: function (checkpoint) {
160 this.reactMountReady.rollback(checkpoint);
161 },
162
163 /**
164 * `PooledClass` looks for this, and will invoke this before allowing this
165 * instance to be reused.
166 */
167 destructor: function () {
168 CallbackQueue.release(this.reactMountReady);
169 this.reactMountReady = null;
170 }
171};
172
173_assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
174
175PooledClass.addPoolingTo(ReactReconcileTransaction);
176
177module.exports = ReactReconcileTransaction;
\No newline at end of file