new file mode 100644
---wp-admin/includes/revision.php (revision 0)n+++wp-admin/includes/revision.php (revision 0)
@@ -0,0 +1,92 @@
+<?php
+
+function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) {
+ if ( ! $post = get_post( $post ) )
+ return false;
+
+ if ( $compare_from ) {
+ if ( ! $compare_from = get_post( $compare_from ) )
+ return false;
+ } else {
+ // If we're dealing with the first revision...
+ $compare_from = false;
+ }
+
+ if ( ! $compare_to = get_post( $compare_to ) )
+ return false;
+
+ // If comparing revisions, make sure we're dealing with the right post parent.
+ if ( $compare_from && $compare_from->post_parent !== $post->ID )
+ return false;
+ if ( $compare_to->post_parent !== $post->ID )
+ return false;
+
+ if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) {
+ $temp = $compare_from;
+ $compare_from = $compare_to;
+ $compare_to = $temp;
+ }
+
+ $return = array();
+
+ foreach ( _wp_post_revision_fields() as $field => $name ) {
+ $content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'left' ) : '';
+ $content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'right' );
+
+ $diff = wp_text_diff( $content_from, $content_to, array( 'show_split_view' => true ) );
+
+ if ( ! $diff && 'post_title' === $field ) {
+ // It's a better user experience to still show the Title, even if it didn't change.
+ // No, you didn't see this.
+ $diff = "<table class='diff'><col class='ltype' /><col class='content' /><col class='ltype' /><col class='content' /><tbody><tr>";
+ $diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>';
+ $diff .= '</tr></tbody>';
+ $diff .= '</table>';
+ }
+
+ if ( $diff ) {
+ $return[] = array(
+ 'id' => $field,
+ 'name' => $name,
+ 'diff' => $diff,
+ );
+ }
+ }
+ return $return;
+}
+
+function wp_prepare_revisions_for_js( $post ) {
+ $post = get_post( $post );
+ $revisions = array();
+ $current = current_time( 'timestamp' );
+
+ $revisions = wp_get_post_revisions( $post->ID );
+
+ cache_users( wp_list_pluck( $revisions, 'post_author' ) );
+
+ foreach ( $revisions as $revision ) {
+ $modified_gmt = strtotime( $revision->post_modified_gmt );
+ $revisions[ $revision->ID ] = array(
+ 'id' => $revision->ID,
+ 'title' => get_the_title( $post->ID ),
+ 'author' => array(
+ 'id' => (int) $revision->post_author,
+ 'avatar' => get_avatar( $revision->post_author, 24 ),
+ 'name' => get_the_author_meta( 'display_name', $revision->post_author ),
+ ),
+ 'date' => date_i18n( __( 'M j, Y @ G:i' ), $modified_gmt ),
+ 'dateShort' => date_i18n( _x( 'j M @ G:i', 'revision date short format' ), $modified_gmt ),
+ 'timeAgo' => human_time_diff( $modified_gmt, $current ),
+ 'autosave' => wp_is_post_autosave( $revision ),
+ 'current' => $revision->post_modified_gmt === $post->post_modified_gmt,
+ 'restoreNonce' => wp_create_nonce( 'restore-post_' . $revision->ID ),
+ );
+ }
+
+ return array(
+ 'postId' => $post->ID,
+ 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ),
+ 'restoreUrl' => admin_url( 'revision.php?action=restore' ), // &revision=$ID&_wpnonce=$restoreNonce
+ 'revisionData' => array_values( $revisions ),
+ );
+}
|
|
|
1 | 1 | window.wp = window.wp || {}; |
2 | 2 | |
3 | 3 | (function($) { |
4 | | var Revision, Revisions, Diff, revisions; |
| 4 | var revisions; |
5 | 5 | |
6 | | revisions = wp.revisions = function() { |
7 | | Diff = revisions.Diff = new Diff(); |
8 | | }; |
9 | | |
10 | | _.extend( revisions, { model: {}, view: {}, controller: {} } ); |
| 6 | revisions = wp.revisions = { model: {}, view: {}, controller: {} }; |
11 | 7 | |
12 | 8 | // Link settings. |
13 | | revisions.model.settings = typeof wpRevisionsSettings === 'undefined' ? {} : wpRevisionsSettings; |
| 9 | revisions.settings = typeof _wpRevisionsSettings === 'undefined' ? {} : _wpRevisionsSettings; |
14 | 10 | |
15 | 11 | |
16 | 12 | /** |
17 | 13 | * ======================================================================== |
18 | | * CONTROLLERS |
| 14 | * MODELS |
19 | 15 | * ======================================================================== |
20 | 16 | */ |
| 17 | revisions.model.Slider = Backbone.Model.extend({ |
| 18 | defaults: { |
| 19 | value: 0, |
| 20 | min: 0, |
| 21 | max: 1, |
| 22 | step: 1 |
| 23 | } |
| 24 | }); |
21 | 25 | |
22 | | /** |
23 | | * wp.revisions.controller.Diff |
24 | | * |
25 | | * Controlls the diff |
26 | | */ |
27 | | Diff = revisions.controller.Diff = Backbone.Model.extend( { |
28 | | rightDiff: 1, |
29 | | leftDiff: 1, |
30 | | revisions: null, |
31 | | leftHandleRevisions: null, |
32 | | rightHandleRevisions: null, |
33 | | revisionsInteractions: null, |
34 | | autosaves: true, |
35 | | showSplitView: true, |
36 | | singleRevision: true, |
37 | | leftModelLoading: false, // keep track of model loads |
38 | | rightModelLoading: false, // disallow slider interaction, also repeat loads, while loading |
39 | | tickmarkView: null, // the slider tickmarks |
40 | | slider: null, // the slider instance |
41 | | |
42 | | constructor: function() { |
43 | | var self = this; |
44 | | this.slider = new revisions.view.Slider(); |
45 | | |
46 | | if ( null === this.revisions ) { |
47 | | this.revisions = new Revisions(); // set up collection |
48 | | this.startRightModelLoading(); |
49 | | |
50 | | this.revisions.fetch({ // load revision data |
51 | | success: function() { |
52 | | self.stopRightModelLoading(); |
53 | | self.completeApplicationSetup(); |
54 | | } |
55 | | }); |
56 | | } |
57 | | }, |
58 | | |
59 | | loadDiffs: function( models ) { |
60 | | var self = this, |
61 | | revisionsToLoad = models.where( { completed: false } ), |
62 | | delay = 0, |
63 | | totalChanges; |
64 | | |
65 | | // match slider to passed revision_id |
66 | | _.each( revisionsToLoad, function( revision ) { |
67 | | if ( revision.get( 'ID' ) == revisions.model.settings.revision_id ) |
68 | | self.rightDiff = self.revisions.indexOf( revision ) + 1; |
69 | | }); |
| 26 | revisions.model.Revision = Backbone.Model.extend({}); |
70 | 27 | |
71 | | _.each( revisionsToLoad, function( revision ) { |
72 | | _.delay( function() { |
73 | | revision.fetch( { |
74 | | update: true, |
75 | | add: false, |
76 | | remove: false, |
77 | | success: function( model ) { |
78 | | model.set( 'completed', true ); |
79 | | |
80 | | // stop spinner when all models are loaded |
81 | | if ( 0 === models.where( { completed: false } ).length ) |
82 | | self.stopModelLoadingSpinner(); |
83 | | |
84 | | totalChanges = model.get( 'linesAdded' ) + model.get( 'linesDeleted' ), |
85 | | scopeOfChanges = 'vsmall'; |
86 | | |
87 | | // Note: hard coded scope of changes |
88 | | // TODO change to dynamic based on range of values |
89 | | if ( totalChanges > 1 && totalChanges <= 3 ) { |
90 | | scopeOfChanges = 'small'; |
91 | | } else if ( totalChanges > 3 && totalChanges <= 5 ) { |
92 | | scopeOfChanges = 'med'; |
93 | | } else if ( totalChanges > 5 && totalChanges <= 10 ) { |
94 | | scopeOfChanges = 'large'; |
95 | | } else if ( totalChanges > 10 ) { |
96 | | scopeOfChanges = 'vlarge'; |
97 | | } |
98 | | model.set( 'scopeOfChanges', scopeOfChanges ); |
99 | | if ( 0 !== self.rightDiff && |
100 | | model.get( 'ID' ) === self.revisions.at( self.rightDiff - 1 ).get( 'ID' ) ) { |
101 | | // reload if current model refreshed |
102 | | self.revisionView.render(); |
103 | | } |
104 | | self.tickmarkView.render(); |
105 | | } |
106 | | } ); |
107 | | }, delay ) ; |
108 | | delay = delay + 150; // stagger model loads to avoid hammering server with requests |
109 | | } |
110 | | ); |
111 | | }, |
| 28 | revisions.model.Revisions = Backbone.Collection.extend({ |
| 29 | model: revisions.model.Revision, |
112 | 30 | |
113 | | startLeftModelLoading: function() { |
114 | | this.leftModelLoading = true; |
115 | | $('#revision-diff-container').addClass('left-model-loading'); |
| 31 | comparator: function( revision ) { |
| 32 | return revision.id; |
116 | 33 | }, |
| 34 | }); |
117 | 35 | |
118 | | stopLeftModelLoading: function() { |
119 | | this.leftModelLoading = false; |
120 | | }, |
| 36 | revisions.model.Field = Backbone.Model.extend({}); |
121 | 37 | |
122 | | startRightModelLoading: function() { |
123 | | this.rightModelLoading = true; |
124 | | $('#revision-diff-container').addClass('right-model-loading'); |
125 | | }, |
126 | | |
127 | | stopRightModelLoading: function() { |
128 | | this.rightModelLoading = false; |
129 | | }, |
| 38 | revisions.model.Fields = Backbone.Collection.extend({ |
| 39 | model: revisions.model.Field |
| 40 | }); |
130 | 41 | |
131 | | stopModelLoadingSpinner: function() { |
132 | | $('#revision-diff-container').removeClass('right-model-loading'); |
133 | | $('#revision-diff-container').removeClass('left-model-loading'); |
134 | | }, |
| 42 | revisions.model.Diff = Backbone.Model.extend({ |
| 43 | initialize: function(attributes, options) { |
| 44 | var fields = this.get('fields'); |
| 45 | this.unset('fields'); |
135 | 46 | |
136 | | reloadModel: function() { |
137 | | if ( this.singleRevision ) { |
138 | | this.reloadModelSingle(); |
139 | | } else { |
140 | | this.reloadLeftRight(); |
141 | | } |
142 | | }, |
| 47 | this.fields = new revisions.model.Fields( fields ); |
| 48 | } |
| 49 | }); |
143 | 50 | |
144 | | // load the models for the single handle mode |
145 | | reloadModelSingle: function() { |
146 | | var self = this; |
147 | | |
148 | | self.startRightModelLoading(); |
149 | | |
150 | | self.revisions.reload({ |
151 | | options: { |
152 | | 'showAutosaves': self.autosaves, |
153 | | 'showSplitView': self.showSplitView |
154 | | }, |
155 | | |
156 | | success: function() { |
157 | | var revisionCount = self.revisions.length; |
158 | | self.revisionView.model = self.revisions; |
159 | | self.revisionView.render(); |
160 | | self.loadDiffs( self.revisions ); |
161 | | self.tickmarkView.model = self.revisions; |
162 | | self.tickmarkView.render(); |
163 | | self.slider.refresh({ |
164 | | 'max': revisionCount - 1, // slider starts at 0 in single handle mode |
165 | | 'value': self.rightDiff - 1 // slider starts at 0 in single handle mode |
166 | | }, true); |
167 | | }, |
168 | | |
169 | | error: function() { |
170 | | self.stopRightModelLoading(); |
171 | | } |
172 | | }); |
| 51 | revisions.model.Diffs = Backbone.Collection.extend({ |
| 52 | initialize: function(models, options) { |
| 53 | this.revisions = options.revisions; |
| 54 | this.requests = {}; |
173 | 55 | }, |
174 | 56 | |
175 | | // load the models for the left handle (the right handler has moved) |
176 | | reloadLeft: function() { |
177 | | var self = this; |
178 | | self.startLeftModelLoading(); |
179 | | self.leftHandleRevisions = new Revisions( {}, { |
180 | | 'compareTo': self.revisions.at( self.rightDiff - 1 ).get( 'ID' ), // diff and model count off by 1 |
181 | | 'showAutosaves': self.autosaves, |
182 | | 'showSplitView': self.showSplitView, |
183 | | 'rightHandleAt': self.rightDiff |
184 | | }); |
| 57 | model: revisions.model.Diff, |
185 | 58 | |
186 | | self.leftHandleRevisions.fetch({ |
187 | | success: function(){ |
188 | | self.stopLeftModelLoading(); |
189 | | self.loadDiffs( self.leftHandleRevisions ); |
190 | | self.tickmarkView.model = self.leftHandleRevisions; |
191 | | self.slider.refresh({ |
192 | | 'max': self.revisions.length |
193 | | }); |
194 | | // ensure right handle not beyond length |
195 | | if ( self.rightDiff > self.revisions.length ) |
196 | | self.rightDiff = self.revisions.length; |
197 | | }, |
| 59 | ensure: function( id, context ) { |
| 60 | var diff = this.get( id ); |
| 61 | var request = this.requests[ id ]; |
| 62 | var deferred = $.Deferred(); |
| 63 | var ids = {}; |
198 | 64 | |
199 | | error: function() { |
200 | | self.stopLeftModelLoading(); |
| 65 | if ( diff ) { |
| 66 | deferred.resolveWith( context, [ diff ] ); |
| 67 | } else { |
| 68 | this.trigger( 'ensure:load', ids ); |
| 69 | _.each( ids, _.bind( function(id) { |
| 70 | // Remove anything that has an ongoing request |
| 71 | if ( this.requests[ id ] ) |
| 72 | delete ids[ id ]; |
| 73 | }, this ) ); |
| 74 | if ( ! request ) { |
| 75 | // Always include the ID that started this ensure |
| 76 | ids[ id ] = true; |
| 77 | request = this.load( _.keys( ids ) ); |
201 | 78 | } |
202 | | }); |
203 | | }, |
204 | 79 | |
205 | | // load the models for the right handle (the left handle has moved) |
206 | | reloadRight: function() { |
207 | | var self = this; |
208 | | self.startRightModelLoading(); |
209 | | self.rightHandleRevisions = new Revisions( {}, { |
210 | | 'compareTo': self.revisions.at( self.leftDiff - 1 ).get( 'ID' ), // diff and model count off by 1 |
211 | | 'showAutosaves': self.autosaves, |
212 | | 'showSplitView': self.showSplitView, |
213 | | 'leftHandleAt': self.leftDiff |
214 | | }); |
215 | | |
216 | | self.rightHandleRevisions.fetch({ |
217 | | success: function(){ |
218 | | self.stopRightModelLoading(); |
219 | | self.loadDiffs( self.rightHandleRevisions ); |
220 | | self.tickmarkView.model = self.rightHandleRevisions; |
221 | | self.slider.refresh({ |
222 | | 'max': self.revisions.length |
223 | | }, true); |
224 | | }, |
225 | | |
226 | | error: function( response ) { |
227 | | self.stopRightModelLoading(); |
228 | | } |
229 | | }); |
| 80 | request.done( _.bind( function() { |
| 81 | deferred.resolveWith( context, [ this.get( id ) ] ); |
| 82 | }, this ) ); |
| 83 | } |
230 | 84 | |
| 85 | return deferred.promise(); |
231 | 86 | }, |
232 | 87 | |
233 | | /** |
234 | | * reloadLeftRight reload models for both the left and right handles |
235 | | */ |
236 | | reloadLeftRight: function() { |
237 | | this.startRightModelLoading(); |
238 | | this.startLeftModelLoading(); |
239 | | this.reloadLeft(); |
240 | | this.reloadRight(); |
| 88 | loadNew: function( comparisons ) { |
| 89 | comparisons = _.object( comparisons, comparisons ); |
| 90 | _.each( comparisons, _.bind( function( id ) { |
| 91 | // Exists |
| 92 | if ( this.get( id ) ) |
| 93 | delete comparisons[ id ]; |
| 94 | }, this ) ); |
| 95 | comparisons = _.toArray( comparisons ); |
| 96 | console.log( 'Loading', comparisons ); |
| 97 | return this.load( comparisons ); |
241 | 98 | }, |
242 | 99 | |
243 | | disabledButtonCheck: function( val ) { |
244 | | var maxVal = this.revisions.length - 1, |
245 | | next = ! isRtl ? $( '#next' ) : $( '#previous' ), |
246 | | prev = ! isRtl ? $( '#previous' ) : $( '#next' ); |
247 | | |
248 | | // Disable "Next" button if you're on the last node |
249 | | if ( maxVal === val ) |
250 | | next.prop( 'disabled', true ); |
251 | | else |
252 | | next.prop( 'disabled', false ); |
253 | | |
254 | | // Disable "Previous" button if you're on the 0 node |
255 | | if ( 0 === val ) |
256 | | prev.prop( 'disabled', true ); |
257 | | else |
258 | | prev.prop( 'disabled', false ); |
259 | | }, |
260 | | |
261 | | /** |
262 | | * completeApplicationSetup finishes loading all views once the initial model load is complete |
263 | | */ |
264 | | completeApplicationSetup: function() { |
265 | | this.revisionView = new revisions.view.Diff({ |
266 | | model: this.revisions |
267 | | }); |
268 | | this.revisionView.render(); // render the revision view |
269 | | |
270 | | this.loadDiffs( this.revisions ); // get the actual revisions data |
271 | | |
272 | | this.revisionsInteractions = new revisions.view.Interact({ |
273 | | model: this.revisions |
274 | | }); |
275 | | this.revisionsInteractions.render(); // render the interaction view |
276 | | |
277 | | this.tickmarkView = new revisions.view.Tickmarks({ |
278 | | model: this.revisions |
279 | | }); |
280 | | this.tickmarkView.render(); // render the tickmark view |
281 | | } |
282 | | }); |
283 | | |
284 | | |
285 | | /** |
286 | | * ======================================================================== |
287 | | * VIEWS |
288 | | * ======================================================================== |
289 | | */ |
290 | | |
291 | | /** |
292 | | * wp.revisions.view.Slider |
293 | | * |
294 | | * The slider |
295 | | */ |
296 | | revisions.view.Slider = Backbone.View.extend({ |
297 | | el: $( '#diff-slider' ), |
298 | | singleRevision: true, |
299 | | |
300 | | initialize: function( options ) { |
301 | | this.options = _.defaults( options || {}, { |
302 | | value: 0, |
303 | | min: 0, |
304 | | max: 1, |
305 | | step: 1 |
306 | | }); |
| 100 | load: function( comparisons ) { |
| 101 | // Our collection should only ever grow, never shrink, so remove: false |
| 102 | return this.fetch({ data: { compare: comparisons }, remove: false }); |
307 | 103 | }, |
308 | 104 | |
309 | | /** |
310 | | * respond to slider slide events |
311 | | * Note: in one handle mode, jQuery UI reports leftmost position as 0 |
312 | | * in two handle mode, jQuery UI Slider reports leftmost position as 1 |
313 | | */ |
314 | | slide: function( event, ui ) { |
315 | | if ( this.singleRevision ) { |
316 | | Diff.rightDiff = ( ui.value + 1 ); |
317 | | Diff.revisionView.render(); |
318 | | Diff.disabledButtonCheck( ui.value ); |
319 | | } else { |
320 | | if ( ui.values[0] === ui.values[1] ) // prevent compare to self |
321 | | return false; |
322 | | |
323 | | if ( $( ui.handle ).hasClass( 'left-handle' ) ) { |
324 | | // Left handler |
325 | | if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle |
326 | | return false; |
327 | | |
328 | | Diff.leftDiff = isRtl ? ui.values[1] : ui.values[0]; // handles are reversed in RTL mode |
329 | | } else { |
330 | | // Right handler |
331 | | if ( Diff.rightModelLoading ) // right model still loading, prevent sliding right handle |
332 | | return false; |
333 | | |
334 | | Diff.rightDiff = isRtl ? ui.values[0] : ui.values[1]; // handles are reversed in RTL mode |
335 | | } |
336 | | |
337 | | Diff.revisionView.render(); |
| 105 | /**/ |
| 106 | loadLast: function( num ) { |
| 107 | num = num || 1; |
| 108 | var ids = this.getProximalDiffIds(); |
| 109 | ids = _.last( ids, num ); |
| 110 | if ( ids.length ) { |
| 111 | console.log( 'Last ' + num, ids ); |
| 112 | return this.loadNew( ids ); |
338 | 113 | } |
339 | 114 | }, |
340 | 115 | |
341 | | /** |
342 | | * responds to slider start sliding events |
343 | | * in two handle mode stores start position, so if unchanged at stop event no need to reload diffs |
344 | | * also swaps in the appropriate models - left handled or right handled |
345 | | */ |
346 | | start: function( event, ui ) { |
347 | | // Not needed in one mode |
348 | | if ( this.singleRevision ) |
349 | | return; |
350 | | |
351 | | if ( $( ui.handle ).hasClass( 'left-handle' ) ) { |
352 | | // Left handler |
353 | | if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle |
354 | | return false; |
355 | | |
356 | | Diff.revisionView.draggingLeft = true; |
357 | | |
358 | | if ( Diff.revisionView.model !== Diff.leftHandleRevisions && |
359 | | null !== Diff.leftHandleRevisions ) { |
360 | | Diff.revisionView.model = Diff.leftHandleRevisions; // use the left handle models |
361 | | Diff.tickmarkView.model = Diff.leftHandleRevisions; |
362 | | Diff.tickmarkView.render(); |
363 | | } |
364 | | |
365 | | Diff.leftDiffStart = isRtl ? ui.values[1] : ui.values[0]; // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
366 | | |
367 | | } else { |
368 | | // Right handler |
369 | | if ( Diff.rightModelLoading || 0 === Diff.rightHandleRevisions.length) // right model still loading, prevent sliding right handle |
370 | | return false; |
371 | | |
372 | | if ( Diff.revisionView.model !== Diff.rightHandleRevisions && |
373 | | null !== Diff.rightHandleRevisions ) { |
374 | | Diff.revisionView.model = Diff.rightHandleRevisions; // use the right handle models |
375 | | Diff.tickmarkView.model = Diff.rightHandleRevisions; |
376 | | Diff.tickmarkView.render(); |
377 | | } |
378 | | |
379 | | Diff.revisionView.draggingLeft = false; |
380 | | Diff.rightDiffStart = isRtl ? ui.values[0] : ui.values[1]; // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
| 116 | loadLastUnloaded: function( num ) { |
| 117 | num = num || 1; |
| 118 | var ids = this.getUnloadedProximalDiffIds(); |
| 119 | ids = _.last( ids, num ); |
| 120 | if ( ids.length ) { |
| 121 | console.log( 'Loading last ' + num ); |
| 122 | return this.loadNew( ids ); |
381 | 123 | } |
382 | 124 | }, |
383 | 125 | |
384 | | /** |
385 | | * responds to slider stop events |
386 | | * in two handled mode, if the handle that stopped has moved, reload the diffs for the other handle |
387 | | * the other handle compares to this handle's position, so if it changes they need to be recalculated |
388 | | */ |
389 | | stop: function( event, ui ) { |
390 | | // Not needed in one mode |
391 | | if ( this.singleRevision ) |
392 | | return; |
393 | | |
394 | | // calculate and generate a diff for comparing to the left handle |
395 | | // and the right handle, swap out when dragging |
396 | | if ( $( ui.handle ).hasClass( 'left-handle' ) ) { |
397 | | // Left handler |
398 | | if ( Diff.leftDiffStart !== isRtl ? ui.values[1] : ui.values[0] ) // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
399 | | Diff.reloadRight(); |
400 | | } else { |
401 | | // Right handler |
402 | | if ( Diff.rightDiffStart !== isRtl ? ui.values[0] : ui.values[1] ) // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
403 | | Diff.reloadLeft(); |
| 126 | getProximalDiffIds: function() { |
| 127 | var previous = 0, ids = []; |
| 128 | this.revisions.each( _.bind( function(revision) { |
| 129 | ids.push( previous + ':' + revision.id ); |
| 130 | previous = revision.id; |
| 131 | }, this ) ); |
| 132 | return ids; |
| 133 | }, |
| 134 | |
| 135 | getUnloadedProximalDiffIds: function() { |
| 136 | var comparisons = this.getProximalDiffIds(); |
| 137 | comparisons = _.object( comparisons, comparisons ); |
| 138 | _.each( comparisons, _.bind( function( id ) { |
| 139 | // Exists |
| 140 | if ( this.get( id ) ) |
| 141 | delete comparisons[ id ]; |
| 142 | }, this ) ); |
| 143 | return _.toArray( comparisons ); |
| 144 | }, |
| 145 | |
| 146 | loadAllBy: function( chunkSize ) { |
| 147 | chunkSize = chunkSize || 20; |
| 148 | var unloaded = this.getUnloadedProximalDiffIds(); |
| 149 | if ( unloaded.length ) { |
| 150 | return this.loadLastUnloaded( chunkSize ).always( _.bind( function() { |
| 151 | this.loadAllBy( chunkSize ); |
| 152 | }, this ) ); |
404 | 153 | } |
405 | 154 | }, |
406 | 155 | |
407 | | addTooltip: function( handle, message ) { |
408 | | handle.find( '.ui-slider-tooltip' ).html( message ); |
409 | | }, |
410 | | |
411 | | width: function() { |
412 | | return $( '#diff-slider' ).width(); |
413 | | }, |
| 156 | /**/ |
414 | 157 | |
415 | | setWidth: function( width ) { |
416 | | $( '#diff-slider' ).width( width ); |
417 | | }, |
| 158 | sync: function( method, model, options ) { |
| 159 | if ( 'read' === method ) { |
| 160 | options = options || {}; |
| 161 | options.context = this; |
| 162 | options.data = _.extend( options.data || {}, { |
| 163 | action: 'get-revision-diffs', |
| 164 | post_id: revisions.settings.postId |
| 165 | }); |
418 | 166 | |
419 | | refresh: function( options, slide ) { |
420 | | $( '#diff-slider' ).slider( 'option', options ); |
| 167 | var deferred = wp.xhr.send( options ); |
| 168 | var requests = this.requests; |
421 | 169 | |
422 | | // Triggers the slide event |
423 | | if ( slide ) |
424 | | $( '#diff-slider' ).trigger( 'slide' ); |
| 170 | // Record that we're requesting each diff. |
| 171 | if ( options.data.compare ) { |
| 172 | _.each( options.data.compare, function( id ) { |
| 173 | requests[ id ] = deferred; |
| 174 | }); |
| 175 | } |
425 | 176 | |
426 | | Diff.disabledButtonCheck( options.value ); |
427 | | }, |
| 177 | // When the request completes, clear the stored request. |
| 178 | deferred.always( function() { |
| 179 | if ( options.data.compare ) { |
| 180 | _.each( options.data.compare, function( id ) { |
| 181 | delete requests[ id ]; |
| 182 | }); |
| 183 | } |
| 184 | }); |
428 | 185 | |
429 | | option: function( key ) { |
430 | | return $( '#diff-slider' ).slider( 'option', key ); |
431 | | }, |
| 186 | return deferred; |
432 | 187 | |
433 | | render: function() { |
434 | | var self = this; |
435 | | // this.$el doesn't work, why? |
436 | | $( '#diff-slider' ).slider( { |
437 | | slide: $.proxy( self.slide, self ), |
438 | | start: $.proxy( self.start, self ), |
439 | | stop: $.proxy( self.stop, self ) |
440 | | } ); |
441 | | |
442 | | // Set options |
443 | | this.refresh( this.options ); |
| 188 | // Otherwise, fall back to `Backbone.sync()`. |
| 189 | } else { |
| 190 | return Backbone.Model.prototype.sync.apply( this, arguments ); |
| 191 | } |
444 | 192 | } |
445 | 193 | }); |
446 | 194 | |
447 | | /** |
448 | | * wp.revisions.view.Tickmarks |
449 | | * |
450 | | * The slider tickmarks. |
451 | | */ |
452 | | revisions.view.Tickmarks = Backbone.View.extend({ |
453 | | el: $('#diff-slider-ticks'), |
454 | | template: wp.template('revision-ticks'), |
455 | | model: Revision, |
456 | | |
457 | | resetTicks: function() { |
458 | | var sliderMax, sliderWidth, adjustMax, tickWidth, tickCount = 0, aTickWidth, tickMargin, self = this, firstTick, lastTick; |
459 | | sliderMax = Diff.slider.option( 'max' ); |
460 | | sliderWidth = Diff.slider.width(); |
461 | | adjustMax = Diff.singleRevision ? 0 : 1; |
462 | | tickWidth = Math.floor( sliderWidth / ( sliderMax - adjustMax ) ); |
463 | | tickWidth = ( tickWidth > 50 ) ? 50 : tickWidth; // set minimum and maximum widths for tick marks |
464 | | tickWidth = ( tickWidth < 6 ) ? 6 : tickWidth; |
465 | | sliderWidth = tickWidth * ( sliderMax - adjustMax ); // calculate the slider width |
466 | | aTickWidth = $( '.revision-tick' ).width(); |
467 | | |
468 | | if ( tickWidth !== aTickWidth ) { // is the width already set correctly? |
469 | | $( '.revision-tick' ).each( function() { |
470 | | tickMargin = Math.floor( ( tickWidth - $( this ).width() ) / 2 ) + 1; |
471 | | $( this ).css( 'border-left', tickMargin + 'px solid #f7f7f7'); // space the ticks out using margins |
472 | | $( this ).css( 'border-right', ( tickWidth - tickMargin - $( this ).width() ) + 'px solid #f7f7f7'); // space the ticks out using margins |
473 | | }); |
474 | | firstTick = $( '.revision-tick' ).first(); //cache selectors for optimization |
475 | | lastTick = $( '.revision-tick' ).last(); |
476 | 195 | |
477 | | sliderWidth = sliderWidth + Math.ceil( ( tickWidth - ( lastTick.outerWidth() - lastTick.innerWidth() ) ) / 2 ); // room for the last tick |
478 | | sliderWidth = sliderWidth + Math.ceil( ( tickWidth - ( firstTick.outerWidth() - firstTick.innerWidth() ) ) / 2 ); // room for the first tick |
479 | | firstTick.css( 'border-left', 'none' ); // first tick gets no left border |
480 | | lastTick.css( 'border-right', 'none' ); // last tick gets no right border |
481 | | } |
| 196 | revisions.model.FrameState = Backbone.Model.extend({ |
| 197 | initialize: function( attributes, options ) { |
| 198 | this.revisions = options.revisions; |
| 199 | this.diffs = new revisions.model.Diffs( [], {revisions: this.revisions} ); |
482 | 200 | |
483 | | /** |
484 | | * reset the slider width |
485 | | */ |
486 | | Diff.slider.setWidth( sliderWidth ); |
487 | | $( '.diff-slider-ticks-wrapper' ).width( sliderWidth ); |
488 | | $( '#diff-slider-ticks' ).width( sliderWidth ); |
489 | | |
490 | | /** |
491 | | * go through all ticks, add hover and click interactions |
492 | | */ |
493 | | $( '.revision-tick' ).each( function() { |
494 | | Diff.slider.addTooltip ( $( this ), Diff.revisions.at( tickCount++ ).get( 'titleTooltip' ) ); |
495 | | $( this ).hover( |
496 | | function() { |
497 | | $( this ).find( '.ui-slider-tooltip' ).show().append('<div class="arrow"></div>'); |
498 | | }, |
499 | | function() { |
500 | | $( this ).find( '.ui-slider-tooltip' ).hide().find( '.arrow' ).remove(); |
501 | | } |
502 | | ); |
503 | | |
504 | | /** |
505 | | * move the slider handle when the tick marks are clicked |
506 | | */ |
507 | | $( this ).on( 'click', |
508 | | { tickCount: tickCount }, // pass the tick through so we know where to move the handle |
509 | | function( event ) { |
510 | | if ( Diff.slider.singleRevision ) { // single handle mode |
511 | | Diff.rightDiff = event.data.tickCount; // reposition the right handle |
512 | | Diff.slider.refresh({ |
513 | | value: Diff.rightDiff - 1 |
514 | | } ); |
515 | | } else { //compare two mode |
516 | | if ( isRtl ) { |
517 | | if ( event.data.tickCount < Diff.leftDiff ) { // click was on the 'left' side |
518 | | Diff.rightDiff = event.data.tickCount; // set the 'right' handle location |
519 | | Diff.reloadLeft(); // reload the left handle comparison models |
520 | | } else { // middle or 'right' clicks |
521 | | Diff.leftDiff = event.data.tickCount; // set the 'left' handle location |
522 | | Diff.reloadRight(); // reload right handle models |
523 | | } |
524 | | } else { |
525 | | if ( event.data.tickCount < Diff.leftDiff ) { // click was on the 'left' side |
526 | | Diff.leftDiff = event.data.tickCount; // set the left handle location |
527 | | Diff.reloadRight(); // reload the right handle comparison models |
528 | | } else { // middle or 'right' clicks |
529 | | Diff.rightDiff = event.data.tickCount; // set the right handle location |
530 | | Diff.reloadLeft(); // reload left handle models |
531 | | } |
532 | | } |
533 | | Diff.slider.refresh( { // set the slider handle positions |
534 | | values: [ isRtl ? Diff.rightDiff : Diff.leftDiff, isRtl ? Diff.leftDiff : Diff.rightDiff ] |
535 | | } ); |
536 | | } |
537 | | Diff.revisionView.render(); // render the main view |
538 | | } ); |
539 | | } ); |
| 201 | this.listenTo( this, 'change:from change:to', this.updateDiffId ); |
540 | 202 | }, |
541 | 203 | |
542 | | // render the tick mark view |
543 | | render: function() { |
544 | | var self = this, addHtml; |
545 | | |
546 | | if ( null !== self.model ) { |
547 | | addHtml = ""; |
548 | | _.each ( self.model.models, function( theModel ) { |
549 | | addHtml = addHtml + self.template ( theModel.toJSON() ); |
550 | | }); |
551 | | self.$el.html( addHtml ); |
552 | | |
553 | | } |
554 | | self.resetTicks(); |
555 | | return self; |
| 204 | updateDiffId: function() { |
| 205 | var from = this.get('from'); |
| 206 | var to = this.get('to'); |
| 207 | this.set( 'diffId', (from ? from.id : '0') + ':' + to.id ); |
556 | 208 | } |
557 | | } ); |
| 209 | }); |
| 210 | |
558 | 211 | |
559 | 212 | /** |
560 | | * wp.revisions.view.Interact |
561 | | * |
562 | | * Next/Prev buttons and the slider |
| 213 | * ======================================================================== |
| 214 | * VIEWS |
| 215 | * ======================================================================== |
563 | 216 | */ |
564 | | revisions.view.Interact = Backbone.View.extend({ |
565 | | el: $( '#revision-interact' ), |
566 | | template: wp.template( 'revision-interact' ), |
567 | | |
568 | | // next and previous buttons, only available in compare one mode |
569 | | events: { |
570 | | 'click #next': ! isRtl ? 'nextRevision' : 'previousRevision', |
571 | | 'click #previous': ! isRtl ? 'previousRevision' : 'nextRevision' |
572 | | }, |
573 | 217 | |
574 | | render: function() { |
575 | | var modelcount; |
576 | | this.$el.html( this.template ); |
| 218 | // The frame view. This contains the entire page. |
| 219 | revisions.view.Frame = wp.Backbone.View.extend({ |
| 220 | tagName: 'div', |
| 221 | className: 'revisions', |
| 222 | template: wp.template('revisions-frame'), |
577 | 223 | |
578 | | modelcount = Diff.revisions.length; |
| 224 | initialize: function() { |
| 225 | this.model = new revisions.model.FrameState({}, { |
| 226 | revisions: this.collection |
| 227 | }); |
579 | 228 | |
580 | | Diff.slider.singleRevision = Diff.singleRevision; |
581 | | Diff.slider.render(); |
| 229 | this.listenTo( this.model, 'change:diffId', this.updateDiff ); |
582 | 230 | |
583 | | if ( Diff.singleRevision ) { |
584 | | Diff.slider.refresh({ |
585 | | value: Diff.rightDiff - 1, // rightDiff value is off model index by 1 |
586 | | min: 0, |
587 | | max: modelcount - 1 |
588 | | }); |
| 231 | this.views.set( '.revisions-control-frame', new revisions.view.Controls({ |
| 232 | model: this.model |
| 233 | }) ); |
589 | 234 | |
590 | | $( '#revision-diff-container' ).removeClass( 'comparing-two-revisions' ); |
| 235 | if ( this.model.revisions.length ) { |
| 236 | var last = this.model.revisions.last(2); |
| 237 | var attributes = { to: last.pop() }; |
591 | 238 | |
592 | | } else { |
593 | | Diff.slider.refresh({ |
594 | | // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
595 | | values: [ isRtl ? Diff.rightDiff : Diff.leftDiff, isRtl ? Diff.leftDiff : Diff.rightDiff ], |
596 | | min: 1, |
597 | | max: modelcount + 1, |
598 | | range: true |
599 | | }); |
| 239 | if ( last.length ) |
| 240 | attributes.from = last.pop(); |
600 | 241 | |
601 | | $( '#revision-diff-container' ).addClass( 'comparing-two-revisions' ); |
602 | | // in RTL mode the 'left handle' is the second in the slider, 'right' is first |
603 | | $( '#diff-slider a.ui-slider-handle' ).first().addClass( isRtl ? 'right-handle' : 'left-handle' ); |
604 | | $( '#diff-slider a.ui-slider-handle' ).last().addClass( isRtl ? 'left-handle' : 'right-handle' ); |
| 242 | this.model.set( attributes ); |
605 | 243 | |
| 244 | // Load the rest: first 10, then the rest by 50 |
| 245 | this.model.diffs.loadLastUnloaded( 10 ).always( _.bind( function() { |
| 246 | console.log( 'Loading all by 50' ); |
| 247 | this.model.diffs.loadAllBy( 50 ); |
| 248 | }, this ) ); |
606 | 249 | } |
607 | | |
608 | | return this; |
609 | 250 | }, |
610 | 251 | |
611 | | // go to the next revision |
612 | | nextRevision: function() { |
613 | | if ( Diff.rightDiff < this.model.length ) // unless at right boundry |
614 | | Diff.rightDiff = Diff.rightDiff + 1 ; |
| 252 | render: function() { |
| 253 | wp.Backbone.View.prototype.render.apply( this, arguments ); |
615 | 254 | |
616 | | Diff.revisionView.render(); |
| 255 | $('#wpbody-content .wrap').append( this.el ); |
| 256 | this.views.ready(); |
617 | 257 | |
618 | | Diff.slider.refresh({ |
619 | | value: Diff.rightDiff - 1 |
620 | | }, true ); |
| 258 | return this; |
621 | 259 | }, |
622 | 260 | |
623 | | // go to the previous revision |
624 | | previousRevision: function() { |
625 | | if ( Diff.rightDiff > 1 ) // unless at left boundry |
626 | | Diff.rightDiff = Diff.rightDiff - 1 ; |
627 | | |
628 | | Diff.revisionView.render(); |
| 261 | updateDiff: function() { |
| 262 | this.model.diffs.ensure( this.model.get('diffId'), this ).done( function( diff ) { |
| 263 | if ( this.model.get('diffId') !== diff.id ) |
| 264 | return; |
| 265 | this.views.set( '.revisions-diff-frame', new revisions.view.Diff({ |
| 266 | model: diff |
| 267 | })); |
| 268 | }); |
| 269 | } |
| 270 | }); |
629 | 271 | |
630 | | Diff.slider.refresh({ |
631 | | value: Diff.rightDiff - 1 |
632 | | }, true ); |
| 272 | // The control view. |
| 273 | // This contains the revision slider, previous/next buttons, and the compare checkbox. |
| 274 | revisions.view.Controls = wp.Backbone.View.extend({ |
| 275 | tagName: 'div', |
| 276 | className: 'revisions-controls', |
| 277 | template: wp.template('revisions-controls'), |
| 278 | |
| 279 | initialize: function() { |
| 280 | this.views.set( new revisions.view.Slider({ |
| 281 | model: this.model |
| 282 | }) ); |
633 | 283 | } |
634 | 284 | }); |
635 | 285 | |
636 | | /** |
637 | | * wp.revisions.view.Diff |
638 | | * |
639 | | * Diff, compare two checkbox and restore button |
640 | | */ |
641 | | revisions.view.Diff = Backbone.View.extend({ |
642 | | el: $( '#revisions-diff' ), |
643 | | template: wp.template( 'revisions-diff' ), |
644 | | draggingLeft: false, |
645 | | |
646 | | // the compare two button is in this view, add the interaction here |
647 | | events: { |
648 | | 'click #compare-two-revisions': 'compareTwo', |
649 | | 'click #restore-revision': 'restore' |
| 286 | // The slider view. |
| 287 | // Encapsulates all of the configuration for the jQuery UI slider into a view. |
| 288 | revisions.view.Slider = wp.Backbone.View.extend({ |
| 289 | tagName: 'div', |
| 290 | className: 'wp-slider', |
| 291 | |
| 292 | initialize: function() { |
| 293 | _.bindAll( this, 'start', 'slide', 'stop' ); |
| 294 | |
| 295 | // Create the slider model from the provided collection data. |
| 296 | // TODO: This should actually pull from the model's `to` key. |
| 297 | var latestRevisionIndex = this.model.revisions.length - 1; |
| 298 | |
| 299 | this.settings = new revisions.model.Slider({ |
| 300 | max: latestRevisionIndex, |
| 301 | value: latestRevisionIndex, |
| 302 | start: this.start, |
| 303 | slide: this.slide, |
| 304 | stop: this.stop |
| 305 | }); |
650 | 306 | }, |
651 | 307 | |
652 | | // render the revisions |
653 | | render: function() { |
654 | | var addHtml = '', thediff; |
655 | | |
656 | | // compare two revisions mode? |
657 | | if ( ! Diff.singleRevision ) { |
658 | | if ( this.draggingLeft ) { |
659 | | thediff = Diff.leftDiff - 1; //leftDiff value is off model index by 1 |
660 | | if ( this.model.at( thediff ) ) { |
661 | | addHtml = this.template( this.model.at( thediff ).toJSON() ); |
662 | | } |
663 | | } else { // dragging right handle |
664 | | thediff = Diff.rightDiff - 1; // rightDiff value is off model index by 1 |
665 | | if ( this.model.at( thediff ) ) { |
666 | | addHtml = this.template( this.model.at( thediff ).toJSON() ); |
667 | | } |
668 | | } |
669 | | } else { // end compare two revisions mode, eg only one slider handle |
670 | | if ( this.model.at( Diff.rightDiff - 1 ) ) { // rightDiff value is off model index by 1 |
671 | | addHtml = this.template( this.model.at( Diff.rightDiff - 1 ).toJSON() ); |
672 | | } |
673 | | } |
674 | | this.$el.html( addHtml ); |
675 | | |
676 | | if ( this.model.length < 2 ) { |
677 | | $( '#diff-slider' ).hide(); // don't allow compare two if fewer than three revisions |
678 | | $( '.diff-slider-ticks-wrapper' ).hide(); |
679 | | } |
680 | | |
681 | | this.toggleCompareTwoCheckbox(); |
682 | | |
683 | | // hide the restore button when on the last sport/current post data |
684 | | $( '#restore-revision' ).toggle( ! Diff.revisions.at( Diff.rightDiff - 1 ).get( 'isCurrent' ) ); |
685 | | |
686 | | return this; |
| 308 | ready: function() { |
| 309 | this.$el.slider( this.settings.toJSON() ); |
| 310 | this.settings.on( 'change', function( model, options ) { |
| 311 | // Apply changes to slider settings here. |
| 312 | }, this ); |
687 | 313 | }, |
688 | 314 | |
689 | | toggleCompareTwoCheckbox: function() { |
690 | | // don't allow compare two if fewer than three revisions |
691 | | if ( this.model.length < 3 ) |
692 | | $( '#toggle-revision-compare-mode' ).hide(); |
| 315 | start: function() { |
693 | 316 | |
694 | | $( '#compare-two-revisions' ).prop( 'checked', ! Diff.singleRevision ); |
695 | 317 | }, |
696 | 318 | |
697 | | // turn on/off the compare two mode |
698 | | compareTwo: function() { |
699 | | if ( $( '#compare-two-revisions' ).is( ':checked' ) ) { // compare 2 mode |
700 | | Diff.singleRevision = false ; |
701 | | |
702 | | // in RTL mode handles are swapped, so boundary checks are different; |
703 | | if ( isRtl ){ |
704 | | Diff.leftDiff = Diff.revisions.length; // put the left handle at the rightmost position, representing current revision |
705 | | |
706 | | if ( Diff.revisions.length === Diff.rightDiff ) // make sure 'left' handle not in rightmost slot |
707 | | Diff.rightDiff = Diff.rightDiff - 1; |
708 | | } else { |
709 | | if ( 1 === Diff.rightDiff ) // make sure right handle not in leftmost slot |
710 | | Diff.rightDiff = 2; |
711 | | } |
712 | | |
713 | | Diff.revisionView.draggingLeft = false; |
| 319 | slide: function( event, ui ) { |
| 320 | var attributes = { |
| 321 | to: this.model.revisions.at( ui.value ) |
| 322 | }; |
714 | 323 | |
715 | | revisions.model.settings.revision_id = ''; // reset passed revision id so switching back to one handle mode doesn't re-select revision |
716 | | Diff.reloadLeftRight(); // load diffs for left and right handles |
717 | | Diff.revisionView.model = Diff.rightHandleRevisions; |
| 324 | // If we're at the first revision, unset 'from'. |
| 325 | if ( ui.value ) |
| 326 | attributes.from = this.model.revisions.at( ui.value - 1 ); |
| 327 | else |
| 328 | this.model.unset('from', { silent: true }); |
718 | 329 | |
719 | | } else { // compare one mode |
720 | | Diff.singleRevision = true; |
721 | | Diff.revisionView.draggingLeft = false; |
722 | | Diff.reloadModelSingle(); |
723 | | } |
724 | | Diff.revisionsInteractions.render(); |
725 | | Diff.tickmarkView.render(); |
| 330 | this.model.set( attributes ); |
726 | 331 | }, |
727 | 332 | |
728 | | restore: function() { |
729 | | document.location = $( '#restore-revision' ).data( 'restoreLink' ); |
| 333 | stop: function() { |
730 | 334 | } |
731 | 335 | }); |
732 | 336 | |
| 337 | // The diff view. |
| 338 | // This is the view for the current active diff. |
| 339 | revisions.view.Diff = wp.Backbone.View.extend({ |
| 340 | tagName: 'div', |
| 341 | className: 'revisions-diff', |
| 342 | template: wp.template('revisions-diff'), |
733 | 343 | |
734 | | /** |
735 | | * ======================================================================== |
736 | | * MODELS |
737 | | * ======================================================================== |
738 | | */ |
739 | | |
740 | | /** |
741 | | * wp.revisions.Revision |
742 | | */ |
743 | | Revision = revisions.model.Revision = Backbone.Model.extend({ |
744 | | idAttribute: 'ID', |
745 | | |
746 | | defaults: { |
747 | | ID: 0, |
748 | | titleTo: '', |
749 | | titleTooltip: '', |
750 | | titleFrom: '', |
751 | | diff: '<div class="diff-loading"><div class="spinner"></div></div>', |
752 | | restoreLink: '', |
753 | | completed: false, |
754 | | linesAdded: 0, |
755 | | linesDeleted: 0, |
756 | | scopeOfChanges: 'none', |
757 | | previousID: 0, |
758 | | isCurrent: false |
759 | | }, |
760 | | |
761 | | url: function() { |
762 | | if ( Diff.singleRevision ) { |
763 | | return ajaxurl + |
764 | | '?action=revisions-data' + |
765 | | '&show_autosaves=true' + |
766 | | '&show_split_view=true' + |
767 | | '&nonce=' + revisions.model.settings.nonce + |
768 | | '&single_revision_id=' + this.id + |
769 | | '&compare_to=' + this.get( 'previousID' ) + |
770 | | '&post_id=' + revisions.model.settings.post_id; |
771 | | } else { |
772 | | return this.collection.url() + '&single_revision_id=' + this.id; |
773 | | } |
774 | | |
| 344 | // Generate the options to be passed to the template. |
| 345 | prepare: function() { |
| 346 | return _.extend({ fields: this.model.fields.toJSON() }, this.options ); |
775 | 347 | } |
776 | 348 | }); |
777 | 349 | |
778 | | /** |
779 | | * wp.revisions.Revisions |
780 | | */ |
781 | | Revisions = revisions.Revisions = Backbone.Collection.extend({ |
782 | | model: Revision, |
783 | | |
784 | | initialize: function( models, options ) { |
785 | | this.options = _.defaults( options || {}, { |
786 | | 'compareTo': revisions.model.settings.post_id, |
787 | | 'post_id': revisions.model.settings.post_id, |
788 | | 'showAutosaves': true, |
789 | | 'showSplitView': true, |
790 | | 'rightHandleAt': 0, |
791 | | 'leftHandleAt': 0, |
792 | | 'nonce': revisions.model.settings.nonce |
793 | | }); |
794 | | }, |
795 | | |
796 | | url: function() { |
797 | | return ajaxurl + |
798 | | '?action=revisions-data' + |
799 | | '&compare_to=' + this.options.compareTo + // revision are we comparing to |
800 | | '&post_id=' + this.options.post_id + // the post id |
801 | | '&show_autosaves=' + this.options.showAutosaves + // show or hide autosaves |
802 | | '&show_split_view=' + this.options.showSplitView + // show in split view or single column view |
803 | | '&right_handle_at=' + this.options.rightHandleAt + // mark point for comparison list |
804 | | '&left_handle_at=' + this.options.leftHandleAt + // mark point for comparison list |
805 | | '&nonce=' + this.options.nonce; |
806 | | }, |
807 | | |
808 | | reload: function( options ) { |
809 | | this.options = _.defaults( options.options || {}, this.options ); |
810 | | |
811 | | this.fetch({ |
812 | | success: options.success || null, |
813 | | error: options.error || null |
814 | | }); |
815 | | } |
816 | | |
817 | | } ); |
818 | | |
819 | | $( wp.revisions ); |
| 350 | // Initialize the revisions UI. |
| 351 | revisions.init = function() { |
| 352 | revisions.view.frame = new revisions.view.Frame({ |
| 353 | collection: new revisions.model.Revisions( revisions.settings.revisionData ) |
| 354 | }).render(); |
| 355 | }; |
820 | 356 | |
| 357 | $( revisions.init ); |
821 | 358 | }(jQuery)); |