Index: trunk/extensions/VisualEditor/tests/es/index.html |
— | — | @@ -32,6 +32,7 @@ |
33 | 33 | <!-- Models --> |
34 | 34 | <script src="../../modules/es/models/es.DocumentModel.js"></script> |
35 | 35 | <script src="../../modules/es/models/es.HistoryModel.js"></script> |
| 36 | + <script src="../../modules/es/models/es.HistoryStateModel.js"></script> |
36 | 37 | <script src="../../modules/es/models/es.ListItemModel.js"></script> |
37 | 38 | <script src="../../modules/es/models/es.ListModel.js"></script> |
38 | 39 | <script src="../../modules/es/models/es.ParagraphModel.js"></script> |
Index: trunk/extensions/VisualEditor/demo/index.html |
— | — | @@ -82,6 +82,7 @@ |
83 | 83 | <script src="../modules/es/models/es.SurfaceModel.js"></script> |
84 | 84 | <script src="../modules/es/models/es.DocumentModel.js"></script> |
85 | 85 | <script src="../modules/es/models/es.HistoryModel.js"></script> |
| 86 | + <script src="../modules/es/models/es.HistoryStateModel.js"></script> |
86 | 87 | <script src="../modules/es/models/es.ParagraphModel.js"></script> |
87 | 88 | <script src="../modules/es/models/es.PreModel.js"></script> |
88 | 89 | <script src="../modules/es/models/es.ListModel.js"></script> |
Index: trunk/extensions/VisualEditor/modules/es/models/es.HistoryModel.js |
— | — | @@ -12,13 +12,13 @@ |
13 | 13 | |
14 | 14 | // Properties |
15 | 15 | this.doc = doc; |
16 | | - this.states = []; |
17 | | - this.currentStateIndex = -1; |
18 | | - this.transactions = []; |
19 | | - this.transactionsDiff = 0; |
| 16 | + this.currentState = new es.HistoryStateModel(); |
| 17 | + this.currentStateIndex = 0; |
| 18 | + this.states = [this.currentState]; |
| 19 | + this.currentStateDiff = 0; |
20 | 20 | |
21 | 21 | // Configuration |
22 | | - this.maxTransactionsDiff = 24; |
| 22 | + this.maxStateDiff = 24; |
23 | 23 | }; |
24 | 24 | |
25 | 25 | /* Methods */ |
— | — | @@ -33,6 +33,15 @@ |
34 | 34 | }; |
35 | 35 | |
36 | 36 | /** |
| 37 | + * Gets the index of the current state. |
| 38 | + * |
| 39 | + * |
| 40 | + */ |
| 41 | +es.HistoryModel.prototype.getCurrentStateSelection = function() { |
| 42 | + return this.currentState.getSelection(); |
| 43 | +}; |
| 44 | + |
| 45 | +/** |
37 | 46 | * Gets the number of states available. |
38 | 47 | * |
39 | 48 | * @method |
— | — | @@ -72,24 +81,26 @@ |
73 | 82 | * |
74 | 83 | * @method |
75 | 84 | * @param {es.TransactionModel} transaction Transaction to commit |
76 | | - * @param {Boolean} accumulate Prevent automatic state pushing |
| 85 | + * @param {es.Range} [selection] Selection to use after the transaction has been applied |
| 86 | + * @param {Boolean} [accumulate] Prevent automatic state pushing |
77 | 87 | */ |
78 | | -es.HistoryModel.prototype.commit = function( transaction, accumulate ) { |
79 | | - var absLengthDiff = Math.abs( transaction.getLengthDiff() ); |
| 88 | +es.HistoryModel.prototype.commit = function( transaction, selection, accumulate ) { |
| 89 | + var transactionDiff = Math.abs( transaction.getLengthDiff() ); |
80 | 90 | // Unless we should intentionally accumulate transactions or this is the first one for this |
81 | 91 | // state, automatically push state |
82 | | - if ( !accumulate && this.transactions.length ) { |
| 92 | + var transactionCount = this.currentState.getTransactionCount(); |
| 93 | + if ( !accumulate && transactionCount ) { |
83 | 94 | if ( |
84 | 95 | // If the transactions are of a different type |
85 | | - this.transactions[this.transactions.length - 1].type !== transaction.type || |
| 96 | + this.currentState.getTransactions()[transactionCount - 1].type !== transaction.type || |
86 | 97 | // This transaction would make the state longer than the maximum length |
87 | | - this.transactionsDiff + absLengthDiff > this.maxTransactionsDiff |
| 98 | + this.currentStateDiff + transactionDiff > this.maxStateDiff |
88 | 99 | ) { |
89 | 100 | this.pushState(); |
90 | 101 | } |
91 | 102 | } |
92 | | - this.transactions.push( transaction ); |
93 | | - this.transactionsDiff += absLengthDiff; |
| 103 | + this.currentState.pushTransaction( transaction ); |
| 104 | + this.currentStateDiff += transactionDiff; |
94 | 105 | // Apply transaction to the document |
95 | 106 | this.doc.commit( transaction ); |
96 | 107 | // Emit a do event with the transaction that was just committed |
— | — | @@ -103,7 +114,7 @@ |
104 | 115 | */ |
105 | 116 | es.HistoryModel.prototype.pushState = function() { |
106 | 117 | // If any transactions have been pushed since the last state push |
107 | | - if ( this.transactions.length ) { |
| 118 | + if ( this.currentState.getTransactionCount() ) { |
108 | 119 | // If the current state is not the most recently added state |
109 | 120 | if ( this.currentStateIndex < this.states.length - 1 ) { |
110 | 121 | // Forget about states newer than the current one |
— | — | @@ -111,14 +122,17 @@ |
112 | 123 | this.currentStateIndex, this.states.length - this.currentStateIndex |
113 | 124 | ); |
114 | 125 | } |
115 | | - // Add accumulated transactions as a state |
116 | | - this.states.push( this.transactions ); |
117 | | - // Clear the transaction buffer |
118 | | - this.transactions = []; |
119 | | - this.transactionsDiff = 0; |
120 | | - // Move the current state forward |
121 | | - this.currentStateIndex++; |
| 126 | + // Create a new current state |
| 127 | + this.currentState = new es.HistoryStateModel(); |
| 128 | + // Add the new current state to the stack |
| 129 | + this.states.push( this.currentState ); |
| 130 | + // Reset the state diff counter |
| 131 | + this.currentStateDiff = 0; |
| 132 | + // Move the current state index to the end (should be equivilant of ++) |
| 133 | + this.currentStateIndex = this.states.length - 1; |
122 | 134 | } |
| 135 | + // Emit the completed |
| 136 | + this.emit( 'pushState', this.states[this.states.length - 1] ); |
123 | 137 | }; |
124 | 138 | |
125 | 139 | /** |
— | — | @@ -130,16 +144,15 @@ |
131 | 145 | if ( steps === undefined ) { |
132 | 146 | steps = 1; |
133 | 147 | } |
134 | | - // Apply transactions in the buffer |
135 | | - this.pushState(); |
136 | 148 | // Stop undo just before the first state |
137 | 149 | var previousStateIndex = this.currentStateIndex; |
138 | 150 | this.currentStateIndex = Math.max( -1, this.currentStateIndex - steps ); |
139 | 151 | if ( previousStateIndex > this.currentStateIndex ) { |
140 | 152 | for ( var i = previousStateIndex; i > this.currentStateIndex; i-- ) { |
141 | 153 | // Apply transaction to the document |
142 | | - for ( var j = this.states[i].length - 1; j >= 0; j-- ) { |
143 | | - this.doc.rollback( this.states[i][j] ); |
| 154 | + var transactions = this.states[i].getTransactions(); |
| 155 | + for ( var j = transactions.length - 1; j >= 0; j-- ) { |
| 156 | + this.doc.rollback( transactions[j] ); |
144 | 157 | } |
145 | 158 | // Emit an undo event with the state to be rolled back |
146 | 159 | this.emit( 'undo', this.states[i] ); |
— | — | @@ -156,15 +169,16 @@ |
157 | 170 | if ( steps === undefined ) { |
158 | 171 | steps = 1; |
159 | 172 | } |
160 | | - // Apply transactions in the buffer |
161 | | - this.pushState(); |
162 | 173 | // Stop redo at the last state |
163 | 174 | var previousStateIndex = this.currentStateIndex; |
164 | 175 | this.currentStateIndex = Math.min( this.states.length - 1, this.currentStateIndex + steps ); |
165 | 176 | if ( previousStateIndex < this.currentStateIndex ) { |
166 | 177 | for ( var i = previousStateIndex + 1; i >= this.currentStateIndex; i++ ) { |
167 | 178 | // Apply transaction to the document |
168 | | - this.doc.rollback( this.states[i] ); |
| 179 | + var transactions = this.states[i].getTransactions(); |
| 180 | + for ( var j = 0; j < transactions.length; j++ ) { |
| 181 | + this.doc.commit( transactions[j] ); |
| 182 | + } |
169 | 183 | // Emit an undo event with the state to be rolled back |
170 | 184 | this.emit( 'redo', this.states[i] ); |
171 | 185 | } |
Index: trunk/extensions/VisualEditor/modules/es/models/es.HistoryStateModel.js |
— | — | @@ -0,0 +1,31 @@ |
| 2 | +/** |
| 3 | + * Creates an es.HistoryStateModel object. |
| 4 | + * |
| 5 | + * @class |
| 6 | + * @constructor |
| 7 | + */ |
| 8 | +es.HistoryStateModel = function() { |
| 9 | + this.transactions = []; |
| 10 | + this.selection = null; |
| 11 | +}; |
| 12 | + |
| 13 | +/* Methods */ |
| 14 | + |
| 15 | +es.HistoryStateModel.prototype.getSelection = function() { |
| 16 | + return this.selection; |
| 17 | +}; |
| 18 | + |
| 19 | +es.HistoryStateModel.prototype.getTransactions = function() { |
| 20 | + return this.transactions; |
| 21 | +}; |
| 22 | + |
| 23 | +es.HistoryStateModel.prototype.getTransactionCount = function() { |
| 24 | + return this.transactions.length; |
| 25 | +}; |
| 26 | + |
| 27 | +es.HistoryStateModel.prototype.pushTransaction = function( transaction, selection ) { |
| 28 | + this.transactions.push( transaction ); |
| 29 | + if ( selection !== undefined ) { |
| 30 | + this.selection = selection.clone(); |
| 31 | + } |
| 32 | +}; |