Ticket #24425: 24425.draft.2.diff
File 24425.draft.2.diff, 49.7 KB (added by , 10 years ago) |
---|
-
wp-admin/admin-ajax.php
do_action( 'admin_init' ); 42 42 43 43 $core_actions_get = array( 44 44 'fetch-list', 'ajax-tag-search', 'wp-compression-test', 'imgedit-preview', 'oembed-cache', 45 'autocomplete-user', 'dashboard-widgets', 'logged-in', 'revisions-data'45 'autocomplete-user', 'dashboard-widgets', 'logged-in', 46 46 ); 47 47 48 48 $core_actions_post = array( … … $core_actions_post = array( 56 56 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post', 57 57 'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment', 58 58 'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor', 59 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'show-post-format-ui', 59 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs', 60 'show-post-format-ui', 60 61 ); 61 62 62 63 // Register core Ajax calls. -
wp-admin/css/wp-admin.css
td.plugin-title p { 3528 3528 /*------------------------------------------------------------------------------ 3529 3529 11.2 - Post Revisions 3530 3530 ------------------------------------------------------------------------------*/ 3531 .revisions .spinner { 3532 float: none; 3533 margin: 100px auto; 3534 } 3535 3536 .revisions.loading .spinner { 3537 display: block; 3538 } 3539 3540 .revisions-control-frame, 3541 .revisions-diff-frame { 3542 position: relative; 3543 } 3544 3545 .revisions-controls { 3546 height: 20px; 3547 padding: 40px 0 20px; 3548 border-bottom: 1px solid #dfdfdf; 3549 margin-bottom: 10px; 3550 } 3551 3552 .revision-toggle-compare-mode { 3553 position: absolute; 3554 top: 0; 3555 right: 0; 3556 } 3557 3558 .revisions-previous { 3559 float: left; 3560 } 3561 3562 .revisions-next { 3563 float: right; 3564 } 3565 3566 .revisions-slider { 3567 width: 70%; 3568 margin: 6px auto 0; 3569 } 3531 3570 3532 3571 /* Revision meta box */ 3533 3572 .post-revisions li img, … … table.diff .diff-addedline ins { 3574 3613 position: relative; 3575 3614 } 3576 3615 3577 #toggle-revision-compare-mode {3578 position: absolute;3579 top: 0;3580 right: 0;3581 padding: 9px 9px 0 0;3582 }3583 3584 3616 #loading-status { 3585 3617 display: none; 3586 3618 position: absolute; … … table.diff .diff-addedline ins { 3598 3630 padding: 20px 0; 3599 3631 } 3600 3632 3601 #diff-next-revision,3602 #diff-previous-revision {3603 margin-top: -.4em; /* Same line as the slider (height: .8em) */3604 }3605 3606 #diff-next-revision {3607 float: right;3608 }3609 3610 #diff-previous-revision {3611 float: left;3612 }3613 3614 #diff-slider {3615 width: 70%;3616 margin: 0 auto;3617 }3618 3619 3633 .comparetwo #diff-slider { 3620 3634 width: 95%; 3621 3635 } -
wp-admin/includes/ajax-actions.php
function wp_ajax_heartbeat() { 2102 2102 wp_send_json($response); 2103 2103 } 2104 2104 2105 function wp_ajax_revisions_data() { 2106 check_ajax_referer( 'revisions-ajax-nonce', 'nonce' ); 2107 2108 $compare_to = ! empty( $_GET['compare_to'] ) ? absint( $_GET['compare_to'] ) : 0; 2109 $show_autosaves = ! empty( $_GET['show_autosaves'] ); 2110 $show_split_view = ! empty( $_GET['show_split_view'] ); 2111 $post_id = ! empty( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0; 2112 $right_handle_at = ! empty( $_GET['right_handle_at'] ) ? (int) $_GET['right_handle_at'] : 0; 2113 $left_handle_at = ! empty( $_GET['left_handle_at'] ) ? (int) $_GET['left_handle_at'] : 0; 2114 $single_revision_id = ! empty( $_GET['single_revision_id'] ) ? absint( $_GET['single_revision_id'] ) : 0; 2115 $compare_two_mode = (bool) $post_id; 2116 2117 $all_the_revisions = array(); 2118 if ( ! $post_id ) 2119 $post_id = $compare_to; 2120 2121 if ( ! current_user_can( 'read_post', $post_id ) ) 2122 continue; 2123 2124 if ( ! $revisions = wp_get_post_revisions( $post_id ) ) 2125 return; 2126 2127 $left_revision = get_post( $compare_to ); 2128 2129 // single model fetch mode 2130 // return the diff of a single revision comparison 2131 if ( $single_revision_id ) { 2132 $right_revision = get_post( $single_revision_id ); 2133 2134 if ( ! $compare_to ) 2135 $left_revision = get_post( $post_id ); 2136 2137 // make sure the right revision is the most recent, except on oldest revision 2138 if ( $compare_to && $right_revision->post_date < $left_revision->post_date ) { 2139 $temp = $left_revision; 2140 $left_revision = $right_revision; 2141 $right_revision = $temp; 2142 } 2143 2144 $lines_added = $lines_deleted = 0; 2145 $content = ''; 2146 // compare from left to right, passed from application 2147 foreach ( _wp_post_revision_fields() as $field => $field_value ) { 2148 $left_content = apply_filters( "_wp_post_revision_field_$field", $left_revision->$field, $field, $left_revision, 'left' ); 2149 $right_content = apply_filters( "_wp_post_revision_field_$field", $right_revision->$field, $field, $right_revision, 'right' ); 2150 2151 add_filter( "_wp_post_revision_field_$field", 'htmlspecialchars' ); 2152 2153 $args = array(); 2154 2155 if ( $show_split_view ) 2156 $args = array( 'show_split_view' => true ); 2157 2158 // compare_to == 0 means first revision, so compare to a blank field to show whats changed 2159 $diff = wp_text_diff_with_count( ( 0 == $compare_to ) ? '' : $left_content, $right_content, $args ); 2105 function wp_ajax_get_revision_diffs() { 2106 require ABSPATH . 'wp-admin/includes/revision.php'; 2160 2107 2161 if ( isset( $diff[ 'html' ] ) ) { 2162 $content .= sprintf( '<div class="diff-label">%s</div>', $field_value ); 2163 $content .= $diff[ 'html' ]; 2164 } 2165 2166 if ( isset( $diff[ 'lines_added' ] ) ) 2167 $lines_added = $lines_added + $diff[ 'lines_added' ]; 2168 2169 if ( isset( $diff[ 'lines_deleted' ] ) ) 2170 $lines_deleted = $lines_deleted + $diff[ 'lines_deleted' ]; 2171 } 2172 $content = '' == $content ? __( 'No difference' ) : $content; 2173 2174 $all_the_revisions = array ( 2175 'diff' => $content, 2176 'linesDeleted' => $lines_deleted, 2177 'linesAdded' => $lines_added 2178 ); 2108 // check_ajax_referer( 'revisions-ajax-nonce', 'nonce' ); 2179 2109 2180 echo json_encode( $all_the_revisions ); 2181 exit(); 2182 } // end single model fetch 2183 2184 $count = -1; 2185 2186 // reverse the list to start with oldest revision 2187 $revisions = array_reverse( $revisions ); 2188 2189 $previous_revision_id = 0; 2190 2191 /* translators: revision date format, see http://php.net/date */ 2192 $datef = _x( 'j F, Y @ G:i:s', 'revision date format'); 2193 2194 foreach ( $revisions as $revision ) : 2195 if ( ! $show_autosaves && wp_is_post_autosave( $revision ) ) 2196 continue; 2197 2198 $revision_from_date_author = ''; 2199 $is_current_revision = false; 2200 $count++; 2201 2202 /** 2203 * return blank data for diffs to the left of the left handle (for right handel model) 2204 * or to the right of the right handle (for left handel model) 2205 * and visa versa in RTL mode 2206 */ 2207 if( ! is_rtl() ) { 2208 if ( ( ( 0 != $left_handle_at && $count < $left_handle_at ) || 2209 ( 0 != $right_handle_at && $count > ( $right_handle_at - 2 ) ) ) ) { 2210 $all_the_revisions[] = array ( 2211 'ID' => $revision->ID, 2212 ); 2213 continue; 2214 } 2215 } else { // is_rtl 2216 if ( ( 0 != $left_handle_at && $count > ( $left_handle_at - 1 ) || 2217 ( 0 != $left_handle_at && $count < $right_handle_at ) ) ) { 2218 $all_the_revisions[] = array ( 2219 'ID' => $revision->ID, 2220 ); 2221 continue; 2222 } 2223 } 2224 2225 if ( $compare_two_mode ) { 2226 $compare_to_gravatar = get_avatar( $left_revision->post_author, 24 ); 2227 $compare_to_author = get_the_author_meta( 'display_name', $left_revision->post_author ); 2228 $compare_to_date = date_i18n( $datef, strtotime( $left_revision->post_modified ) ); 2229 2230 $revision_from_date_author = sprintf( 2231 /* translators: post revision title: 1: author avatar, 2: author name, 3: time ago, 4: date */ 2232 _x( '%1$s %2$s, %3$s ago (%4$s)', 'post revision title' ), 2233 $compare_to_gravatar, 2234 $compare_to_author, 2235 human_time_diff( strtotime( $left_revision->post_modified ), current_time( 'timestamp' ) ), 2236 $compare_to_date 2237 ); 2238 } 2239 2240 $gravatar = get_avatar( $revision->post_author, 24 ); 2241 $author = get_the_author_meta( 'display_name', $revision->post_author ); 2242 $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); 2243 $revision_date_author = sprintf( 2244 /* translators: post revision title: 1: author avatar, 2: author name, 3: time ago, 4: date */ 2245 _x( '%1$s %2$s, %3$s ago (%4$s)', 'post revision title' ), 2246 $gravatar, 2247 $author, 2248 human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ), 2249 $date 2250 ); 2251 2252 /* translators: 1: date */ 2253 $autosavef = _x( '%1$s [Autosave]', 'post revision title extra' ); 2254 /* translators: 1: date */ 2255 $currentf = _x( '%1$s [Current Revision]', 'post revision title extra' ); 2256 2257 if ( ! $post = get_post( $post_id ) ) 2258 continue; 2110 if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) ) 2111 wp_send_json_error(); 2259 2112 2260 if ( $left_revision->post_modified === $post->post_modified ) 2261 $revision_from_date_author = sprintf( $currentf, $revision_from_date_author ); 2262 elseif ( wp_is_post_autosave( $left_revision ) ) 2263 $revision_from_date_author = sprintf( $autosavef, $revision_from_date_author ); 2113 if ( ! current_user_can( 'read_post', $post->ID ) ) 2114 wp_send_json_error(); 2264 2115 2265 if ( $revision->post_modified === $post->post_modified ) { 2266 $revision_date_author = sprintf( $currentf, $revision_date_author ); 2267 $is_current_revision = true; 2268 } elseif ( wp_is_post_autosave( $revision ) ) { 2269 $revision_date_author = sprintf( $autosavef, $revision_date_author ); 2270 } 2116 // Really just pre-loading the cache here. 2117 if ( ! $revisions = wp_get_post_revisions( $post->ID ) ) 2118 wp_send_json_error(); 2271 2119 2272 /* translators: revision date short format, see http://php.net/date */ 2273 $date_short_format = _x( 'j M @ G:i', 'revision date short format'); 2274 $date_short = date_i18n( $date_short_format, strtotime( $revision->post_modified ) ); 2120 $return = array(); 2121 @set_time_limit( count( $_REQUEST['compare'] ) ); 2275 2122 2276 $revision_date_author_short = sprintf( 2277 '%s <strong>%s</strong><br />%s', 2278 $gravatar, 2279 $author, 2280 $date_short 2281 ); 2123 foreach ( $_REQUEST['compare'] as $compare_key ) { 2124 list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to 2282 2125 2283 $restore_link = wp_nonce_url( 2284 add_query_arg( 2285 array( 'revision' => $revision->ID, 2286 'action' => 'restore' ), 2287 admin_url( 'revision.php' ) 2288 ), 2289 "restore-post_{$revision->ID}" 2126 $return[] = array( 2127 'id' => $compare_key, 2128 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ), 2290 2129 ); 2130 } 2291 2131 2292 // if this is a left handled calculation swap data 2293 if ( 0 != $right_handle_at ) { 2294 $tmp = $revision_from_date_author; 2295 $revision_from_date_author = $revision_date_author; 2296 $revision_date_author = $tmp; 2297 } 2298 2299 if ( ( $compare_two_mode || -1 !== $previous_revision_id ) ) { 2300 $all_the_revisions[] = array ( 2301 'ID' => $revision->ID, 2302 'titleTo' => $revision_date_author, 2303 'titleFrom' => $revision_from_date_author, 2304 'titleTooltip' => $revision_date_author_short, 2305 'restoreLink' => urldecode( $restore_link ), 2306 'previousID' => $previous_revision_id, 2307 'isCurrent' => $is_current_revision, 2308 ); 2309 } 2310 $previous_revision_id = $revision->ID; 2311 2312 endforeach; 2313 2314 // in RTL + single handle mode, reverse the revision direction 2315 if ( is_rtl() && $compare_two_mode ) 2316 $all_the_revisions = array_reverse( $all_the_revisions ); 2317 2318 echo json_encode( $all_the_revisions ); 2319 exit(); 2132 wp_send_json_success( $return ); 2320 2133 } -
wp-admin/js/revisions.js
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 * CONTROLLERS14 * 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 }, 26 revisions.model.Revision = Backbone.Model.extend({}); 58 27 59 loadDiffs: function( models ) { 60 var self = this, 61 revisionsToLoad = models.where( { completed: false } ), 62 delay = 0, 63 totalChanges; 28 revisions.model.Revisions = Backbone.Collection.extend({ 29 model: revisions.model.Revision 30 }); 64 31 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 }); 32 revisions.model.Field = Backbone.Model.extend({}); 70 33 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 }, 34 revisions.model.Fields = Backbone.Collection.extend({ 35 model: revisions.model.Field 36 }); 112 37 113 startLeftModelLoading: function(){114 this.leftModelLoading = true;115 $('#revision-diff-container').addClass('left-model-loading');116 },38 revisions.model.Diff = Backbone.Model.extend({ 39 initialize: function(attributes, options) { 40 var fields = this.get('fields'); 41 this.unset('fields'); 117 42 118 stopLeftModelLoading: function() {119 this.leftModelLoading = false;120 },43 this.fields = new revisions.model.Fields( fields ); 44 } 45 }); 121 46 122 startRightModelLoading: function() { 123 this.rightModelLoading = true; 124 $('#revision-diff-container').addClass('right-model-loading'); 125 }, 47 revisions.model.Diffs = Backbone.Collection.extend({ 48 model: revisions.model.Diff, 126 49 127 stopRightModelLoading: function() {128 this.rightModelLoading = false;50 load: function( comparisons ) { 51 return this.fetch({ data: { compare: comparisons } }); 129 52 }, 130 53 131 stopModelLoadingSpinner: function() { 132 $('#revision-diff-container').removeClass('right-model-loading'); 133 $('#revision-diff-container').removeClass('left-model-loading'); 134 }, 54 sync: function( method, model, options ) { 55 // Overload the `read` request so Attachment.fetch() functions correctly. 56 if ( 'read' === method ) { 57 options = options || {}; 58 options.context = this; 59 options.data = _.extend( options.data || {}, { 60 action: 'get-revision-diffs', 61 post_id: revisions.settings.postId 62 }); 63 return wp.xhr.send( options ); 135 64 136 reloadModel: function() { 137 if ( this.singleRevision ) { 138 this.reloadModelSingle(); 65 // Otherwise, fall back to `Backbone.sync()`. 139 66 } else { 140 this.reloadLeftRight();67 return Backbone.Model.prototype.sync.apply( this, arguments ); 141 68 } 142 },143 144 // load the models for the single handle mode145 reloadModelSingle: function() {146 var self = this;147 148 self.startRightModelLoading();149 150 self.revisions.reload({151 options: {152 'showAutosaves': self.autosaves,153 'showSplitView': self.showSplitView154 },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 mode165 'value': self.rightDiff - 1 // slider starts at 0 in single handle mode166 }, true);167 },168 169 error: function() {170 self.stopRightModelLoading();171 }172 });173 },174 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 1181 'showAutosaves': self.autosaves,182 'showSplitView': self.showSplitView,183 'rightHandleAt': self.rightDiff184 });185 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.length193 });194 // ensure right handle not beyond length195 if ( self.rightDiff > self.revisions.length )196 self.rightDiff = self.revisions.length;197 },198 199 error: function() {200 self.stopLeftModelLoading();201 }202 });203 },204 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 1211 'showAutosaves': self.autosaves,212 'showSplitView': self.showSplitView,213 'leftHandleAt': self.leftDiff214 });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.length223 }, true);224 },225 226 error: function( response ) {227 self.stopRightModelLoading();228 }229 });230 231 },232 233 /**234 * reloadLeftRight reload models for both the left and right handles235 */236 reloadLeftRight: function() {237 this.startRightModelLoading();238 this.startLeftModelLoading();239 this.reloadLeft();240 this.reloadRight();241 },242 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 node249 if ( maxVal === val )250 next.prop( 'disabled', true );251 else252 next.prop( 'disabled', false );253 254 // Disable "Previous" button if you're on the 0 node255 if ( 0 === val )256 prev.prop( 'disabled', true );257 else258 prev.prop( 'disabled', false );259 },260 261 /**262 * completeApplicationSetup finishes loading all views once the initial model load is complete263 */264 completeApplicationSetup: function() {265 this.revisionView = new revisions.view.Diff({266 model: this.revisions267 });268 this.revisionView.render(); // render the revision view269 270 this.loadDiffs( this.revisions ); // get the actual revisions data271 272 this.revisionsInteractions = new revisions.view.Interact({273 model: this.revisions274 });275 this.revisionsInteractions.render(); // render the interaction view276 277 this.tickmarkView = new revisions.view.Tickmarks({278 model: this.revisions279 });280 this.tickmarkView.render(); // render the tickmark view281 69 } 282 70 }); 283 71 … … window.wp = window.wp || {}; 288 76 * ======================================================================== 289 77 */ 290 78 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 }); 307 }, 308 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 } 79 // The frame view. This contains the entire page. 80 revisions.view.Frame = wp.Backbone.View.extend({ 81 tagName: 'div', 82 className: 'revisions', 83 template: wp.template('revisions-frame'), 336 84 337 Diff.revisionView.render(); 338 } 339 }, 340 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 381 } 382 }, 383 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(); 404 } 405 }, 406 407 addTooltip: function( handle, message ) { 408 handle.find( '.ui-slider-tooltip' ).html( message ); 409 }, 410 411 width: function() { 412 return $( '#diff-slider' ).width(); 413 }, 414 415 setWidth: function( width ) { 416 $( '#diff-slider' ).width( width ); 417 }, 418 419 refresh: function( options, slide ) { 420 $( '#diff-slider' ).slider( 'option', options ); 421 422 // Triggers the slide event 423 if ( slide ) 424 $( '#diff-slider' ).trigger( 'slide' ); 425 426 Diff.disabledButtonCheck( options.value ); 427 }, 428 429 option: function( key ) { 430 return $( '#diff-slider' ).slider( 'option', key ); 85 initialize: function() { 86 this.views.set( '.revisions-control-frame', new revisions.view.Controls() ); 87 this.views.set( '.revisions-diff-frame', new revisions.view.Diff() ); 431 88 }, 432 89 433 90 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 ); 444 } 445 }); 91 wp.Backbone.View.prototype.render.apply( this, arguments ); 446 92 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 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 } 482 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 } ); 540 }, 541 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; 556 } 557 } ); 558 559 /** 560 * wp.revisions.view.Interact 561 * 562 * Next/Prev buttons and the slider 563 */ 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 574 render: function() { 575 var modelcount; 576 this.$el.html( this.template ); 577 578 modelcount = Diff.revisions.length; 579 580 Diff.slider.singleRevision = Diff.singleRevision; 581 Diff.slider.render(); 582 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 }); 589 590 $( '#revision-diff-container' ).removeClass( 'comparing-two-revisions' ); 591 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 }); 600 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' ); 605 606 } 93 $('#wpbody-content .wrap').append( this.el ); 94 this.views.ready(); 607 95 608 96 return this; 609 },610 611 // go to the next revision612 nextRevision: function() {613 if ( Diff.rightDiff < this.model.length ) // unless at right boundry614 Diff.rightDiff = Diff.rightDiff + 1 ;615 616 Diff.revisionView.render();617 618 Diff.slider.refresh({619 value: Diff.rightDiff - 1620 }, true );621 },622 623 // go to the previous revision624 previousRevision: function() {625 if ( Diff.rightDiff > 1 ) // unless at left boundry626 Diff.rightDiff = Diff.rightDiff - 1 ;627 628 Diff.revisionView.render();629 630 Diff.slider.refresh({631 value: Diff.rightDiff - 1632 }, true );633 97 } 634 98 }); 635 99 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' 650 }, 100 // The control view. 101 // This contains the revision slider, previous/next buttons, and the compare checkbox. 102 revisions.view.Controls = wp.Backbone.View.extend({ 103 tagName: 'div', 104 className: 'revisions-controls', 105 template: wp.template('revisions-controls'), 651 106 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' ) ); 107 initialize: function() { 108 this.views.set( new revisions.view.Slider() ); 109 } 110 }); 685 111 686 return this; 112 // The slider view. 113 // Encapsulates all of the configuration for the jQuery UI slider into a view. 114 revisions.view.Slider = wp.Backbone.View.extend({ 115 tagName: 'div', 116 className: 'wp-slider', 117 118 initialize: function() { 119 // Create the slider model. 120 if ( ! this.model ) 121 this.model = new revisions.model.Slider(); 122 123 // Attach the start, slide, and stop methods to the model. 124 _.bindAll( this, 'start', 'slide', 'stop' ); 125 this.model.set({ 126 start: this.start, 127 slide: this.slide, 128 stop: this.stop 129 }); 687 130 }, 688 131 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(); 693 694 $( '#compare-two-revisions' ).prop( 'checked', ! Diff.singleRevision ); 132 ready: function() { 133 this.$el.slider( this.model.toJSON() ); 134 this.model.on( 'change', function( model, options ) { 135 // Apply changes to slider here. 136 }, this ); 695 137 }, 696 138 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 } 139 start: function() { 712 140 713 Diff.revisionView.draggingLeft = false;714 715 revisions.model.settings.revision_id = ''; // reset passed revision id so switching back to one handle mode doesn't re-select revision716 Diff.reloadLeftRight(); // load diffs for left and right handles717 Diff.revisionView.model = Diff.rightHandleRevisions;718 719 } else { // compare one mode720 Diff.singleRevision = true;721 Diff.revisionView.draggingLeft = false;722 Diff.reloadModelSingle();723 }724 Diff.revisionsInteractions.render();725 Diff.tickmarkView.render();726 141 }, 727 142 728 restore: function() { 729 document.location = $( '#restore-revision' ).data( 'restoreLink' ); 730 } 731 }); 732 733 734 /** 735 * ======================================================================== 736 * MODELS 737 * ======================================================================== 738 */ 739 740 /** 741 * wp.revisions.Revision 742 */ 743 Revision = revisions.model.Revision = Backbone.Model.extend({ 744 idAttribute: 'ID', 143 slide: function() { 745 144 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: false759 145 }, 760 146 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 } 147 stop: function() { 774 148 775 149 } 776 150 }); 777 151 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 } ); 152 // The diff view. 153 // This is the view for the current active diff. 154 revisions.view.Diff = wp.Backbone.View.extend({ 155 tagName: 'div', 156 className: 'revisions-diff', 157 template: wp.template('revisions-diff') 158 }); 818 159 819 $( wp.revisions ); 160 // Initialize the revisions UI. 161 revisions.init = function() { 162 revisions.model.revisions = new revisions.model.Revisions( revisions.settings.revisionData ); 163 revisions.model.diffs = new revisions.model.Diffs(); 164 new revisions.view.Frame().render(); 165 }; 820 166 167 $( revisions.init ); 821 168 }(jQuery)); -
wp-admin/revision.php
8 8 9 9 /** WordPress Administration Bootstrap */ 10 10 require_once('./admin.php'); 11 12 require ABSPATH . 'wp-admin/includes/revision.php'; 13 14 // wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) 15 // wp_prepare_revisions_for_js( $post ) 16 11 17 wp_reset_vars( array( 'revision', 'action' ) ); 12 18 13 19 $revision_id = absint( $revision ); … … else 77 83 $parent_file = $submenu_file = 'edit.php'; 78 84 79 85 wp_enqueue_script( 'revisions' ); 80 81 82 $settings = array( 83 'post_id' => $post->ID, 84 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ), 85 'revision_id' => $revision_id 86 ); 87 88 wp_localize_script( 'revisions', 'wpRevisionsSettings', $settings ); 86 wp_localize_script( 'revisions', '_wpRevisionsSettings', wp_prepare_revisions_for_js( $post ) ); 89 87 90 88 /* Revisions Help Tab */ 91 89 … … require_once( './admin-header.php' ); 114 112 115 113 <div class="wrap"> 116 114 <?php screen_icon(); ?> 117 < div id="revision-diff-container" class="current-version right-model-loading">118 <h2 class="long-header"><?php echo $h2; ?></h2>115 <h2 class="long-header"><?php echo $h2; ?></h2> 116 </div> 119 117 120 <div id="loading-status" class="updated message"> 121 <p><span class="spinner" ></span></p> 122 </div> 118 <script id="tmpl-revisions-frame" type="text/html"> 119 <span class="spinner"></span> 120 <div class="revisions-control-frame"></div> 121 <div class="revisions-diff-frame"></div> 122 </script> 123 123 124 <div class="diff-slider-ticks-wrapper"> 125 <div id="diff-slider-ticks"></div> 126 </div> 124 <script id="tmpl-revisions-controls" type="text/html"> 125 <div class="revision-toggle-compare-mode"> 126 <label> 127 <input type="checkbox" class="compare-two-revisions" /> 128 <?php esc_attr_e( 'Compare two revisions' ); ?> 129 </label> 130 </div> 127 131 128 <div id="revision-interact"></div> 132 <div class="revisions-previous"> 133 <input class="button" type="button" id="previous" value="<?php echo esc_attr_x( 'Previous', 'Button label for a previous revision' ); ?>" /> 134 </div> 129 135 130 <div id="revisions-diff"></div> 136 <div class="revisions-next"> 137 <input class="button" type="button" id="next" value="<?php echo esc_attr_x( 'Next', 'Button label for a next revision' ); ?>" /> 131 138 </div> 132 </div> 139 140 <div class="revisions-slider"></div> 141 </script> 133 142 134 143 <script id="tmpl-revisions-diff" type="text/html"> 144 DIFF 145 </script> 146 147 <script id="tmpl-revisions-diff-old" type="text/html"> 135 148 <div id="toggle-revision-compare-mode"> 136 149 <label> 137 150 <input type="checkbox" id="compare-two-revisions" /> … … require_once( './admin-header.php' ); 157 170 </div> 158 171 </div> 159 172 160 </div>161 162 173 <div id="diff-table">{{{ data.diff }}}</div> 163 174 </script> 164 175 -
wp-includes/revision.php
function _wp_upgrade_revisions_of_post( $post, $revisions ) { 681 681 682 682 return true; 683 683 } 684 685 /**686 * Displays a human readable HTML representation of the difference between two strings.687 * similar to wp_text_diff, but tracks and returns could of lines added and removed688 *689 * @since 3.6.0690 *691 * @see wp_parse_args() Used to change defaults to user defined settings.692 * @uses Text_Diff693 * @uses WP_Text_Diff_Renderer_Table694 *695 * @param string $left_string "old" (left) version of string696 * @param string $right_string "new" (right) version of string697 * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults.698 * @return array contains html, linesadded & linesdeletd, empty string if strings are equivalent.699 */700 function wp_text_diff_with_count( $left_string, $right_string, $args = null ) {701 $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );702 $args = wp_parse_args( $args, $defaults );703 704 if ( ! class_exists( 'WP_Text_Diff_Renderer_Table' ) )705 require( ABSPATH . WPINC . '/wp-diff.php' );706 707 $left_string = normalize_whitespace( $left_string );708 $right_string = normalize_whitespace( $right_string );709 710 $left_lines = explode( "\n", $left_string );711 $right_lines = explode( "\n", $right_string) ;712 713 $text_diff = new Text_Diff($left_lines, $right_lines );714 $lines_added = $text_diff->countAddedLines();715 $lines_deleted = $text_diff->countDeletedLines();716 717 $renderer = new WP_Text_Diff_Renderer_Table();718 $diff = $renderer->render( $text_diff );719 720 if ( !$diff )721 return '';722 723 $r = "<table class='diff'>\n";724 725 if ( ! empty( $args[ 'show_split_view' ] ) ) {726 $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";727 } else {728 $r .= "<col class='content' />";729 }730 731 if ( $args['title'] || $args['title_left'] || $args['title_right'] )732 $r .= "<thead>";733 if ( $args['title'] )734 $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";735 if ( $args['title_left'] || $args['title_right'] ) {736 $r .= "<tr class='diff-sub-title'>\n";737 $r .= "\t<td></td><th>$args[title_left]</th>\n";738 $r .= "\t<td></td><th>$args[title_right]</th>\n";739 $r .= "</tr>\n";740 }741 if ( $args['title'] || $args['title_left'] || $args['title_right'] )742 $r .= "</thead>\n";743 744 $r .= "<tbody>\n$diff\n</tbody>\n";745 $r .= "</table>";746 747 return array( 'html' => $r, 'lines_added' => $lines_added, 'lines_deleted' => $lines_deleted );748 }