Ticket #23901: 23901.4.diff
File 23901.4.diff, 58.5 KB (added by , 12 years ago) |
---|
-
wp-includes/revision.php
675 675 $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' ); 676 676 $args = wp_parse_args( $args, $defaults ); 677 677 678 if ( ! class_exists( 'WP_Text_Diff_Renderer_Table' ) )678 if ( ! class_exists( 'WP_Text_Diff_Renderer_Table' ) ) 679 679 require( ABSPATH . WPINC . '/wp-diff.php' ); 680 680 681 681 $left_string = normalize_whitespace( $left_string ); … … 685 685 $right_lines = explode( "\n", $right_string) ; 686 686 687 687 $text_diff = new Text_Diff($left_lines, $right_lines ); 688 $lines added = $text_diff->countAddedLines();689 $lines deleted = $text_diff->countDeletedLines();688 $lines_added = $text_diff->countAddedLines(); 689 $lines_deleted = $text_diff->countDeletedLines(); 690 690 691 691 $renderer = new WP_Text_Diff_Renderer_Table(); 692 692 $diff = $renderer->render( $text_diff ); … … 718 718 $r .= "<tbody>\n$diff\n</tbody>\n"; 719 719 $r .= "</table>"; 720 720 721 return array( 'html' => $r, 'lines added' => $linesadded, 'linesdeleted' => $linesdeleted );721 return array( 'html' => $r, 'lines_added' => $lines_added, 'lines_deleted' => $lines_deleted ); 722 722 } -
wp-admin/includes/ajax-actions.php
2092 2092 function wp_ajax_revisions_data() { 2093 2093 check_ajax_referer( 'revisions-ajax-nonce', 'nonce' ); 2094 2094 2095 $compare_to = isset( $_GET['compare_to'] ) ? absint( $_GET['compare_to'] ) : 0; 2096 $show_autosaves = isset( $_GET['show_autosaves'] ) ? $_GET['show_autosaves'] : ''; 2097 $show_split_view = isset( $_GET['show_split_view'] ) ? $_GET['show_split_view'] : ''; 2098 $post_id = isset( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : ''; 2099 $right_handle_at = isset( $_GET['right_handle_at'] ) ? $_GET['right_handle_at'] : 0; 2100 $left_handle_at = isset( $_GET['left_handle_at'] ) ? $_GET['left_handle_at'] : 0; 2101 $single_revision_id = isset( $_GET['single_revision_id'] ) ? $_GET['single_revision_id'] : 0; 2095 $compare_to = ! empty( $_GET['compare_to'] ) ? absint( $_GET['compare_to'] ) : 0; 2096 $show_autosaves = ! empty( $_GET['show_autosaves'] ); 2097 $show_split_view = ! empty( $_GET['show_split_view'] ); 2098 $post_id = ! empty( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0; 2099 $right_handle_at = ! empty( $_GET['right_handle_at'] ) ? (int) $_GET['right_handle_at'] : 0; 2100 $left_handle_at = ! empty( $_GET['left_handle_at'] ) ? (int) $_GET['left_handle_at'] : 0; 2101 $single_revision_id = ! empty( $_GET['single_revision_id'] ) ? absint( $_GET['single_revision_id'] ) : 0; 2102 $compare_two_mode = (bool) $post_id; 2102 2103 2103 $compare_two_mode = ( '' == $post_id ) ? false : true;2104 2104 // 2105 2105 //TODO: currently code returns all possible comparisons for the indicated 'compare_to' revision 2106 2106 //however, the front end prevents users from pulling the right handle past the left or the left pass the right, 2107 2107 //so only the possible diffs need be generated 2108 2108 // 2109 $all therevisions = array();2110 if ( '' ==$post_id )2109 $all_the_revisions = array(); 2110 if ( ! $post_id ) 2111 2111 $post_id = $compare_to; 2112 2112 2113 2113 if ( ! current_user_can( 'read_post', $post_id ) ) … … 2116 2116 if ( ! $revisions = wp_get_post_revisions( $post_id ) ) 2117 2117 return; 2118 2118 2119 /* translators: revision date format, see http://php.net/date */2120 $datef = _x( 'j F, Y @ G:i:s', 'revision date format');2121 2122 2119 $left_revision = get_post( $compare_to ); 2123 2120 2124 2121 //single model fetch mode 2125 2122 //return the diff of a single revision comparison 2126 if ( 0 !=$single_revision_id ) {2123 if ( $single_revision_id ) { 2127 2124 $right_revision = get_post( $single_revision_id ); 2128 2125 2129 if ( 0 ==$compare_to )2126 if ( ! $compare_to ) 2130 2127 $left_revision = get_post( $post_id ); 2131 2128 2132 // make sure the right revision is the most recent2133 if ( $compare_two_mode && $right_revision->ID < $left_revision->ID ) {2134 $temp = $left_revision;2135 $left_revision = $right_revision;2136 $right_revision = $temp;2137 }2129 // make sure the right revision is the most recent 2130 if ( $compare_two_mode && $right_revision->ID < $left_revision->ID ) { 2131 $temp = $left_revision; 2132 $left_revision = $right_revision; 2133 $right_revision = $temp; 2134 } 2138 2135 2139 $linesadded=0; 2140 $linesdeleted=0; 2141 2142 // 2136 $lines_added = $lines_deleted = 0; 2137 $content = ''; 2143 2138 //compare from left to right, passed from application 2144 //2145 $content='';2146 2139 foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { 2147 2140 $left_content = apply_filters( "_wp_post_revision_field_$field", $left_revision->$field, $field, $left_revision, 'left' ); 2148 2141 $right_content = apply_filters( "_wp_post_revision_field_$field", $right_revision->$field, $field, $right_revision, 'right' ); … … 2151 2144 2152 2145 $args = array(); 2153 2146 2154 if ( ! empty( $show_split_view ))2147 if ( $show_split_view ) 2155 2148 $args = array( 'show_split_view' => true ); 2156 2149 2157 2150 // compare_to == 0 means first revision, so compare to a blank field to show whats changed 2158 $diff = wp_text_diff_with_count( ( 0 == $compare_to ) ? '' : $left_content, $right_content, $args );2151 $diff = wp_text_diff_with_count( ( 0 == $compare_to ) ? '' : $left_content, $right_content, $args ); 2159 2152 2160 2153 if ( isset( $diff[ 'html' ] ) ) 2161 2154 $content .= $diff[ 'html' ]; 2162 2155 2163 if ( isset( $diff[ 'lines added' ] ) )2164 $lines added = $linesadded + $diff[ 'linesadded' ];2156 if ( isset( $diff[ 'lines_added' ] ) ) 2157 $lines_added = $lines_added + $diff[ 'lines_added' ]; 2165 2158 2166 if ( isset( $diff[ 'linesdeleted' ] ) ) 2167 $linesdeleted = $linesdeleted + $diff[ 'linesdeleted' ]; 2168 2169 2159 if ( isset( $diff[ 'lines_deleted' ] ) ) 2160 $lines_deleted = $lines_deleted + $diff[ 'lines_deleted' ]; 2170 2161 } 2171 2162 $content = '' == $content ? __( 'No difference' ) : $content; 2172 2163 2173 $all therevisions = array (2174 ' revisiondiff'=> $content,2175 'lines_deleted' => $lines deleted,2176 'lines_added' => $linesadded2164 $all_the_revisions = array ( 2165 'diff' => $content, 2166 'lines_deleted' => $lines_deleted, 2167 'lines_added' => $lines_added 2177 2168 ); 2178 echo json_encode( $alltherevisions ); 2169 2170 echo json_encode( $all_the_revisions ); 2179 2171 exit(); 2180 2172 } //end single model fetch 2181 2173 … … 2186 2178 2187 2179 $previous_revision_id = 0; 2188 2180 2181 /* translators: revision date format, see http://php.net/date */ 2182 $datef = _x( 'j F, Y @ G:i:s', 'revision date format'); 2183 2189 2184 foreach ( $revisions as $revision ) : 2190 //error_log( ( $show_autosaves )); 2191 if ( empty( $show_autosaves ) && wp_is_post_autosave( $revision ) ) 2192 continue; 2185 if ( $show_autosaves && wp_is_post_autosave( $revision ) ) 2186 continue; 2193 2187 2194 2188 $revision_from_date_author = ''; 2195 2189 $count++; 2196 2190 // return blank data for diffs to the left of the left handle (for right handel model) 2197 2191 // or to the right of the right handle (for left handel model) 2198 if ( ( 0 != $left_handle_at && $count < =$left_handle_at ) ||2199 ( 0 != $right_handle_at && $count > $right_handle_at )) {2200 $all therevisions[] = array (2192 if ( ( 0 != $left_handle_at && $count < $left_handle_at ) || 2193 ( 0 != $right_handle_at && $count > ( $right_handle_at -2 ) ) ) { 2194 $all_the_revisions[] = array ( 2201 2195 'ID' => $revision->ID, 2202 2196 ); 2203 2197 continue; … … 2230 2224 $date 2231 2225 ); 2232 2226 2233 $autosavef = _ _( '%1$s [Autosave]' );2234 $currentf = _ _( '%1$s [Current Revision]' );2227 $autosavef = _x( '%1$s [Autosave]', 'post revision title extra' ); 2228 $currentf = _x( '%1$s [Current Revision]', 'post revision title extra' ); 2235 2229 2236 if ( ! $post = get_post( $post_id ))2237 exit(); 2230 if ( ! $post = get_post( $post_id ) ) 2231 exit(); // Should that be `continue;` instead? 2238 2232 2239 2233 if ( $left_revision->post_modified === $post->post_modified ) 2240 2234 $revision_from_date_author = sprintf( $currentf, $revision_from_date_author ); … … 2246 2240 elseif ( wp_is_post_autosave( $revision ) ) 2247 2241 $revision_date_author = sprintf( $autosavef, $revision_date_author ); 2248 2242 2249 $date_short_format = __( 'j M @ G:i' ); 2243 /* translators: revision date short format, see http://php.net/date */ 2244 $date_short_format = _x( 'j M @ G:i', 'revision date short format'); 2250 2245 $date_short = date_i18n( $date_short_format, strtotime( $revision->post_modified ) ); 2251 2246 2252 2247 $revision_date_author_short = sprintf( … … 2256 2251 $date_short 2257 2252 ); 2258 2253 2259 $restore action= wp_nonce_url(2254 $restore_link = wp_nonce_url( 2260 2255 add_query_arg( 2261 2256 array( 'revision' => $revision->ID, 2262 2257 'action' => 'restore' ), … … 2264 2259 ), 2265 2260 "restore-post_{$revision->ID}" 2266 2261 ); 2262 2267 2263 // if this is a left handled calculation swap data 2268 2264 if ( 0 != $right_handle_at ) { 2269 2265 $tmp = $revision_from_date_author; 2270 2266 $revision_from_date_author = $revision_date_author; 2271 2267 $revision_date_author = $tmp; 2272 2268 } 2269 2273 2270 if ( ( $compare_two_mode || -1 !== $previous_revision_id ) ) { 2274 $all therevisions[] = array (2275 'ID' => $revision->ID,2276 ' revision_date_author'=> $revision_date_author,2277 ' revision_from_date_author'=> $revision_from_date_author,2278 ' revision_date_author_short'=> $revision_date_author_short,2279 'restore action' => urldecode( $restoreaction),2280 'revision_toload' => true,2271 $all_the_revisions[] = array ( 2272 'ID' => $revision->ID, 2273 'titleTo' => $revision_date_author, 2274 'titleFrom' => $revision_from_date_author, 2275 'titleTooltip' => $revision_date_author_short, 2276 'restoreLink' => urldecode( $restore_link ), 2277 'revision_toload' => true, 2281 2278 'previous_revision_id' => $previous_revision_id 2282 2279 ); 2283 2280 } … … 2285 2282 2286 2283 endforeach; 2287 2284 2288 echo json_encode( $all therevisions );2285 echo json_encode( $all_the_revisions ); 2289 2286 exit(); 2290 2287 } -
wp-admin/js/revisions.js
1 1 window.wp = window.wp || {}; 2 2 3 3 (function($) { 4 wp.revisions = {4 var Revision, Revisions, Diff, l10n, revisions; 5 5 6 views: {}, 6 revisions = wp.revisions = function() { 7 Diff = revisions.Diff = new Diff(); 8 }; 7 9 8 Model: Backbone.Model.extend({ 9 idAttribute: 'ID', 10 urlRoot: ajaxurl + '?action=revisions-data' + 11 '&show_autosaves=true&show_split_view=true&nonce=' + wpRevisionsSettings.nonce, 12 defaults: { 13 ID: 0, 14 revision_date_author: '', 15 revision_date_author_short: '', 16 revisiondiff: '<div class="diff-loading"><div class="spinner"></div></div>', 17 restoreaction: '', 18 revision_from_date_author: '', 19 revision_toload: false, 20 lines_added: 0, 21 lines_deleted: 0, 22 scope_of_changes: 'none', 23 previous_revision_id: 0 24 }, 10 _.extend( revisions, { model: {}, view: {}, controller: {} } ); 25 11 26 url: function() { 27 if ( 1 === REVAPP._compareOneOrTwo ) { 28 return this.urlRoot + 29 '&single_revision_id=' + this.id + 30 '&compare_to=' + this.get( 'previous_revision_id' ) + 31 '&post_id=' + wpRevisionsSettings.post_id; 32 } else { 33 return this.urlRoot + 34 '&single_revision_id=' + this.id; 35 } 12 // Link any localized strings. 13 l10n = revisions.model.l10n = typeof wpRevisionsL10n === 'undefined' ? {} : wpRevisionsL10n; 36 14 37 } 15 // Link any settings. 16 revisions.model.settings = l10n.settings || {}; 17 delete l10n.settings; 38 18 39 }),40 19 41 app: _.extend({}, Backbone.Events), 20 /** 21 * ======================================================================== 22 * CONTROLLERS 23 * ======================================================================== 24 */ 42 25 43 App: Backbone.Router.extend({ 44 _revisions: null, 45 _leftHandleRevisions: null, 46 _rightHandleRevisions: null, 47 _revisionsInteractions: null, 48 _revisionsOptions: null, 49 _leftDiff: 1, 50 _rightDiff: 1, 51 _autosaves: true, 52 _showSplitView: true, 53 _compareOneOrTwo: 1, 54 _leftModelLoading: false, // keep track of model loads 55 _rightModelLoading: false, // disallow slider interaction, also repeat loads, while loading 56 _tickmarkView: null, // the slider tickmarks 26 /** 27 * wp.revisions.controller.Diff 28 * 29 * Controlls the diff 30 */ 31 Diff = revisions.controller.Diff = Backbone.Model.extend( { 32 rightDiff: 1, 33 leftDiff: 1, 34 revisions: null, 35 leftHandleRevisions: null, 36 rightHandleRevisions: null, 37 revisionsInteractions: null, 38 autosaves: true, 39 showSplitView: true, 40 singleRevision: true, 41 leftModelLoading: false, // keep track of model loads 42 rightModelLoading: false, // disallow slider interaction, also repeat loads, while loading 43 tickmarkView: null, // the slider tickmarks 44 slider: null, // the slider instance 57 45 58 routes: { 59 }, 46 constructor: function() { 47 this.slider = new revisions.view.Slider(); 48 if ( null === this.revisions ) { 49 this.revisions = new Revisions(); // set up collection 50 this.startRightModelLoading(); 60 51 61 reloadToLoadRevisions: function( model_collection, reverse_direction ) { 62 var self = this, 63 revisionsToLoad = model_collection.where( { revision_toload: true } ), 64 delay = 0; 65 // match slider to passed revision_id 66 _.each( revisionsToLoad, function( theModel ) { 67 if ( theModel.get( 'ID' ) == wpRevisionsSettings.revision_id ) { 68 self._rightDiff = self._revisions.indexOf( theModel ) + 1; 52 var self = this; 53 this.revisions.fetch({ // load revision data 54 success: function() { 55 self.stopRightModelLoading(); 56 self.completeApplicationSetup(); 69 57 } 70 71 58 }); 72 _.each( revisionsToLoad, function( theModel ) { 73 theModel.urlRoot = model_collection.url; 74 _.delay( function() { 75 theModel.fetch( { 76 update: true, 77 add: false, 78 remove: false, 79 success: function( model ) { 80 model.set( 'revision_toload', 'false' ); 59 } 60 }, 81 61 82 // stop spinner when all models are loaded 83 if ( 0 === model_collection.where( { revision_toload: true } ).length ) 84 self.stopModelLoadingSpinner(); 62 reloadToLoadRevisions: function( models, reverse_direction ) { 63 var self = this, 64 revisionsToLoad = models.where( { revision_toload: true } ), 65 delay = 0; 85 66 86 self._tickmarkView.render(); 67 // match slider to passed revision_id 68 _.each( revisionsToLoad, function( revision ) { 69 if ( revision.get( 'ID' ) == revisions.model.settings.revision_id ) 70 self.rightDiff = self.revisions.indexOf( revision ) + 1; 71 }); 87 72 88 var total_changes = model.get( 'lines_added' ) + model.get( 'lines_deleted'), 89 scope_of_changes = 'vsmall'; 73 _.each( revisionsToLoad, function( revision ) { 74 revision.urlRoot = models.url(); 75 _.delay( function() { 76 revision.fetch( { 77 update: true, 78 add: false, 79 remove: false, 80 success: function( model ) { 81 model.set( 'revision_toload', 'false' ); 90 82 91 // Note: hard coded scope of changes 92 // TODO change to dynamic based on range of values 93 if ( total_changes > 1 && total_changes <= 3 ) { 94 scope_of_changes = 'small'; 95 } else if(total_changes > 3 && total_changes <= 5 ) { 96 scope_of_changes = 'med'; 97 } else if(total_changes > 5 && total_changes <= 10 ) { 98 scope_of_changes = 'large'; 99 } else if(total_changes > 10 ) { 100 scope_of_changes = 'vlarge'; 101 } 102 model.set( 'scope_of_changes', scope_of_changes ); 103 if ( 0 !== self._rightDiff && 104 model.get( 'ID' ) === self._revisions.at( self._rightDiff - 1 ).get( 'ID' ) ) { 105 // reload if current model refreshed 106 self._revisionView.render(); 107 } 83 // stop spinner when all models are loaded 84 if ( 0 === models.where( { revision_toload: true } ).length ) 85 self.stopModelLoadingSpinner(); 108 86 109 } 110 } ); 111 }, delay ) ; 112 delay = delay + 150; // stagger model loads to avoid hammering server with requests 113 } 114 ); 115 }, 87 self.tickmarkView.render(); 116 88 117 startLeftModelLoading: function() { 118 this._leftModelLoading = true; 119 $('.revisiondiffcontainer').addClass('leftmodelloading'); 120 }, 89 var total_changes = model.get( 'lines_added' ) + model.get( 'lines_deleted'), 90 scope_of_changes = 'vsmall'; 121 91 122 stopLeftModelLoading: function() { 123 this._leftModelLoading = false; 124 }, 92 // Note: hard coded scope of changes 93 // TODO change to dynamic based on range of values 94 if ( total_changes > 1 && total_changes <= 3 ) { 95 scope_of_changes = 'small'; 96 } else if( total_changes > 3 && total_changes <= 5 ) { 97 scope_of_changes = 'med'; 98 } else if( total_changes > 5 && total_changes <= 10 ) { 99 scope_of_changes = 'large'; 100 } else if( total_changes > 10 ) { 101 scope_of_changes = 'vlarge'; 102 } 103 model.set( 'scope_of_changes', scope_of_changes ); 104 if ( 0 !== self.rightDiff && 105 model.get( 'ID' ) === self.revisions.at( self.rightDiff - 1 ).get( 'ID' ) ) { 106 // reload if current model refreshed 107 self.revisionView.render(); 108 } 125 109 126 startRightModelLoading: function() { 127 this._rightModelLoading = true; 128 $('.revisiondiffcontainer').addClass('rightmodelloading'); 129 }, 110 } 111 } ); 112 }, delay ) ; 113 delay = delay + 150; // stagger model loads to avoid hammering server with requests 114 } 115 ); 116 }, 130 117 131 stopRightModelLoading: function() { 132 this._rightModelLoading = false; 133 }, 118 startLeftModelLoading: function() { 119 this.leftModelLoading = true; 120 $('.revisiondiffcontainer').addClass('leftmodelloading'); 121 }, 134 122 135 stopModelLoadingSpinner: function() { 136 $('.revisiondiffcontainer').removeClass('rightmodelloading'); 137 $('.revisiondiffcontainer').removeClass('leftmodelloading'); 138 }, 123 stopLeftModelLoading: function() { 124 this.leftModelLoading = false; 125 }, 139 126 140 reloadModel: function() { 141 if ( 2 === this._compareOneOrTwo ) { 142 this.reloadLeftRight(); 143 } else { 144 this.reloadModelSingle(); 145 } 146 }, 127 startRightModelLoading: function() { 128 this.rightModelLoading = true; 129 $('.revisiondiffcontainer').addClass('rightmodelloading'); 130 }, 147 131 148 // load the models for the single handle mode 149 reloadModelSingle: function() { 150 var self = this; 151 self._revisions.url = ajaxurl + '?action=revisions-data&compare_to=' + wpRevisionsSettings.post_id + 152 '&show_autosaves=' + self._autosaves + 153 '&show_split_view=' + self._showSplitView + 154 '&nonce=' + wpRevisionsSettings.nonce; 155 self.startRightModelLoading(); 156 self._revisions.fetch({ // reload revision data 157 success: function() { 158 console.log('loaded'); 159 // self.stopRightModelLoading(); 160 // REVAPP._rightDiff -= 1; 161 var revisionCount = self._revisions.length; 162 self._revisionView.model = self._revisions; 163 self._revisionView.render(); 164 self.reloadToLoadRevisions( self._revisions ); 165 self._tickmarkView.model = self._revisions; 166 self._tickmarkView.render(); 167 $( '#slider' ).slider( 'option', 'max', revisionCount - 1 ); // TODO: test this, if autosave option changed 168 $( '#slider' ).slider( 'value', self._rightDiff - 1 ).trigger( 'slide' ); 132 stopRightModelLoading: function() { 133 this.rightModelLoading = false; 134 }, 169 135 170 }, 136 stopModelLoadingSpinner: function() { 137 $('.revisiondiffcontainer').removeClass('rightmodelloading'); 138 $('.revisiondiffcontainer').removeClass('leftmodelloading'); 139 }, 171 140 172 error: function() { 173 self.stopRightModelLoading(); 174 } 141 reloadModel: function() { 142 if ( this.singleRevision ) { 143 this.reloadModelSingle(); 144 } else { 145 this.reloadLeftRight(); 146 } 147 }, 175 148 176 }); 177 }, 149 // load the models for the single handle mode 150 reloadModelSingle: function() { 151 var self = this; 178 152 179 // load the models for the left handle180 reloadLeft: function(){181 var self = this;182 self.startLeftModelLoading();183 self._leftHandleRevisions = new wp.revisions.Collection();153 // TODO: Only updates the query args yet 154 self.revisions.reload({ 155 'showAutosaves': self.autosaves, 156 'showSplitView': self.showSplitView 157 }); 184 158 185 self._leftHandleRevisions.url = 186 ajaxurl + 187 '?action=revisions-data&compare_to=' + self._revisions.at( self._rightDiff - 1 ).get( 'ID' ) + 188 '&post_id=' + wpRevisionsSettings.post_id + 189 '&show_autosaves=' + REVAPP._autosaves + 190 '&show_split_view=' + REVAPP._showSplitView + 191 '&nonce=' + wpRevisionsSettings.nonce + 192 '&right_handle_at=' + ( self._rightDiff ); 159 self.startRightModelLoading(); 160 self.revisions.fetch({ // reload revision data 161 success: function() { 162 var revisionCount = self.revisions.length; 163 self.revisionView.model = self.revisions; 164 self.revisionView.render(); 165 self.reloadToLoadRevisions( self.revisions ); 166 self.tickmarkView.model = self.revisions; 167 self.tickmarkView.render(); 168 self.slider.refresh({ 169 'max': revisionCount - 1, 170 'value': self.rightDiff - 1 171 }, true); 172 }, 193 173 194 self._leftHandleRevisions.fetch({ 174 error: function() { 175 self.stopRightModelLoading(); 176 } 195 177 196 success: function(){ 197 self.stopLeftModelLoading(); 198 self.reloadToLoadRevisions( self._leftHandleRevisions ); 199 self._tickmarkView.model = self._leftHandleRevisions; 200 $( '#slider' ).slider( 'option', 'max', self._revisions.length ); 201 // ensure right handle not beyond length, in particular if viewing autosaves is switched from on to off 202 // the number of models in the collection might get shorter, this ensures right handle is not beyond last model 203 if ( self._rightDiff > self._revisions.length ) 204 self._rightDiff = self._revisions.length; 205 }, 178 }); 179 }, 206 180 207 error: function() { 208 self.stopLeftModelLoading(); 209 } 210 }); 211 }, 181 // load the models for the left handle 182 reloadLeft: function() { 183 var self = this; 184 self.startLeftModelLoading(); 185 self.leftHandleRevisions = new Revisions( {}, { 186 'compareTo': self.revisions.at( self.rightDiff - 1 ).get( 'ID' ), 187 'showAutosaves': self.autosaves, 188 'showSplitView': self.showSplitView, 189 'rightHandleAt': self.rightDiff 190 }); 212 191 213 // load the models for the right handle 214 reloadRight: function() { 215 var self = this; 216 self.startRightModelLoading(); 217 self._rightHandleRevisions = new wp.revisions.Collection(); 192 self.leftHandleRevisions.fetch({ 193 success: function(){ 194 self.stopLeftModelLoading(); 195 self.reloadToLoadRevisions( self.leftHandleRevisions ); 196 self.tickmarkView.model = self.leftHandleRevisions; 197 self.slider.refresh({ 198 'max': self.revisions.length 199 }); 200 // ensure right handle not beyond length, in particular if viewing autosaves is switched from on to off 201 // the number of models in the collection might get shorter, this ensures right handle is not beyond last model 202 if ( self.rightDiff > self.revisions.length ) 203 self.rightDiff = self.revisions.length; 204 }, 218 205 219 self._rightHandleRevisions.url = 220 ajaxurl + 221 '?action=revisions-data&compare_to=' + ( self._revisions.at( self._leftDiff ).get( 'ID' ) - 1 )+ 222 '&post_id=' + wpRevisionsSettings.post_id + 223 '&show_autosaves=' + REVAPP._autosaves + 224 '&show_split_view=' + REVAPP._showSplitView + 225 '&nonce=' + wpRevisionsSettings.nonce; 206 error: function() { 207 self.stopLeftModelLoading(); 208 } 209 }); 210 }, 226 211 227 self._rightHandleRevisions.fetch({ 212 // load the models for the right handle 213 reloadRight: function() { 214 var self = this; 215 self.startRightModelLoading(); 216 self.rightHandleRevisions = new Revisions( {}, { 217 'compareTo': self.revisions.at( self.leftDiff ).get( 'ID' ) - 1, 218 'showAutosaves': self.autosaves, 219 'showSplitView': self.showSplitView, 220 'leftHandleAt': self.leftDiff 221 }); 228 222 229 success: function(){ 230 self.stopRightModelLoading(); 231 self.reloadToLoadRevisions( self._rightHandleRevisions ); 232 self._tickmarkView.model = self._rightHandleRevisions; 233 $( '#slider' ).slider( 'option', 'max', self._revisions.length ); 234 $( '#slider' ).slider( 'values', [ REVAPP._leftDiff, REVAPP._rightDiff] ).trigger( 'slide' ); 223 self.rightHandleRevisions.fetch({ 224 success: function(){ 225 self.stopRightModelLoading(); 226 self.reloadToLoadRevisions( self.rightHandleRevisions ); 227 self.tickmarkView.model = self.rightHandleRevisions; 228 self.slider.refresh({ 229 'max': self.revisions.length, 230 'values': [ self.leftDiff, self.rightDiff] 231 }, true); 232 }, 235 233 236 // REVAPP._revisionView.render(); 234 error: function( response ) { 235 self.stopRightModelLoading(); 236 } 237 }); 237 238 238 239 }, 239 240 240 error: function( response ) { 241 self.stopRightModelLoading(); 242 } 243 }); 241 reloadLeftRight: function() { 242 this.startRightModelLoading(); 243 this.startLeftModelLoading(); 244 this.reloadLeft(); 245 this.reloadRight(); 246 }, 244 247 245 }, 248 completeApplicationSetup: function() { 249 this.revisionView = new revisions.view.Diff({ 250 model: this.revisions 251 }); 252 this.revisionView.render(); 246 253 247 reloadLeftRight: function() { 248 this.startRightModelLoading(); 249 this.startLeftModelLoading(); 250 this.reloadLeft(); 251 this.reloadRight(); 252 }, 254 this.reloadToLoadRevisions( this.revisions ); 253 255 254 /* 255 * initialize the revision application 256 */ 257 initialize: function( options ) { 258 var self = this; // store the application instance 259 if (this._revisions === null) { 260 self._revisions = new wp.revisions.Collection(); // set up collection 261 self.startRightModelLoading(); 262 self._revisions.fetch({ // load revision data 256 this.revisionsInteractions = new revisions.view.Interact({ 257 model: this.revisions 258 }); 259 this.revisionsInteractions.render(); 263 260 264 success: function() { 265 self.stopRightModelLoading(); 266 // self._rightHandleRevisions = self._revisions; 267 self.completeApplicationSetup(); 268 } 269 }); 270 } 271 return this; 272 }, 261 this.tickmarkView = new revisions.view.Tickmarks({ 262 model: this.revisions 263 }); 264 this.tickmarkView.render(); 265 this.tickmarkView.resetTicks(); 273 266 274 addTooltip: function( handle, message ) { 267 } 268 }); 275 269 276 handle.attr( 'title', '' ).tooltip({277 track: false,278 270 279 position: { 280 my: "left-30 top-66", 281 at: "top left", 282 using: function( position, feedback ) { 283 $( this ).css( position ); 284 $( "<div>" ) 285 .addClass( "arrow" ) 286 .addClass( feedback.vertical ) 287 .addClass( feedback.horizontal ) 288 .appendTo( $( this ) ); 289 } 290 }, 291 show: false, 292 hide: false, 293 content: function() { 294 return message; 295 } 271 /** 272 * ======================================================================== 273 * VIEWS 274 * ======================================================================== 275 */ 296 276 297 } ); 298 }, 299 /**/ 277 /** 278 * wp.revisions.view.Slider 279 * 280 * The slider 281 */ 282 revisions.view.Slider = Backbone.View.extend({ 283 el: $( '#slider' ), 284 singleRevision: true, 300 285 301 completeApplicationSetup: function() { 302 this._revisionView = new wp.revisions.views.View({ 303 model: this._revisions 304 }); 305 this._revisionView.render(); 306 $( '#slider' ).slider( 'option', 'max', this._revisions.length - 1 ); 286 initialize: function( options ) { 287 this.options = _.defaults( options || {}, { 288 value: 0, 289 min: 0, 290 max: 1, 291 step: 1 292 }); 293 }, 307 294 308 this.reloadToLoadRevisions( this._revisions ); 295 slide: function( event, ui ) { 296 if ( this.singleRevision ) { 297 Diff.rightDiff = ( ui.value + 1 ); 298 Diff.revisionView.render(); 299 } else { 300 if ( ui.values[0] === ui.values[1] ) // prevent compare to self 301 return false; 309 302 310 this._revisionsInteractions = new wp.revisions.views.Interact({311 model: this._revisions312 });313 this._revisionsInteractions.render();303 if ( $( ui.handle ).hasClass( 'left-handle' ) ) { 304 // Left handler 305 if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle 306 return false; 314 307 315 this._tickmarkView = new wp.revisions.views.Tickmarks({316 model: this._revisions317 });318 this._tickmarkView.render();319 this._tickmarkView.resetTicks();308 Diff.leftDiff = ui.values[0]; 309 } else { 310 // Right handler 311 if ( Diff.rightModelLoading ) // right model still loading, prevent sliding right handle 312 return false; 320 313 314 Diff.rightDiff = ui.values[1]; 315 } 321 316 322 /* 323 .on( 'mouseup', function( event ) { 324 REVAPP._keep_tooltip_open = false; 325 $( this ).find('.ui-slider-tooltip').hide(); 326 } ).on( 'mousedown', function( event ) { 327 REVAPP._keep_tooltip_open = true; 328 } ).on( 'mouseout', function( event ) { 329 if ( REVAPP._keep_tooltip_open) 330 event.stopImmediatePropagation(); 331 }); 332 */ 333 /* 334 // Options hidden for now, moving to screen options 335 this._revisionsOptions = new wp.revisions.views.Options({ 336 model: this._revisions 337 }); 338 this._revisionsOptions.render(); 339 */ 317 if ( 0 === Diff.leftDiff ) { 318 $( '.revisiondiffcontainer' ).addClass( 'currentversion' ); 319 } else { 320 $( '.revisiondiffcontainer' ).removeClass( 'currentversion' ); 321 } 340 322 323 Diff.revisionView.render(); 341 324 } 342 }) 343 }; 325 }, 344 326 345 wp.revisions.Collection = Backbone.Collection.extend({346 model: wp.revisions.Model,347 url: ajaxurl + '?action=revisions-data&compare_to=' + wpRevisionsSettings.post_id +348 '&show_autosaves=true&show_split_view=true&nonce=' + wpRevisionsSettings.nonce,327 start: function( event, ui ) { 328 // Not needed in one mode 329 if ( this.singleRevision ) 330 return; 349 331 350 initialize: function() { 351 } 352 } ); 332 if ( $( ui.handle ).hasClass( 'left-handle' ) ) { 333 // Left handler 334 if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle 335 return false; 353 336 354 _.extend(wp.revisions.views, {337 Diff.revisionView.draggingLeft = true; 355 338 356 // Ticks inside slider view 357 Tickmarks: Backbone.View.extend({ 358 el: $('#diff-slider-ticks')[0], 359 tagName: 'diff-slider-ticks-view', 360 className: 'diff-slider-ticks-container', 361 template: wp.template('revision-ticks'), 362 model: wp.revisions.Model, 339 if ( Diff.revisionView.model !== Diff.leftHandleRevisions && 340 null !== Diff.leftHandleRevisions ) { 341 Diff.revisionView.model = Diff.leftHandleRevisions; 342 Diff.tickmarkView.model = Diff.leftHandleRevisions; 343 Diff.tickmarkView.render(); 344 } 363 345 364 resetTicks: function() { 365 var sliderMax = $( '#slider' ).slider( 'option', 'max'); 366 var sliderWidth = $( '#slider' ).width(); 367 var adjustMax = ( 2 === REVAPP._compareOneOrTwo ) ? 1 : 0; 368 var tickWidth = Math.floor( sliderWidth / ( sliderMax - adjustMax ) ); 346 Diff.leftDiffStart = ui.values[ 0 ]; 369 347 370 // TODO: adjust right margins for wider ticks so they stay centered on handle stop point 348 } else { 349 // Right handler 350 if ( Diff.rightModelLoading || 0 === Diff.rightHandleRevisions.length) // right model still loading, prevent sliding right handle 351 return false; 371 352 372 // set minimum and maximum widths for tick marks 373 tickWidth = (tickWidth > 50 ) ? 50 : tickWidth; 374 tickWidth = (tickWidth < 10 ) ? 10 : tickWidth; 353 if ( Diff.revisionView.model !== Diff.rightHandleRevisions && 354 null !== Diff.rightHandleRevisions ) { 355 Diff.revisionView.model = Diff.rightHandleRevisions; 356 Diff.tickmarkView.model = Diff.rightHandleRevisions; 357 Diff.tickmarkView.render(); 358 } 375 359 376 sliderWidth = tickWidth * (sliderMax - adjustMax ) + 1; 360 Diff.revisionView.draggingLeft = false; 361 Diff.rightDiffStart = ui.values[1]; 362 } 363 }, 377 364 378 $( '#slider' ).width( sliderWidth );379 $( '.diff-slider-ticks-wrapper' ).width( sliderWidth );380 $( '#diffslider' ).width( sliderWidth );381 $( '#diff-slider-ticks' ).width( sliderWidth );365 stop: function( event, ui ) { 366 // Not needed in one mode 367 if ( this.singleRevision ) 368 return; 382 369 383 var aTickWidth = $( '.revision-tick' ).width(); 370 // calculate and generate a diff for comparing to the left handle 371 // and the right handle, swap out when dragging 372 if ( $( ui.handle ).hasClass( 'left-handle' ) ) { 373 // Left hadnler 374 if ( Diff.leftDiffStart !== ui.values[0] ) 375 Diff.reloadRight(); 376 } else { 377 // Right handler 378 if ( Diff.rightDiffStart !== ui.values[1] ) 379 Diff.reloadLeft(); 380 } 381 }, 384 382 385 if ( tickWidth !== aTickWidth ) { // is the width already set correctly? 386 $( '.revision-tick' ).each( function( ) { 387 $(this).css( 'margin-right', tickWidth - 1 + 'px'); // space the ticks out using right margin 388 }); 383 addTooltip: function( handle, message ) { 389 384 390 if( 2 === REVAPP._compareOneOrTwo ) { 391 $( '.revision-tick' ).first().remove(); // TODO - remove the check 385 handle.attr( 'title', '' ).tooltip({ 386 track: false, 387 388 position: { 389 my: "left-30 top-66", 390 at: "top left", 391 using: function( position, feedback ) { 392 $( this ).css( position ); 393 $( "<div>" ) 394 .addClass( "arrow" ) 395 .addClass( feedback.vertical ) 396 .addClass( feedback.horizontal ) 397 .appendTo( $( this ) ); 392 398 } 393 $( '.revision-tick' ).last().css( 'margin-right', '0' ); // last tick gets no right margin 399 }, 400 show: false, 401 hide: false, 402 content: function() { 403 return message; 394 404 } 395 405 396 }, 406 } ); 407 }, 397 408 398 // render the tickmark view399 re nder: function() {400 var self = this;409 width: function() { 410 return $( '#slider' ).width(); 411 }, 401 412 402 if ( null !== self.model ) { 403 var addHtml = ""; 404 _.each ( self.model.models, function( theModel ) { 405 addHtml = addHtml + self.template ( theModel.toJSON() ); 406 }); 407 self.$el.html( addHtml ); 413 setWidth: function( width ) { 414 return $( '#slider' ).width( width ); 415 }, 408 416 409 } 410 self.resetTicks(); 411 return self; 412 } 413 }), 417 refresh: function( options, slide ) { 418 $( '#slider' ).slider( 'option', options ); 414 419 415 // primary revision diff view 416 View: Backbone.View.extend({ 417 el: $('#backbonerevisionsdiff')[0], 418 tagName: 'revisionvview', 419 className: 'revisionview-container', 420 template: wp.template('revision'), 421 comparetwochecked: '', 422 draggingLeft: false, 420 // Triggers the slide event 421 if ( slide ) 422 $( '#slider' ).trigger( 'slide' ); 423 }, 423 424 424 // render the revisions 425 render: function() { 426 var addHtml = ''; 427 var thediff; 428 // compare two revisions mode? 425 option: function( key ) { 426 return $( '#slider' ).slider( 'option', key ); 427 }, 429 428 430 if ( 2 === REVAPP._compareOneOrTwo ) { 429 render: function() { 430 var self = this; 431 // this.$el doesn't work, why? 432 $( '#slider' ).slider( { 433 slide: $.proxy( self.slide, self ), 434 start: $.proxy( self.start, self ), 435 stop: $.proxy( self.stop, self ) 436 } ); 431 437 432 this.comparetwochecked = 'checked'; 433 if ( this.draggingLeft ) { 434 thediff = REVAPP._leftDiff -1; 435 if ( this.model.at( thediff ) ) { 436 addHtml = this.template( _.extend( 437 this.model.at( thediff ).toJSON(), 438 { comparetwochecked: this.comparetwochecked } // keep the checkmark checked 439 ) ); 440 } 441 } else { // dragging right handle 442 thediff = REVAPP._rightDiff -1; 443 if ( this.model.at( thediff ) ) { 444 addHtml = this.template( _.extend( 445 this.model.at( thediff ).toJSON(), 446 { comparetwochecked: this.comparetwochecked } // keep the checkmark checked 447 ) ); 448 } 449 } 450 } else { // end compare two revisions mode, eg only one slider handle 451 this.comparetwochecked = ''; 452 if ( this.model.at( REVAPP._rightDiff - 1 ) ) { 453 addHtml = this.template( _.extend( 454 this.model.at( REVAPP._rightDiff - 1 ).toJSON(), 455 { comparetwochecked: this.comparetwochecked } // keep the checkmark unchecked 456 ) ); 457 } 458 } 459 this.$el.html( addHtml ); 460 if ( this.model.length < 3 ) { 461 $( 'div#comparetworevisions' ).hide(); // don't allow compare two if fewer than three revisions 462 } 463 if ( this.model.length < 2 ) { 464 $( 'div#diffslider' ).hide(); // don't allow compare two if fewer than three revisions 465 $( 'div.diff-slider-ticks-wrapper' ).hide(); 466 } 438 // Set options 439 this.refresh( this.options ); 440 } 441 }); 467 442 468 // add tooltips to the handles 469 if ( 2 === REVAPP._compareOneOrTwo ) { 470 REVAPP.addTooltip ( $( 'a.ui-slider-handle.left-handle' ), 471 ( REVAPP._leftDiff < 0 ) ? '' : REVAPP._revisions.at( REVAPP._leftDiff - 1 ).get( 'revision_date_author_short' ) ); 472 REVAPP.addTooltip ( $( 'a.ui-slider-handle.right-handle' ), 473 ( REVAPP._rightDiff > REVAPP._revisions.length ) ? '' : REVAPP._revisions.at( REVAPP._rightDiff - 1 ).get( 'revision_date_author_short' ) ); 474 } else { 475 REVAPP.addTooltip ( $( 'a.ui-slider-handle' ), 476 ( REVAPP._rightDiff > REVAPP._revisions.length ) ? '' : REVAPP._revisions.at( REVAPP._rightDiff - 1 ).get( 'revision_date_author_short' ) ); 477 } 443 /** 444 * wp.revisions.view.Tickmarks 445 * 446 * The slider tickmarks. 447 */ 448 revisions.view.Tickmarks = Backbone.View.extend({ 449 el: $('#diff-slider-ticks'), 450 template: wp.template('revision-ticks'), 451 model: Revision, 478 452 479 // hide the restore button when on the last sport/current post data 480 if ( REVAPP._rightDiff === REVAPP._revisions.length ){ 481 $( '.restore-button' ).hide(); 482 } else { 483 $( '.restore-button' ).show(); 484 } 453 resetTicks: function() { 454 var sliderMax = Diff.slider.option( 'max' ); 455 var sliderWidth = Diff.slider.width(); 456 var adjustMax = Diff.singleRevision ? 0 : 1; 457 var tickWidth = Math.floor( sliderWidth / ( sliderMax - adjustMax ) ); 485 458 486 return this; 487 }, 459 // TODO: adjust right margins for wider ticks so they stay centered on handle stop point 488 460 489 // the compare two button is in this view, add the interaction here 490 events: { 491 'click #comparetwo': 'clickcomparetwo' 492 }, 461 // set minimum and maximum widths for tick marks 462 tickWidth = (tickWidth > 50 ) ? 50 : tickWidth; 463 tickWidth = (tickWidth < 10 ) ? 10 : tickWidth; 493 464 494 // turn on/off the compare two mmode 495 clickcomparetwo: function(){ 496 self = this; 465 sliderWidth = tickWidth * (sliderMax - adjustMax ) + 1; 497 466 498 if ( $( 'input#comparetwo' ).is( ':checked' ) ) { // compare 2 mode 499 REVAPP._compareOneOrTwo = 2 ; 467 Diff.slider.setWidth( sliderWidth ); 468 $( '.diff-slider-ticks-wrapper' ).width( sliderWidth ); 469 $( '#diffslider' ).width( sliderWidth ); 470 $( '#diff-slider-ticks' ).width( sliderWidth ); 500 471 501 if ( 1 === REVAPP._rightDiff ) 502 REVAPP._rightDiff = 2; 503 REVAPP._revisionView.draggingLeft = false; 472 var aTickWidth = $( '.revision-tick' ).width(); 504 473 505 wpRevisionsSettings.revision_id = ''; // reset passed revision id so switching back to one handle mode doesn't re-select revision 506 REVAPP.reloadLeftRight(); 507 REVAPP._revisionView.model = REVAPP._rightHandleRevisions; 474 if ( tickWidth !== aTickWidth ) { // is the width already set correctly? 475 $( '.revision-tick' ).each( function( ) { 476 $(this).css( 'margin-right', tickWidth - 1 + 'px'); // space the ticks out using right margin 477 }); 508 478 509 } else { // compare one mode 510 REVAPP._compareOneOrTwo = 1 ; 511 REVAPP._revisionView.draggingLeft = false; 512 // REVAPP._leftDiff = 0; 513 // REVAPP._rightDiff = (REVAPP._revisions.length <= REVAPP._rightDiff ) ? REVAPP._rightDiff + 1 : REVAPP._rightDiff + 1; 514 REVAPP.reloadModelSingle(); 515 } 516 // REVAPP._revisionView.render(); 517 REVAPP._revisionsInteractions.render(); 518 REVAPP._tickmarkView.render(); 519 479 if( ! Diff.singleRevision ) { 480 $( '.revision-tick' ).first().remove(); // TODO - remove the check 481 } 482 $( '.revision-tick' ).last().css( 'margin-right', '0' ); // last tick gets no right margin 520 483 } 521 }),522 484 523 // options view for show autosaves and show split view options 524 /* DISABLED for now 525 Options: Backbone.View.extend({ 526 el: $('#backbonerevisionsoptions')[0], 527 tagName: 'revisionoptionsview', 528 className: 'revisionoptions-container', 529 template: wp.template('revisionoptions'), 485 }, 530 486 531 // render the options view 532 render: function() { 533 var addHtml = this.template; 534 this.$el.html( addHtml ); 535 return this; 536 }, 487 // render the tickmark view 488 render: function() { 489 var self = this; 537 490 538 // add options interactions 539 events: { 540 'click #toggleshowautosaves': 'toggleshowautosaves', 541 'click #showsplitview': 'showsplitview' 542 }, 491 if ( null !== self.model ) { 492 var addHtml = ""; 493 _.each ( self.model.models, function( theModel ) { 494 addHtml = addHtml + self.template ( theModel.toJSON() ); 495 }); 496 self.$el.html( addHtml ); 543 497 544 // toggle include autosaves 545 toggleshowautosaves: function() { 546 var self = this; 547 if ( $( '#toggleshowautosaves' ).is( ':checked' ) ) { 548 REVAPP._autosaves = true ; 549 } else { 550 REVAPP._autosaves = false ; 551 } 498 } 499 self.resetTicks(); 500 return self; 501 } 502 }); 552 503 553 // refresh the model data 554 REVAPP.reloadModel(); 555 }, 504 /** 505 * wp.revisions.view.Interact 506 * 507 * Next/Prev buttons and the slider 508 */ 509 // TODO: Change Interact to something else. 510 revisions.view.Interact = Backbone.View.extend({ 511 el: $('#backbonerevisionsinteract'), 512 template: wp.template('revision-interact'), 556 513 557 // toggle showing the split diff view 558 showsplitview: function() { 559 var self = this; 514 // next and previous buttons, only available in compare one mode 515 events: { 516 'click #next': 'nextRevision', 517 'click #previous': 'previousRevision' 518 }, 560 519 561 if ( $( 'input#showsplitview' ).is( ':checked' ) ) { 562 REVAPP._showSplitView = 'true'; 563 $('.revisiondiffcontainer').addClass('diffsplit'); 564 } else { 565 REVAPP._showSplitView = ''; 566 $('.revisiondiffcontainer').removeClass('diffsplit'); 567 } 520 render: function() { 521 var self = this; 568 522 569 REVAPP.reloadModel(); 570 } 571 }), 572 */ 573 // main interactions view 574 Interact: Backbone.View.extend({ 575 el: $('#backbonerevisionsinteract')[0], 576 tagName: 'revisionvinteract', 577 className: 'revisionvinteract-container', 578 template: wp.template('revisionvinteract'), 523 var addHtml = this.template; 524 this.$el.html( addHtml ); 579 525 580 initialize: function() { 581 }, 526 var modelcount = Diff.revisions.length; 582 527 583 render: function() {584 var self = this;528 Diff.slider.singleRevision = Diff.singleRevision; 529 Diff.slider.render(); 585 530 586 var addHtml = this.template; 587 this.$el.html( addHtml ); 531 if ( Diff.singleRevision ) { 532 Diff.slider.refresh({ 533 value: Diff.rightDiff - 1, 534 min: 0, 535 max: modelcount - 1 536 }); 588 537 589 var modelcount = REVAPP._revisions.length;538 $( '.revisiondiffcontainer' ).removeClass( 'comparetwo' ); 590 539 591 slider = $( "#slider" ); 592 if ( 1 === REVAPP._compareOneOrTwo ) { 593 // set up the slider with a single handle 594 slider.slider({ 595 value: REVAPP._rightDiff - 1, 596 min: 0, 597 max: modelcount - 1, 598 step: 1, 540 } else { 541 Diff.slider.refresh({ 542 values: [ Diff.leftDiff, Diff.rightDiff + 1 ], 543 min: 1, 544 max: modelcount + 1, 545 range: true 546 }); 599 547 548 $( '.revisiondiffcontainer' ).addClass( 'comparetwo' ); 549 $( '#diffslider a.ui-slider-handle' ).first().addClass( 'left-handle' ); 550 $( '#diffslider a.ui-slider-handle' ).last().addClass( 'right-handle' ); 600 551 601 // slide interactions for one handles slider 602 slide: function( event, ui ) { 552 } 603 553 604 REVAPP._rightDiff = ( ui.value + 1 ); 605 REVAPP._revisionView.render(); 606 /* 607 $( 'a.ui-slider-handle' ).tooltip( { 608 content: REVAPP._revisions.at( ui.value ).get( 'revision_date_author_short' ), 609 position: { 610 my: "top-65", 611 using: function( position, feedback ) { 612 $( this ).css( position ); 613 $( "<div>" ) 614 .addClass( "arrow" ) 615 .addClass( feedback.vertical ) 616 .addClass( feedback.horizontal ) 617 .appendTo( this ); 618 } 619 } 620 });// .trigger( 'close' ).trigger( 'open' ); 621 */ 622 } 623 }); 624 $( '.revisiondiffcontainer' ).removeClass( 'comparetwo' ); 554 return this; 555 }, 625 556 626 } else { // comparing more than one, eg 2 627 // set up the slider with two handles 628 slider.slider({ 629 values: [ REVAPP._leftDiff, REVAPP._rightDiff + 1 ], 630 min: 1, 631 max: modelcount + 1, 632 step: 1, 633 range: true, 557 // go to the next revision 558 nextRevision: function() { 559 if ( Diff.rightDiff < this.model.length ) // unless at right boundry 560 Diff.rightDiff = Diff.rightDiff + 1 ; 634 561 635 // in two handled mode when user starts dragging, swap in precalculated diff for handle 636 start: function(event, ui ) { 637 var index = $( ui.handle ).index(); // 0 (left) or 1 (right) 638 switch ( index ) { 639 case 1: // left handle drag 640 if ( REVAPP._leftModelLoading ) // left model still loading, prevent sliding left handle 641 return false; 562 Diff.revisionView.render(); 642 563 643 REVAPP._revisionView.draggingLeft = true; 564 Diff.slider.refresh({ 565 value: Diff.rightDiff - 1 566 }, true ); 567 }, 644 568 645 if ( REVAPP._revisionView.model !== REVAPP._leftHandleRevisions && 646 null !== REVAPP._leftHandleRevisions ) { 647 REVAPP._revisionView.model = REVAPP._leftHandleRevisions; 648 REVAPP._tickmarkView.model = REVAPP._leftHandleRevisions; 649 REVAPP._tickmarkView.render(); 650 } 569 // go the the previous revision 570 previousRevision: function() { 571 if ( Diff.rightDiff > 1 ) // unless at left boundry 572 Diff.rightDiff = Diff.rightDiff - 1 ; 651 573 652 REVAPP._leftDiffStart = ui.values[ 0 ]; 653 break; 574 Diff.revisionView.render(); 654 575 655 case 2: // right 656 if ( REVAPP._rightModelLoading || 0 === REVAPP._rightHandleRevisions.length) // right model still loading, prevent sliding right handle 657 return false; 576 Diff.slider.refresh({ 577 value: Diff.rightDiff - 1 578 }, true ); 579 } 580 }); 658 581 659 if ( REVAPP._revisionView.model !== REVAPP._rightHandleRevisions && 660 null !== REVAPP._rightHandleRevisions ) { 661 REVAPP._revisionView.model = REVAPP._rightHandleRevisions; 662 REVAPP._tickmarkView.model = REVAPP._rightHandleRevisions; 663 REVAPP._tickmarkView.render(); 664 } 582 /** 583 * wp.revisions.view.Diff 584 * 585 * Next/Prev buttons and the slider 586 */ 587 revisions.view.Diff = Backbone.View.extend({ 588 el: $('#backbonerevisionsdiff'), 589 template: wp.template('revision'), 590 draggingLeft: false, 665 591 666 REVAPP._revisionView.draggingLeft = false;667 REVAPP._rightDiffStart = ui.values[1];668 break;669 }670 592 // the compare two button is in this view, add the interaction here 593 events: { 594 'click #comparetwo': 'compareTwo', 595 'click #restore': 'restore' 596 }, 671 597 672 // when sliding in two handled mode change appropriate value673 slide: function( event, ui) {674 if ( ui.values[0] === ui.values[1] ) // prevent compare to self675 return false;598 // render the revisions 599 render: function() { 600 var addHtml = ''; 601 var thediff; 676 602 677 var index = $( ui.handle ).index(); // 0 (left) or 1 (right) 603 // compare two revisions mode? 604 if ( ! Diff.singleRevision ) { 605 if ( this.draggingLeft ) { 606 thediff = Diff.leftDiff - 1; 607 if ( this.model.at( thediff ) ) { 608 addHtml = this.template( this.model.at( thediff ).toJSON() ); 609 } 610 } else { // dragging right handle 611 thediff = Diff.rightDiff -1; 612 if ( this.model.at( thediff ) ) { 613 addHtml = this.template( this.model.at( thediff ).toJSON() ); 614 } 615 } 616 } else { // end compare two revisions mode, eg only one slider handle 617 this.comparetwochecked = ''; 618 if ( this.model.at( Diff.rightDiff - 1 ) ) { 619 addHtml = this.template( this.model.at( Diff.rightDiff - 1 ).toJSON() ); 620 } 621 } 622 this.$el.html( addHtml ); 678 623 679 switch ( index) {680 case 1: // left681 if ( REVAPP._leftModelLoading ) // left model still loading, prevent sliding left handle682 return false;624 if ( this.model.length < 2 ) { 625 $( '#diffslider' ).hide(); // don't allow compare two if fewer than three revisions 626 $( '.diff-slider-ticks-wrapper' ).hide(); 627 } 683 628 684 REVAPP._leftDiff = ui.values[0]; 685 break; 629 // add tooltips to the handles 630 if ( ! Diff.singleRevision ) { 631 Diff.slider.addTooltip ( $( 'a.ui-slider-handle.left-handle' ), 632 ( Diff.leftDiff < 0 ) ? '' : Diff.revisions.at( Diff.leftDiff - 1 ).get( 'titleTooltip' ) ); 633 Diff.slider.addTooltip ( $( 'a.ui-slider-handle.right-handle' ), 634 ( Diff.rightDiff > Diff.revisions.length ) ? '' : Diff.revisions.at( Diff.rightDiff - 1 ).get( 'titleTooltip' ) ); 635 } else { 636 Diff.slider.addTooltip ( $( 'a.ui-slider-handle' ), 637 ( Diff.rightDiff > Diff.revisions.length ) ? '' : Diff.revisions.at( Diff.rightDiff - 1 ).get( 'titleTooltip' ) ); 638 } 686 639 687 case 2: // right 688 if ( REVAPP._rightModelLoading ) // right model still loading, prevent sliding right handle 689 return false; 640 this.toogleCompareTwoCheckbox(); 690 641 691 REVAPP._rightDiff = ui.values[1]; 692 break; 693 } 642 // hide the restore button when on the last sport/current post data 643 if ( Diff.rightDiff === Diff.revisions.length ){ 644 $( '#restore' ).hide(); 645 } else { 646 $( '#restore' ).show(); 647 } 694 648 695 if ( 0 === REVAPP._leftDiff ) {696 $( '.revisiondiffcontainer' ).addClass( 'currentversion' );649 return this; 650 }, 697 651 698 } else { 699 $( '.revisiondiffcontainer' ).removeClass( 'currentversion' ); 700 } 652 toogleCompareTwoCheckbox: function() { 653 // don't allow compare two if fewer than three revisions 654 if ( this.model.length < 3 ) 655 $( '#comparetworevisions' ).hide(); 701 656 702 REVAPP._revisionView.render(); 657 $( '#comparetwo' ).prop( 'checked', ! Diff.singleRevision ); 658 }, 703 659 704 }, 660 // turn on/off the compare two mode 661 compareTwo: function() { 662 if ( $( 'input#comparetwo' ).is( ':checked' ) ) { // compare 2 mode 663 Diff.singleRevision = false ; 705 664 706 // when the user stops sliding in 2 handle mode, recalculate diffs 707 stop: function( event, ui ) { 708 if ( 2 === REVAPP._compareOneOrTwo ) { 709 // calculate and generate a diff for comparing to the left handle 710 // and the right handle, swap out when dragging 665 if ( 1 === Diff.rightDiff ) 666 Diff.rightDiff = 2; 711 667 712 var index = $( ui.handle ).index(); // 0 (left) or 1 (right)668 Diff.revisionView.draggingLeft = false; 713 669 714 switch ( index ) { 715 case 1: // left 670 revisions.model.settings.revision_id = ''; // reset passed revision id so switching back to one handle mode doesn't re-select revision 671 Diff.reloadLeftRight(); 672 Diff.revisionView.model = Diff.rightHandleRevisions; 716 673 717 // left handle dragged & changed, reload right handle model 718 if ( REVAPP._leftDiffStart !== ui.values[0] ) 719 REVAPP.reloadRight(); 674 } else { // compare one mode 675 Diff.singleRevision = true; 676 Diff.revisionView.draggingLeft = false; 677 Diff.reloadModelSingle(); 678 } 679 Diff.revisionsInteractions.render(); 680 Diff.tickmarkView.render(); 681 }, 720 682 721 break; 683 restore: function() { 684 document.location = $( '#restore' ).data( 'restoreLink' ); 685 } 686 }); 722 687 723 case 2: // right724 // REVAPP._rightDiff = ( 1 >= REVAPP._rightDiff ) ? 1 : REVAPP._rightDiff - 1;725 // right handle dragged & changed, reload left handle model if changed726 if ( REVAPP._rightDiffStart !== ui.values[1] )727 REVAPP.reloadLeft();728 688 729 break; 730 } 731 } 732 } 733 }); 734 $( '.revisiondiffcontainer' ).addClass( 'comparetwo' ); 735 $( '#diffslider a.ui-slider-handle' ).first().addClass( 'left-handle' ).next().addClass( 'right-handle' ); 736 } 689 /** 690 * ======================================================================== 691 * MODELS 692 * ======================================================================== 693 */ 737 694 738 return this; 739 }, 695 /** 696 * wp.revisions.Revision 697 */ 698 Revision = revisions.model.Revision = Backbone.Model.extend({ 699 idAttribute: 'ID', 700 urlRoot: ajaxurl + '?action=revisions-data' + 701 '&show_autosaves=true&show_split_view=true&nonce=' + revisions.model.settings.nonce, 702 defaults: { 703 ID: 0, 704 titleTo: '', 705 titleTooltip: '', 706 titleFrom: '', 707 diff: '<div class="diff-loading"><div class="spinner"></div></div>', 708 restoreLink: '', 709 revision_toload: false, 710 lines_added: 0, 711 lines_deleted: 0, 712 scope_of_changes: 'none', 713 previous_revision_id: 0 714 }, 740 715 741 // next and previous buttons, only available in compare one mode 742 events: { 743 'click #next': 'nextRevision', 744 'click #previous': 'previousRevision' 745 }, 716 url: function() { 717 if ( Diff.singleRevision ) { 718 return this.urlRoot + 719 '&single_revision_id=' + this.id + 720 '&compare_to=' + this.get( 'previous_revision_id' ) + 721 '&post_id=' + revisions.model.settings.post_id; 722 } else { 723 return this.urlRoot + '&single_revision_id=' + this.id; 724 } 746 725 747 // go to the next revision 748 nextRevision: function() { 749 if ( REVAPP._rightDiff < this.model.length ) // unless at right boundry 750 REVAPP._rightDiff = REVAPP._rightDiff + 1 ; 726 } 727 }); 751 728 752 REVAPP._revisionView.render(); 729 /** 730 * wp.revisions.Revisions 731 */ 732 Revisions = revisions.Revisions = Backbone.Collection.extend({ 733 model: Revision, 734 urlRoot: ajaxurl + '?action=revisions-data', 753 735 754 $( '#slider' ).slider( 'value', REVAPP._rightDiff - 1 ).trigger( 'slide' ); 755 }, 736 initialize: function( models, options ) { 737 this.options = _.defaults( options || {}, { 738 'compareTo': revisions.model.settings.post_id, 739 'post_id': revisions.model.settings.post_id, 740 'showAutosaves': true, 741 'showSplitView': true, 742 'rightHandleAt': 0, 743 'leftHandleAt': 0, 744 'nonce': revisions.model.settings.nonce 745 }); 746 }, 756 747 757 // go the the previous revision 758 previousRevision: function() { 759 if ( REVAPP._rightDiff > 1 ) // unless at left boundry 760 REVAPP._rightDiff = REVAPP._rightDiff - 1 ; 748 url: function() { 749 return this.urlRoot + 750 '&compare_to=' + this.options.compareTo + 751 '&post_id=' + this.options.post_id + 752 '&show_autosaves=' + this.options.showAutosaves + 753 '&show_split_view=' + this.options.showSplitView + 754 '&right_handle_at=' + this.options.rightHandleAt + 755 '&left_handle_at=' + this.options.leftHandleAt + 756 '&nonce=' + this.options.nonce; 757 }, 761 758 762 REVAPP._revisionView.render(); 759 reload: function( options ) { 760 this.options = _.defaults( options || {}, this.options ); 763 761 764 $( '#slider' ).slider( 'value', REVAPP._rightDiff - 1 ).trigger( 'slide' ); 765 } 766 }) 767 }); 762 // TODO 763 //this.fetch(); 764 } 768 765 769 // instantiate Revision Application 770 REVAPP = new wp.revisions.App(); 766 } ); 771 767 768 $( wp.revisions ); 769 772 770 }(jQuery)); -
wp-admin/revision.php
79 79 80 80 require_once( './admin-header.php' ); 81 81 82 //TODO - Some of the translations below split things into multiple strings that are contextually related and this makes it pretty impossible for RTL translation. 83 //TODO can we pass the context in a better way 84 $wpRevisionsSettings = array( 'post_id' => $post->ID, 85 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ), 86 'revision_id' => $revision_id ); 87 wp_localize_script( 'revisions', 'wpRevisionsSettings', $wpRevisionsSettings ); 82 $strings = array( 83 'diffFromTitle' => _x( 'From: %s', 'revision from title' ), 84 'diffToTitle' => _x( 'To: %s', 'revision to title' ) 85 ); 88 86 87 $settings = array( 88 'post_id' => $post->ID, 89 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ), 90 'revision_id' => $revision_id 91 ); 92 93 $strings['settings'] = $settings; 94 95 wp_localize_script( 'revisions', 'wpRevisionsL10n', $strings ); 96 89 97 $comparetworevisionslink = get_edit_post_link( $revision->ID ); 90 98 ?> 91 99 … … 112 120 </div> 113 121 114 122 <script id="tmpl-revision" type="text/html"> 123 <div id="comparetworevisions"> 124 <label> 125 <input type="checkbox" id="comparetwo" /> 126 <?php esc_attr_e( 'Compare two revisions' ); ?> 127 </label> 128 </div> 129 115 130 <div id="diffsubheader" class="diff-left-hand-meta-row"> 116 131 <div id="diff_from_current_revision"> 117 132 <?php printf( '<b>%1$s</b> %2$s.' , __( 'From:' ), __( 'the current version' ) ); ?> 118 133 </div> 119 134 <div id="difftitlefrom"> 120 <div class="diff-from-title"><?php _e( 'From:' ); ?></div>{{{ data. revision_from_date_author}}}135 <div class="diff-from-title"><?php _e( 'From:' ); ?></div>{{{ data.titleFrom }}} 121 136 </div> 122 137 </div> 123 138 124 139 <div id="diffsubheader"> 125 140 <div id="difftitle"> 126 <div class="diff-to-title"><?php _e( 'To:' ); ?></div>{{{ data. revision_date_author}}}141 <div class="diff-to-title"><?php _e( 'To:' ); ?></div>{{{ data.titleTo }}} 127 142 </div> 128 143 <div id="diffrestore"> 129 <input class="button button-primary restore-button" onClick="document.location='{{{ data.restoreaction }}}'" type="submit" id="restore" value="<?php esc_attr_e( 'Restore This Revision' )?>" />144 <input class="button button-primary" data-restore-link="{{{ data.restoreLink }}}" type="button" id="restore" value="<?php esc_attr_e( 'Restore This Revision' )?>" /> 130 145 </div> 131 <div id="comparetworevisions">132 <input type="checkbox" id="comparetwo" value="comparetwo" {{{ data.comparetwochecked }}} name="comparetwo"/>133 <label for="comparetwo"><?php esc_attr_e( 'Compare two revisions' ); ?></a></label>134 </div>135 146 </div> 136 147 137 148 <div id="removedandadded"> 138 149 <div id="removed"><?php _e( 'Removed -' ); ?></div> 139 150 <div id="added"><?php _e( 'Added +' ); ?></div> 140 151 </div 141 <div>{{{ data. revisiondiff }}}</div>152 <div>{{{ data.diff }}}</div> 142 153 </script> 143 154 144 <script id="tmpl-revision vinteract" type="text/html">155 <script id="tmpl-revision-interact" type="text/html"> 145 156 <div id="diffheader"> 146 157 <div id="diffprevious"><input class="button" type="submit" id="previous" value="<?php esc_attr_e( 'Previous' ); ?>" /> 147 158 </div> … … 153 164 </div> 154 165 </div> 155 166 </script> 167 156 168 <script id="tmpl-revision-ticks" type="text/html"> 157 169 <div class="revision-tick revision-toload{{{ data.revision_toload }}} revision-scopeofchanges-{{{ data.scope_of_changes }}}"> 158 170 </div> 159 171 </script> 160 172 <?php 161 /* 162 TODO Convert these into screen options 163 <script id="tmpl-revisionoptions" type="text/html"> 164 <div id="revisionoptions"> 165 <div id="showsplitviewoption"> 166 <input type='checkbox' id="show_split_view" checked="checked" value="1" /> <?php _e( 'Show split diff view' ); ?> 167 </div> 168 <div id="toggleshowautosavesoption"> 169 <input type='checkbox' id="toggleshowautosaves" value="1" /> <?php _e( 'Show autosaves' ); ?> 170 </div> 171 </div> 172 </script> 173 */ 174 require_once( './admin-footer.php' ); 175 No newline at end of file 173 require_once( './admin-footer.php' );