Make WordPress Core

Changeset 23898


Ignore:
Timestamp:
04/04/2013 07:53:49 AM (12 years ago)
Author:
markjaquith
Message:

Further cleanup of revisions code. Probably not the last.

see #23901. props adamsilverstein, azaozz, ocean90.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/includes/ajax-actions.php

    r23890 r23898  
    20932093    check_ajax_referer( 'revisions-ajax-nonce', 'nonce' );
    20942094
    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;
    2102 
    2103     $compare_two_mode = ( '' == $post_id ) ? false : true;
     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;
     2103
    21042104    //
    21052105    //TODO: currently code returns all possible comparisons for the indicated 'compare_to' revision
     
    21072107    //so only the possible diffs need be generated
    21082108    //
    2109     $alltherevisions = array();
    2110     if ( '' == $post_id )
     2109    $all_the_revisions = array();
     2110    if ( ! $post_id )
    21112111        $post_id = $compare_to;
    21122112
     
    21172117        return;
    21182118
    2119     /* translators: revision date format, see http://php.net/date */
    2120     $datef = _x( 'j F, Y @ G:i:s', 'revision date format');
    2121 
    21222119    $left_revision = get_post( $compare_to );
    21232120
    21242121    //single model fetch mode
    21252122    //return the diff of a single revision comparison
    2126     if ( 0 != $single_revision_id ) {
     2123    if ( $single_revision_id ) {
    21272124        $right_revision = get_post( $single_revision_id );
    21282125
    2129     if ( 0 == $compare_to )
     2126        if ( ! $compare_to )
    21302127            $left_revision = get_post( $post_id );
    21312128
    2132     // make sure the right revision is the most recent
    2133     if ( $compare_two_mode && $right_revision->ID < $left_revision->ID ) {
    2134         $temp = $left_revision;
    2135         $left_revision = $right_revision;
    2136         $right_revision = $temp;
    2137     }
    2138 
    2139         $linesadded=0;
    2140         $linesdeleted=0;
    2141 
    2142         //
     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        }
     2135
     2136        $lines_added = $lines_deleted = 0;
     2137        $content = '';
    21432138        //compare from left to right, passed from application
    2144         //
    2145         $content='';
    21462139        foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
    21472140            $left_content = apply_filters( "_wp_post_revision_field_$field", $left_revision->$field, $field, $left_revision, 'left' );
     
    21522145            $args = array();
    21532146
    2154             if ( ! empty( $show_split_view ) )
     2147            if ( $show_split_view )
    21552148                 $args = array( 'show_split_view' => true );
    21562149
    21572150            // 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 );
    21592152
    21602153            if ( isset( $diff[ 'html' ] ) )
    21612154                $content .= $diff[ 'html' ];
    21622155
    2163             if ( isset( $diff[ 'linesadded' ] ) )
    2164                 $linesadded = $linesadded + $diff[ 'linesadded' ];
    2165 
    2166             if ( isset( $diff[ 'linesdeleted' ] ) )
    2167                 $linesdeleted = $linesdeleted + $diff[ 'linesdeleted' ];
    2168 
    2169 
     2156            if ( isset( $diff[ 'lines_added' ] ) )
     2157                $lines_added = $lines_added + $diff[ 'lines_added' ];
     2158
     2159            if ( isset( $diff[ 'lines_deleted' ] ) )
     2160                $lines_deleted = $lines_deleted + $diff[ 'lines_deleted' ];
    21702161        }
    21712162        $content = '' == $content ? __( 'No difference' ) : $content;
    21722163
    2173         $alltherevisions = array (
    2174             'revisiondiff' => $content,
    2175             'lines_deleted' => $linesdeleted,
    2176             'lines_added' => $linesadded
     2164        $all_the_revisions = array (
     2165            'diff'          => $content,
     2166            'lines_deleted' => $lines_deleted,
     2167            'lines_added'   => $lines_added
    21772168        );
    2178         echo json_encode( $alltherevisions );
     2169
     2170        echo json_encode( $all_the_revisions );
    21792171        exit();
    21802172    } //end single model fetch
     
    21872179    $previous_revision_id = 0;
    21882180
     2181    /* translators: revision date format, see http://php.net/date */
     2182    $datef = _x( 'j F, Y @ G:i:s', 'revision date format');
     2183
    21892184    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;
    21932187
    21942188        $revision_from_date_author = '';
     
    21962190        // return blank data for diffs to the left of the left handle (for right handel model)
    21972191        // 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             $alltherevisions[] = 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 (
    22012195                'ID' => $revision->ID,
    22022196            );
     
    22312225        );
    22322226
    2233         $autosavef = __( '%1$s [Autosave]' );
    2234         $currentf  = __( '%1$s [Current Revision]' );
    2235 
    2236         if ( ! $post = get_post( $post_id))
    2237             exit();
     2227        $autosavef = _x( '%1$s [Autosave]', 'post revision title extra' );
     2228        $currentf  = _x( '%1$s [Current Revision]', 'post revision title extra' );
     2229
     2230        if ( ! $post = get_post( $post_id ) )
     2231            continue;
    22382232
    22392233        if ( $left_revision->post_modified === $post->post_modified )
     
    22472241            $revision_date_author = sprintf( $autosavef, $revision_date_author );
    22482242
    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');
    22502245        $date_short = date_i18n( $date_short_format, strtotime( $revision->post_modified ) );
    22512246
     
    22572252        );
    22582253
    2259         $restoreaction = wp_nonce_url(
     2254        $restore_link = wp_nonce_url(
    22602255            add_query_arg(
    22612256                array( 'revision' => $revision->ID,
     
    22652260            "restore-post_{$revision->ID}"
    22662261        );
     2262
    22672263        // if this is a left handled calculation swap data
    22682264        if ( 0 != $right_handle_at ) {
     
    22712267            $revision_date_author = $tmp;
    22722268        }
     2269
    22732270        if ( ( $compare_two_mode || -1 !== $previous_revision_id ) ) {
    2274             $alltherevisions[] = 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                 'restoreaction' => 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,
    22812278                'previous_revision_id' => $previous_revision_id
    22822279            );
     
    22862283    endforeach;
    22872284
    2288     echo json_encode( $alltherevisions );
     2285    echo json_encode( $all_the_revisions );
    22892286    exit();
    22902287}
  • trunk/wp-admin/js/revisions.js

    r23872 r23898  
    22
    33(function($) {
    4     wp.revisions = {
    5 
    6         views: {},
    7 
    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             },
    25 
    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                 }
    36 
    37             }
    38 
    39         }),
    40 
    41         app: _.extend({}, Backbone.Events),
    42 
    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
    57 
    58             routes: {
    59             },
    60 
    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;
    69                     }
    70 
    71                 });
    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' );
    81 
    82                                     // stop spinner when all models are loaded
    83                                     if ( 0 === model_collection.where( { revision_toload: true } ).length )
    84                                         self.stopModelLoadingSpinner();
    85 
    86                                     self._tickmarkView.render();
    87 
    88                                     var total_changes = model.get( 'lines_added' ) + model.get( 'lines_deleted'),
    89                                         scope_of_changes = 'vsmall';
    90 
    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                                     }
    108 
    109                                 }
    110                         } );
    111                         }, delay ) ;
    112                         delay = delay + 150; // stagger model loads to avoid hammering server with requests
    113                     }
    114                 );
    115             },
    116 
    117             startLeftModelLoading: function() {
    118                 this._leftModelLoading = true;
    119                 $('.revisiondiffcontainer').addClass('leftmodelloading');
    120             },
    121 
    122             stopLeftModelLoading: function() {
    123                 this._leftModelLoading = false;
    124             },
    125 
    126             startRightModelLoading: function() {
    127                 this._rightModelLoading = true;
    128                 $('.revisiondiffcontainer').addClass('rightmodelloading');
    129             },
    130 
    131             stopRightModelLoading: function() {
    132                 this._rightModelLoading = false;
    133             },
    134 
    135             stopModelLoadingSpinner: function() {
    136                 $('.revisiondiffcontainer').removeClass('rightmodelloading');
    137                 $('.revisiondiffcontainer').removeClass('leftmodelloading');
    138             },
    139 
    140             reloadModel: function() {
    141                 if ( 2 === this._compareOneOrTwo ) {
    142                     this.reloadLeftRight();
    143                 } else {
    144                     this.reloadModelSingle();
    145                 }
    146             },
    147 
    148             // load the models for the single handle mode
    149             reloadModelSingle: function() {
     4    var Revision, Revisions, Diff, l10n, revisions;
     5
     6    revisions = wp.revisions = function() {
     7        Diff = revisions.Diff = new Diff();
     8    };
     9
     10    _.extend( revisions, { model: {}, view: {}, controller: {} } );
     11
     12    // Link any localized strings.
     13    l10n = revisions.model.l10n = typeof wpRevisionsL10n === 'undefined' ? {} : wpRevisionsL10n;
     14
     15    // Link any settings.
     16    revisions.model.settings = l10n.settings || {};
     17    delete l10n.settings;
     18
     19
     20    /**
     21     * ========================================================================
     22     * CONTROLLERS
     23     * ========================================================================
     24     */
     25
     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
     45
     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();
     51
    15052                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
     53                this.revisions.fetch({ // load revision data
    15754                    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' );
    169 
    170                     },
    171 
    172                     error: function() {
    17355                        self.stopRightModelLoading();
    174                     }
    175 
    176                 });
    177             },
    178 
    179             // load the models for the left handle
    180             reloadLeft: function() {
    181                 var self = this;
    182                 self.startLeftModelLoading();
    183                 self._leftHandleRevisions = new wp.revisions.Collection();
    184 
    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 );
    193 
    194                 self._leftHandleRevisions.fetch({
    195 
    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                         },
    206 
    207                     error: function() {
    208                         self.stopLeftModelLoading();
     56                        self.completeApplicationSetup();
    20957                    }
    21058                });
    211             },
    212 
    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();
    218 
    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;
    226 
    227                 self._rightHandleRevisions.fetch({
    228 
    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' );
    235 
    236                         // REVAPP._revisionView.render();
    237 
     59            }
     60        },
     61
     62        reloadToLoadRevisions: function( models, reverse_direction ) {
     63            var self = this,
     64                revisionsToLoad = models.where( { revision_toload: true } ),
     65                delay = 0;
     66
     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            });
     72
     73            _.each( revisionsToLoad, function( revision ) {
     74                    _.delay( function() {
     75                        revision.fetch( {
     76                            update: true,
     77                            add: false,
     78                            remove: false,
     79                            success: function( model ) {
     80                                model.set( 'revision_toload', 'false' );
     81
     82                                // stop spinner when all models are loaded
     83                                if ( 0 === models.where( { revision_toload: true } ).length )
     84                                    self.stopModelLoadingSpinner();
     85
     86                                self.tickmarkView.render();
     87
     88                                var total_changes = model.get( 'lines_added' ) + model.get( 'lines_deleted'),
     89                                    scope_of_changes = 'vsmall';
     90
     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                                }
     108
     109                            }
     110                    } );
     111                    }, delay ) ;
     112                    delay = delay + 150; // stagger model loads to avoid hammering server with requests
     113                }
     114            );
     115        },
     116
     117        startLeftModelLoading: function() {
     118            this.leftModelLoading = true;
     119            $('.revisiondiffcontainer').addClass('leftmodelloading');
     120        },
     121
     122        stopLeftModelLoading: function() {
     123            this.leftModelLoading = false;
     124        },
     125
     126        startRightModelLoading: function() {
     127            this.rightModelLoading = true;
     128            $('.revisiondiffcontainer').addClass('rightmodelloading');
     129        },
     130
     131        stopRightModelLoading: function() {
     132            this.rightModelLoading = false;
     133        },
     134
     135        stopModelLoadingSpinner: function() {
     136            $('.revisiondiffcontainer').removeClass('rightmodelloading');
     137            $('.revisiondiffcontainer').removeClass('leftmodelloading');
     138        },
     139
     140        reloadModel: function() {
     141            if ( this.singleRevision ) {
     142                this.reloadModelSingle();
     143            } else {
     144                this.reloadLeftRight();
     145            }
     146        },
     147
     148        // load the models for the single handle mode
     149        reloadModelSingle: function() {
     150            var self = this;
     151
     152            // TODO: Only updates the query args yet
     153            self.revisions.reload({
     154                'showAutosaves': self.autosaves,
     155                'showSplitView': self.showSplitView
     156            });
     157
     158            self.startRightModelLoading();
     159            self.revisions.fetch({ // reload revision data
     160                success: function() {
     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                    self.slider.refresh({
     168                        'max': revisionCount - 1,
     169                        'value': self.rightDiff - 1
     170                    }, true);
     171                },
     172
     173                error: function() {
     174                    self.stopRightModelLoading();
     175                }
     176
     177            });
     178        },
     179
     180        // load the models for the left handle
     181        reloadLeft: function() {
     182            var self = this;
     183            self.startLeftModelLoading();
     184            self.leftHandleRevisions = new Revisions( {}, {
     185                'compareTo': self.revisions.at( self.rightDiff - 1 ).get( 'ID' ),
     186                'showAutosaves': self.autosaves,
     187                'showSplitView': self.showSplitView,
     188                'rightHandleAt': self.rightDiff
     189            });
     190
     191            self.leftHandleRevisions.fetch({
     192                success: function(){
     193                    self.stopLeftModelLoading();
     194                    self.reloadToLoadRevisions( self.leftHandleRevisions );
     195                    self.tickmarkView.model = self.leftHandleRevisions;
     196                    self.slider.refresh({
     197                        'max': self.revisions.length
     198                    });
     199                    // ensure right handle not beyond length, in particular if viewing autosaves is switched from on to off
     200                    // the number of models in the collection might get shorter, this ensures right handle is not beyond last model
     201                    if ( self.rightDiff > self.revisions.length )
     202                        self.rightDiff = self.revisions.length;
    238203                    },
    239204
    240                     error: function( response ) {
    241                         self.stopRightModelLoading();
     205                error: function() {
     206                    self.stopLeftModelLoading();
     207                }
     208            });
     209        },
     210
     211        // load the models for the right handle
     212        reloadRight: function() {
     213            var self = this;
     214            self.startRightModelLoading();
     215            self.rightHandleRevisions = new Revisions( {}, {
     216                'compareTo': self.revisions.at( self.leftDiff ).get( 'ID' ) - 1,
     217                'showAutosaves': self.autosaves,
     218                'showSplitView': self.showSplitView,
     219                'leftHandleAt': self.leftDiff
     220            });
     221
     222            self.rightHandleRevisions.fetch({
     223                success: function(){
     224                    self.stopRightModelLoading();
     225                    self.reloadToLoadRevisions( self.rightHandleRevisions );
     226                    self.tickmarkView.model = self.rightHandleRevisions;
     227                    self.slider.refresh({
     228                        'max': self.revisions.length,
     229                        'values': [ self.leftDiff, self.rightDiff]
     230                    }, true);
     231                },
     232
     233                error: function( response ) {
     234                    self.stopRightModelLoading();
     235                }
     236            });
     237
     238        },
     239
     240        reloadLeftRight: function() {
     241            this.startRightModelLoading();
     242            this.startLeftModelLoading();
     243            this.reloadLeft();
     244            this.reloadRight();
     245        },
     246
     247        completeApplicationSetup: function() {
     248            this.revisionView = new revisions.view.Diff({
     249                model: this.revisions
     250            });
     251            this.revisionView.render();
     252
     253            this.reloadToLoadRevisions( this.revisions );
     254
     255            this.revisionsInteractions = new revisions.view.Interact({
     256                model: this.revisions
     257            });
     258            this.revisionsInteractions.render();
     259
     260            this.tickmarkView = new revisions.view.Tickmarks({
     261                model: this.revisions
     262            });
     263            this.tickmarkView.render();
     264            this.tickmarkView.resetTicks();
     265
     266        }
     267    });
     268
     269
     270    /**
     271     * ========================================================================
     272     * VIEWS
     273     * ========================================================================
     274     */
     275
     276    /**
     277     * wp.revisions.view.Slider
     278     *
     279     * The slider
     280     */
     281    revisions.view.Slider = Backbone.View.extend({
     282        el: $( '#slider' ),
     283        singleRevision: true,
     284
     285        initialize: function( options ) {
     286            this.options = _.defaults( options || {}, {
     287                value: 0,
     288                min: 0,
     289                max: 1,
     290                step: 1
     291            });
     292        },
     293
     294        slide: function( event, ui ) {
     295            if ( this.singleRevision ) {
     296                Diff.rightDiff = ( ui.value + 1 );
     297                Diff.revisionView.render();
     298            } else {
     299                if ( ui.values[0] === ui.values[1] ) // prevent compare to self
     300                    return false;
     301
     302                if ( $( ui.handle ).hasClass( 'left-handle' ) ) {
     303                    // Left handler
     304                    if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle
     305                        return false;
     306
     307                    Diff.leftDiff = ui.values[0];
     308                } else {
     309                    // Right handler
     310                    if ( Diff.rightModelLoading ) // right model still loading, prevent sliding right handle
     311                        return false;
     312
     313                    Diff.rightDiff = ui.values[1];
     314                }
     315
     316                if ( 0 === Diff.leftDiff ) {
     317                    $( '.revisiondiffcontainer' ).addClass( 'currentversion' );
     318                } else {
     319                    $( '.revisiondiffcontainer' ).removeClass( 'currentversion' );
     320                }
     321
     322                Diff.revisionView.render();
     323            }
     324        },
     325
     326        start: function( event, ui ) {
     327            // Not needed in one mode
     328            if ( this.singleRevision )
     329                return;
     330
     331            if ( $( ui.handle ).hasClass( 'left-handle' ) ) {
     332                // Left handler
     333                if ( Diff.leftModelLoading ) // left model still loading, prevent sliding left handle
     334                    return false;
     335
     336                Diff.revisionView.draggingLeft = true;
     337
     338                if ( Diff.revisionView.model !== Diff.leftHandleRevisions &&
     339                        null !== Diff.leftHandleRevisions ) {
     340                    Diff.revisionView.model = Diff.leftHandleRevisions;
     341                    Diff.tickmarkView.model = Diff.leftHandleRevisions;
     342                    Diff.tickmarkView.render();
     343                }
     344
     345                Diff.leftDiffStart = ui.values[ 0 ];
     346
     347            } else {
     348                // Right handler
     349                if ( Diff.rightModelLoading || 0 === Diff.rightHandleRevisions.length) // right model still loading, prevent sliding right handle
     350                    return false;
     351
     352                if ( Diff.revisionView.model !== Diff.rightHandleRevisions &&
     353                        null !== Diff.rightHandleRevisions ) {
     354                    Diff.revisionView.model = Diff.rightHandleRevisions;
     355                    Diff.tickmarkView.model = Diff.rightHandleRevisions;
     356                    Diff.tickmarkView.render();
     357                }
     358
     359                Diff.revisionView.draggingLeft = false;
     360                Diff.rightDiffStart = ui.values[1];
     361            }
     362        },
     363
     364        stop: function( event, ui ) {
     365            // Not needed in one mode
     366            if ( this.singleRevision )
     367                return;
     368
     369            // calculate and generate a diff for comparing to the left handle
     370            // and the right handle, swap out when dragging
     371            if ( $( ui.handle ).hasClass( 'left-handle' ) ) {
     372                // Left hadnler
     373                if ( Diff.leftDiffStart !== ui.values[0] )
     374                    Diff.reloadRight();
     375            } else {
     376                // Right handler
     377                if ( Diff.rightDiffStart !== ui.values[1] )
     378                    Diff.reloadLeft();
     379            }
     380        },
     381
     382        addTooltip: function( handle, message ) {
     383
     384            handle.attr( 'title', '' ).tooltip({
     385                track: false,
     386
     387                position: {
     388                    my: "left-30 top-66",
     389                    at: "top left",
     390                    using: function( position, feedback ) {
     391                        $( this ).css( position );
     392                        $( "<div>" )
     393                        .addClass( "arrow" )
     394                        .addClass( feedback.vertical )
     395                        .addClass( feedback.horizontal )
     396                        .appendTo( $( this ) );
    242397                    }
     398                },
     399                show: false,
     400                hide: false,
     401                content:  function() {
     402                    return message;
     403                }
     404
     405            } );
     406        },
     407
     408        width: function() {
     409            return $( '#slider' ).width();
     410        },
     411
     412        setWidth: function( width ) {
     413            return $( '#slider' ).width( width );
     414        },
     415
     416        refresh: function( options, slide ) {
     417            $( '#slider' ).slider( 'option', options );
     418
     419            // Triggers the slide event
     420            if ( slide )
     421                $( '#slider' ).trigger( 'slide' );
     422        },
     423
     424        option: function( key ) {
     425            return $( '#slider' ).slider( 'option', key );
     426        },
     427
     428        render: function() {
     429            var self = this;
     430            // this.$el doesn't work, why?
     431            $( '#slider' ).slider( {
     432                slide: $.proxy( self.slide, self ),
     433                start: $.proxy( self.start, self ),
     434                stop: $.proxy( self.stop, self )
     435            } );
     436
     437            // Set options
     438            this.refresh( this.options );
     439        }
     440    });
     441
     442    /**
     443     * wp.revisions.view.Tickmarks
     444     *
     445     * The slider tickmarks.
     446     */
     447    revisions.view.Tickmarks = Backbone.View.extend({
     448        el: $('#diff-slider-ticks'),
     449        template: wp.template('revision-ticks'),
     450        model: Revision,
     451
     452        resetTicks: function() {
     453            var sliderMax = Diff.slider.option( 'max' );
     454            var sliderWidth = Diff.slider.width();
     455            var adjustMax = Diff.singleRevision ? 0 : 1;
     456            var tickWidth = Math.floor( sliderWidth / ( sliderMax - adjustMax ) );
     457
     458            // TODO: adjust right margins for wider ticks so they stay centered on handle stop point
     459
     460            // set minimum and maximum widths for tick marks
     461            tickWidth = (tickWidth > 50 ) ? 50 : tickWidth;
     462            tickWidth = (tickWidth < 10 ) ? 10 : tickWidth;
     463
     464            sliderWidth = tickWidth * (sliderMax - adjustMax ) + 1;
     465
     466            Diff.slider.setWidth( sliderWidth );
     467            $( '.diff-slider-ticks-wrapper' ).width( sliderWidth );
     468            $( '#diffslider' ).width( sliderWidth );
     469            $( '#diff-slider-ticks' ).width( sliderWidth );
     470
     471            var aTickWidth = $( '.revision-tick' ).width();
     472
     473            if ( tickWidth !== aTickWidth ) { // is the width already set correctly?
     474                $( '.revision-tick' ).each( function( ) {
     475                    $(this).css( 'margin-right', tickWidth - 1 + 'px'); // space the ticks out using right margin
    243476                });
    244477
    245             },
    246 
    247             reloadLeftRight: function() {
    248                 this.startRightModelLoading();
    249                 this.startLeftModelLoading();
    250                 this.reloadLeft();
    251                 this.reloadRight();
    252             },
    253 
    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
    263 
    264                         success: function() {
    265                             self.stopRightModelLoading();
    266                             // self._rightHandleRevisions = self._revisions;
    267                             self.completeApplicationSetup();
    268                         }
    269                     });
    270                 }
    271                 return this;
    272             },
    273 
    274             addTooltip: function( handle, message ) {
    275 
    276                 handle.attr( 'title', '' ).tooltip({
    277                     track: false,
    278 
    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;
     478                if( ! Diff.singleRevision ) {
     479                    $( '.revision-tick' ).first().remove(); // TODO - remove the check
     480                }
     481                $( '.revision-tick' ).last().css( 'margin-right', '0' ); // last tick gets no right margin
     482            }
     483
     484        },
     485
     486        // render the tickmark view
     487        render: function() {
     488            var self = this;
     489
     490            if ( null !== self.model ) {
     491                var addHtml = "";
     492                _.each ( self.model.models, function( theModel ) {
     493                    addHtml = addHtml + self.template ( theModel.toJSON() );
     494                });
     495                self.$el.html( addHtml );
     496
     497            }
     498            self.resetTicks();
     499            return self;
     500        }
     501    });
     502
     503    /**
     504     * wp.revisions.view.Interact
     505     *
     506     * Next/Prev buttons and the slider
     507     */
     508    // TODO: Change Interact to something else.
     509    revisions.view.Interact = Backbone.View.extend({
     510        el: $('#backbonerevisionsinteract'),
     511        template: wp.template('revision-interact'),
     512
     513        // next and previous buttons, only available in compare one mode
     514        events: {
     515            'click #next':     'nextRevision',
     516            'click #previous': 'previousRevision'
     517        },
     518
     519        render: function() {
     520            var self = this;
     521
     522            var addHtml = this.template;
     523            this.$el.html( addHtml );
     524
     525            var modelcount = Diff.revisions.length;
     526
     527            Diff.slider.singleRevision = Diff.singleRevision;
     528            Diff.slider.render();
     529
     530            if ( Diff.singleRevision ) {
     531                Diff.slider.refresh({
     532                    value: Diff.rightDiff - 1,
     533                    min: 0,
     534                    max: modelcount - 1
     535                });
     536
     537                $( '.revisiondiffcontainer' ).removeClass( 'comparetwo' );
     538
     539            } else {
     540                Diff.slider.refresh({
     541                    values: [ Diff.leftDiff, Diff.rightDiff + 1 ],
     542                    min: 1,
     543                    max: modelcount + 1,
     544                    range: true
     545                });
     546
     547                $( '.revisiondiffcontainer' ).addClass( 'comparetwo' );
     548                $( '#diffslider a.ui-slider-handle' ).first().addClass( 'left-handle' );
     549                $( '#diffslider a.ui-slider-handle' ).last().addClass( 'right-handle' );
     550
     551            }
     552
     553            return this;
     554        },
     555
     556        // go to the next revision
     557        nextRevision: function() {
     558            if ( Diff.rightDiff < this.model.length ) // unless at right boundry
     559                Diff.rightDiff = Diff.rightDiff + 1 ;
     560
     561            Diff.revisionView.render();
     562
     563            Diff.slider.refresh({
     564                value: Diff.rightDiff - 1
     565            }, true );
     566        },
     567
     568        // go the the previous revision
     569        previousRevision: function() {
     570            if ( Diff.rightDiff > 1 ) // unless at left boundry
     571                Diff.rightDiff = Diff.rightDiff - 1 ;
     572
     573            Diff.revisionView.render();
     574
     575            Diff.slider.refresh({
     576                value: Diff.rightDiff - 1
     577            }, true );
     578        }
     579    });
     580
     581    /**
     582     * wp.revisions.view.Diff
     583     *
     584     * Next/Prev buttons and the slider
     585     */
     586    revisions.view.Diff = Backbone.View.extend({
     587        el: $('#backbonerevisionsdiff'),
     588        template: wp.template('revision'),
     589        draggingLeft: false,
     590
     591        // the compare two button is in this view, add the interaction here
     592        events: {
     593            'click #comparetwo': 'compareTwo',
     594            'click #restore':    'restore'
     595        },
     596
     597        // render the revisions
     598        render: function() {
     599            var addHtml = '';
     600            var thediff;
     601
     602            // compare two revisions mode?
     603            if ( ! Diff.singleRevision ) {
     604                if ( this.draggingLeft ) {
     605                    thediff = Diff.leftDiff - 1;
     606                    if ( this.model.at( thediff ) ) {
     607                        addHtml = this.template( this.model.at( thediff ).toJSON() );
    295608                    }
    296 
    297                 } );
    298             },
    299 /**/
    300 
    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 );
    307 
    308                 this.reloadToLoadRevisions( this._revisions );
    309 
    310                 this._revisionsInteractions = new wp.revisions.views.Interact({
    311                     model: this._revisions
    312                 });
    313                 this._revisionsInteractions.render();
    314 
    315                 this._tickmarkView = new wp.revisions.views.Tickmarks({
    316                     model: this._revisions
    317                 });
    318                 this._tickmarkView.render();
    319                 this._tickmarkView.resetTicks();
    320 
    321 
    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                 */
    340 
    341             }
    342         })
    343     };
    344 
    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,
    349 
    350         initialize: function() {
    351             }
     609                } else { // dragging right handle
     610                    thediff = Diff.rightDiff -1;
     611                    if ( this.model.at( thediff ) ) {
     612                        addHtml = this.template( this.model.at( thediff ).toJSON() );
     613                    }
     614                }
     615            } else { // end compare two revisions mode, eg only one slider handle
     616                this.comparetwochecked = '';
     617                if ( this.model.at( Diff.rightDiff - 1 ) ) {
     618                    addHtml = this.template( this.model.at( Diff.rightDiff - 1 ).toJSON() );
     619                }
     620            }
     621            this.$el.html( addHtml );
     622
     623            if ( this.model.length < 2 ) {
     624                $( '#diffslider' ).hide(); // don't allow compare two if fewer than three revisions
     625                $( '.diff-slider-ticks-wrapper' ).hide();
     626            }
     627
     628            // add tooltips to the handles
     629            if ( ! Diff.singleRevision ) {
     630                Diff.slider.addTooltip ( $( 'a.ui-slider-handle.left-handle' ),
     631                    ( Diff.leftDiff < 0 ) ? '' : Diff.revisions.at( Diff.leftDiff - 1 ).get( 'titleTooltip' ) );
     632                Diff.slider.addTooltip ( $( 'a.ui-slider-handle.right-handle' ),
     633                    ( Diff.rightDiff > Diff.revisions.length ) ? '' : Diff.revisions.at( Diff.rightDiff - 1 ).get( 'titleTooltip' ) );
     634            } else {
     635                Diff.slider.addTooltip ( $( 'a.ui-slider-handle' ),
     636                    ( Diff.rightDiff > Diff.revisions.length ) ? '' : Diff.revisions.at( Diff.rightDiff - 1 ).get( 'titleTooltip' ) );
     637            }
     638
     639            this.toogleCompareTwoCheckbox();
     640
     641            // hide the restore button when on the last sport/current post data
     642            if ( Diff.rightDiff === Diff.revisions.length ){
     643                $( '#restore' ).hide();
     644            } else {
     645                $( '#restore' ).show();
     646            }
     647
     648            return this;
     649        },
     650
     651        toogleCompareTwoCheckbox: function() {
     652            // don't allow compare two if fewer than three revisions
     653            if ( this.model.length < 3 )
     654                $( '#comparetworevisions' ).hide();
     655
     656            $( '#comparetwo' ).prop( 'checked', ! Diff.singleRevision );
     657        },
     658
     659        // turn on/off the compare two mode
     660        compareTwo: function() {
     661            if ( $( 'input#comparetwo' ).is( ':checked' ) ) { // compare 2 mode
     662                Diff.singleRevision = false ;
     663
     664                if ( 1 === Diff.rightDiff )
     665                    Diff.rightDiff = 2;
     666
     667                Diff.revisionView.draggingLeft = false;
     668
     669                revisions.model.settings.revision_id = ''; // reset passed revision id so switching back to one handle mode doesn't re-select revision
     670                Diff.reloadLeftRight();
     671                Diff.revisionView.model = Diff.rightHandleRevisions;
     672
     673            } else { // compare one mode
     674                Diff.singleRevision = true;
     675                Diff.revisionView.draggingLeft = false;
     676                Diff.reloadModelSingle();
     677            }
     678            Diff.revisionsInteractions.render();
     679            Diff.tickmarkView.render();
     680        },
     681
     682        restore: function() {
     683            document.location = $( '#restore' ).data( 'restoreLink' );
     684        }
     685    });
     686
     687
     688    /**
     689     * ========================================================================
     690     * MODELS
     691     * ========================================================================
     692     */
     693
     694    /**
     695     * wp.revisions.Revision
     696     */
     697    Revision = revisions.model.Revision = Backbone.Model.extend({
     698        idAttribute: 'ID',
     699        urlRoot: ajaxurl +  '?action=revisions-data' +
     700            '&show_autosaves=true&show_split_view=true&nonce=' + revisions.model.settings.nonce,
     701        defaults: {
     702            ID: 0,
     703            titleTo: '',
     704            titleTooltip: '',
     705            titleFrom: '',
     706            diff: '<div class="diff-loading"><div class="spinner"></div></div>',
     707            restoreLink: '',
     708            revision_toload: false,
     709            lines_added: 0,
     710            lines_deleted: 0,
     711            scope_of_changes: 'none',
     712            previous_revision_id: 0
     713        },
     714
     715        url: function() {
     716            if ( Diff.singleRevision ) {
     717                return this.urlRoot +
     718                    '&single_revision_id=' + this.id +
     719                    '&compare_to=' + this.get( 'previous_revision_id' ) +
     720                    '&post_id=' + revisions.model.settings.post_id;
     721            } else {
     722                return this.collection.url() + '&single_revision_id=' + this.id;
     723            }
     724
     725        }
     726    });
     727
     728    /**
     729     * wp.revisions.Revisions
     730     */
     731    Revisions = revisions.Revisions = Backbone.Collection.extend({
     732        model: Revision,
     733        urlRoot: ajaxurl + '?action=revisions-data',
     734
     735        initialize: function( models, options ) {
     736            this.options = _.defaults( options || {}, {
     737                'compareTo': revisions.model.settings.post_id,
     738                'post_id': revisions.model.settings.post_id,
     739                'showAutosaves': true,
     740                'showSplitView': true,
     741                'rightHandleAt': 0,
     742                'leftHandleAt': 0,
     743                'nonce': revisions.model.settings.nonce
     744            });
     745        },
     746
     747        url: function() {
     748            return this.urlRoot +
     749                '&compare_to=' + this.options.compareTo +
     750                '&post_id=' + this.options.post_id +
     751                '&show_autosaves=' + this.options.showAutosaves +
     752                '&show_split_view=' + this.options.showSplitView +
     753                '&right_handle_at=' + this.options.rightHandleAt +
     754                '&left_handle_at=' + this.options.leftHandleAt +
     755                '&nonce=' + this.options.nonce;
     756        },
     757
     758        reload: function( options ) {
     759            this.options = _.defaults( options || {}, this.options );
     760
     761            // TODO
     762            //this.fetch();
     763        }
     764
    352765    } );
    353766
    354     _.extend(wp.revisions.views, {
    355 
    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,
    363 
    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 ) );
    369 
    370                 // TODO: adjust right margins for wider ticks so they stay centered on handle stop point
    371 
    372                 // set minimum and maximum widths for tick marks
    373                 tickWidth = (tickWidth > 50 ) ? 50 : tickWidth;
    374                 tickWidth = (tickWidth < 10 ) ? 10 : tickWidth;
    375 
    376                 sliderWidth = tickWidth * (sliderMax - adjustMax ) + 1;
    377 
    378                 $( '#slider' ).width( sliderWidth );
    379                 $( '.diff-slider-ticks-wrapper' ).width( sliderWidth );
    380                 $( '#diffslider' ).width( sliderWidth );
    381                 $( '#diff-slider-ticks' ).width( sliderWidth );
    382 
    383                 var aTickWidth = $( '.revision-tick' ).width();
    384 
    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                     });
    389 
    390                     if( 2 === REVAPP._compareOneOrTwo ) {
    391                         $( '.revision-tick' ).first().remove(); // TODO - remove the check
    392                     }
    393                     $( '.revision-tick' ).last().css( 'margin-right', '0' ); // last tick gets no right margin
    394                 }
    395 
    396             },
    397 
    398             // render the tickmark view
    399             render: function() {
    400                 var self = this;
    401 
    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 );
    408 
    409                 }
    410                 self.resetTicks();
    411                 return self;
    412             }
    413         }),
    414 
    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,
    423 
    424             // render the revisions
    425             render: function() {
    426                 var addHtml = '';
    427                 var thediff;
    428                 // compare two revisions mode?
    429 
    430                 if ( 2 === REVAPP._compareOneOrTwo ) {
    431 
    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                 }
    467 
    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                 }
    478 
    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                 }
    485 
    486                 return this;
    487             },
    488 
    489             // the compare two button is in this view, add the interaction here
    490             events: {
    491                 'click #comparetwo': 'clickcomparetwo'
    492             },
    493 
    494             // turn on/off the compare two mmode
    495             clickcomparetwo: function(){
    496                 self = this;
    497 
    498                 if ( $( 'input#comparetwo' ).is( ':checked' ) ) { // compare 2 mode
    499                     REVAPP._compareOneOrTwo = 2 ;
    500 
    501                     if ( 1 === REVAPP._rightDiff )
    502                         REVAPP._rightDiff = 2;
    503                         REVAPP._revisionView.draggingLeft = false;
    504 
    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;
    508 
    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 
    520             }
    521         }),
    522 
    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'),
    530 
    531             // render the options view
    532             render: function() {
    533                 var addHtml = this.template;
    534                 this.$el.html( addHtml );
    535                 return this;
    536             },
    537 
    538             // add options interactions
    539             events: {
    540                 'click #toggleshowautosaves': 'toggleshowautosaves',
    541                 'click #showsplitview': 'showsplitview'
    542             },
    543 
    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                 }
    552 
    553                 // refresh the model data
    554                 REVAPP.reloadModel();
    555             },
    556 
    557             // toggle showing the split diff view
    558             showsplitview:  function() {
    559                 var self = this;
    560 
    561                 if ( $( 'input#showsplitview' ).is( ':checked' ) ) {
    562                     REVAPP._showSplitView = 'true';
    563                     $('.revisiondiffcontainer').addClass('diffsplit');
    564                 } else {
    565                     REVAPP._showSplitView = '';
    566                     $('.revisiondiffcontainer').removeClass('diffsplit');
    567                 }
    568 
    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'),
    579 
    580             initialize: function() {
    581             },
    582 
    583             render: function() {
    584                 var self = this;
    585 
    586                 var addHtml = this.template;
    587                 this.$el.html( addHtml );
    588 
    589                 var modelcount = REVAPP._revisions.length;
    590 
    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,
    599 
    600 
    601                         // slide interactions for one handles slider
    602                         slide: function( event, ui ) {
    603 
    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' );
    625 
    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,
    634 
    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;
    642 
    643                                     REVAPP._revisionView.draggingLeft = true;
    644 
    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                                     }
    651 
    652                                     REVAPP._leftDiffStart = ui.values[ 0 ];
    653                                     break;
    654 
    655                                 case 2: // right
    656                                     if ( REVAPP._rightModelLoading || 0 === REVAPP._rightHandleRevisions.length) // right model still loading, prevent sliding right handle
    657                                         return false;
    658 
    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                                     }
    665 
    666                                     REVAPP._revisionView.draggingLeft = false;
    667                                     REVAPP._rightDiffStart = ui.values[1];
    668                                     break;
    669                             }
    670                         },
    671 
    672                         // when sliding in two handled mode change appropriate value
    673                         slide: function( event, ui ) {
    674                             if ( ui.values[0] === ui.values[1] ) // prevent compare to self
    675                                 return false;
    676 
    677                             var index = $( ui.handle ).index(); // 0 (left) or 1 (right)
    678 
    679                             switch ( index ) {
    680                                 case 1: // left
    681                                     if ( REVAPP._leftModelLoading ) // left model still loading, prevent sliding left handle
    682                                         return false;
    683 
    684                                     REVAPP._leftDiff = ui.values[0];
    685                                     break;
    686 
    687                                 case 2: // right
    688                                     if ( REVAPP._rightModelLoading ) // right model still loading, prevent sliding right handle
    689                                         return false;
    690 
    691                                     REVAPP._rightDiff = ui.values[1];
    692                                     break;
    693                             }
    694 
    695                             if ( 0 === REVAPP._leftDiff ) {
    696                                 $( '.revisiondiffcontainer' ).addClass( 'currentversion' );
    697 
    698                             } else {
    699                                 $( '.revisiondiffcontainer' ).removeClass( 'currentversion' );
    700                             }
    701 
    702                             REVAPP._revisionView.render();
    703 
    704                         },
    705 
    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
    711 
    712                                 var index = $( ui.handle ).index(); // 0 (left) or 1 (right)
    713 
    714                                 switch ( index ) {
    715                                     case 1: // left
    716 
    717                                         // left handle dragged & changed, reload right handle model
    718                                         if ( REVAPP._leftDiffStart !== ui.values[0] )
    719                                             REVAPP.reloadRight();
    720 
    721                                         break;
    722 
    723                                     case 2: // right
    724                                         // REVAPP._rightDiff =  ( 1 >= REVAPP._rightDiff ) ? 1 : REVAPP._rightDiff - 1;
    725                                         // right handle dragged & changed, reload left handle model if changed
    726                                         if ( REVAPP._rightDiffStart !== ui.values[1] )
    727                                             REVAPP.reloadLeft();
    728 
    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                 }
    737 
    738                 return this;
    739             },
    740 
    741             // next and previous buttons, only available in compare one mode
    742             events: {
    743                 'click #next': 'nextRevision',
    744                 'click #previous': 'previousRevision'
    745             },
    746 
    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 ;
    751 
    752                 REVAPP._revisionView.render();
    753 
    754                 $( '#slider' ).slider( 'value', REVAPP._rightDiff - 1 ).trigger( 'slide' );
    755             },
    756 
    757             // go the the previous revision
    758             previousRevision: function() {
    759                 if ( REVAPP._rightDiff > 1 ) // unless at left boundry
    760                     REVAPP._rightDiff = REVAPP._rightDiff - 1 ;
    761 
    762                 REVAPP._revisionView.render();
    763 
    764                 $( '#slider' ).slider( 'value', REVAPP._rightDiff - 1 ).trigger( 'slide' );
    765             }
    766         })
    767     });
    768 
    769     // instantiate Revision Application
    770     REVAPP = new wp.revisions.App();
     767    $( wp.revisions );
    771768
    772769}(jQuery));
  • trunk/wp-admin/revision.php

    r23834 r23898  
    8080require_once( './admin-header.php' );
    8181
    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);
     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
     95wp_localize_script( 'revisions', 'wpRevisionsL10n', $strings );
    8896
    8997$comparetworevisionslink = get_edit_post_link( $revision->ID );
     
    113121
    114122<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
    115130    <div id="diffsubheader" class="diff-left-hand-meta-row">
    116131        <div id="diff_from_current_revision">
     
    118133        </div>
    119134        <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 }}}
    121136        </div>
    122137    </div>
     
    124139    <div id="diffsubheader">
    125140        <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 }}}
    127142        </div>
    128143        <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' )?>" />
    130         </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>
     144            <input class="button button-primary" data-restore-link="{{{ data.restoreLink }}}" type="button" id="restore" value="<?php esc_attr_e( 'Restore This Revision' )?>" />
    134145        </div>
    135146    </div>
     
    139150        <div id="added"><?php _e( 'Added +' ); ?></div>
    140151    </div
    141     <div>{{{ data.revisiondiff }}}</div>
     152    <div>{{{ data.diff }}}</div>
    142153</script>
    143154
    144 <script id="tmpl-revisionvinteract" type="text/html">
     155<script id="tmpl-revision-interact" type="text/html">
    145156    <div id="diffheader">
    146157        <div id="diffprevious"><input class="button" type="submit" id="previous" value="<?php esc_attr_e( 'Previous' ); ?>" />
     
    154165    </div>
    155166</script>
     167
    156168<script id="tmpl-revision-ticks" type="text/html">
    157169    <div class="revision-tick revision-toload{{{ data.revision_toload }}} revision-scopeofchanges-{{{ data.scope_of_changes }}}">
     
    159171</script>
    160172<?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 */
    174173require_once( './admin-footer.php' );
  • trunk/wp-includes/revision.php

    r23885 r23898  
    676676    $args = wp_parse_args( $args, $defaults );
    677677
    678     if ( !class_exists( 'WP_Text_Diff_Renderer_Table' ) )
     678    if ( ! class_exists( 'WP_Text_Diff_Renderer_Table' ) )
    679679            require( ABSPATH . WPINC . '/wp-diff.php' );
    680680
     
    686686
    687687    $text_diff = new Text_Diff($left_lines, $right_lines  );
    688     $linesadded = $text_diff->countAddedLines();
    689     $linesdeleted = $text_diff->countDeletedLines();
     688    $lines_added = $text_diff->countAddedLines();
     689    $lines_deleted = $text_diff->countDeletedLines();
    690690
    691691    $renderer  = new WP_Text_Diff_Renderer_Table();
     
    719719    $r .= "</table>";
    720720
    721     return array( 'html' => $r, 'linesadded' => $linesadded, 'linesdeleted' => $linesdeleted );
    722 }
     721    return array( 'html' => $r, 'lines_added' => $lines_added, 'lines_deleted' => $lines_deleted );
     722}
Note: See TracChangeset for help on using the changeset viewer.