UNPKG

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