Вход Регистрация
Файл: wordpress/wp-admin/js/revisions.js
Строк: 1317
<?php
/* global isRtl */
/**
 * @file Revisions interface functions, Backbone classes and
 * the revisions.php document.ready bootstrap.
 *
 */

window.wp window.wp || {};

(function($) {
    var 
revisions;
    
/**
     * Expose the module in window.wp.revisions.
     */
    
revisions wp.revisions = { model: {}, view: {}, controller: {} };

    
// Link post revisions data served from the back-end.
    
revisions.settings window._wpRevisionsSettings || {};

    
// For debugging
    
revisions.debug false;

    
/**
     * wp.revisions.log
     *
     * A debugging utility for revisions. Works only when a
     * debug flag is on and the browser supports it.
     */
    
revisions.log = function() {
        if ( 
window.console && revisions.debug ) {
            
window.console.log.applywindow.consolearguments );
        }
    };

    
// Handy functions to help with positioning
    
$.fn.allOffsets = function() {
        var 
offset this.offset() || {top0left0}, win = $(window);
        return 
_.extendoffset, {
            
right:  win.width()  - offset.left this.outerWidth(),
            
bottomwin.height() - offset.top  this.outerHeight()
        });
    };

    $.fn.
allPositions = function() {
        var 
position this.position() || {top0left0}, parent this.parent();
        return 
_.extendposition, {
            
right:  parent.outerWidth()  - position.left this.outerWidth(),
            
bottomparent.outerHeight() - position.top  this.outerHeight()
        });
    };

    
/**
     * ========================================================================
     * MODELS
     * ========================================================================
     */
    
revisions.model.Slider Backbone.Model.extend({
        
defaults: {
            
valuenull,
            
valuesnull,
            
min0,
            
max1,
            
step1,
            
rangefalse,
            
compareTwoModefalse
        
},

        
initialize: function( options ) {
            
this.frame options.frame;
            
this.revisions options.revisions;

            
// Listen for changes to the revisions or mode from outside
            
this.listenTothis.frame'update:revisions'this.receiveRevisions );
            
this.listenTothis.frame'change:compareTwoMode'this.updateMode );

            
// Listen for internal changes
            
this.on'change:from'this.handleLocalChanges );
            
this.on'change:to'this.handleLocalChanges );
            
this.on'change:compareTwoMode'this.updateSliderSettings );
            
this.on'update:revisions'this.updateSliderSettings );

            
// Listen for changes to the hovered revision
            
this.on'change:hoveredRevision'this.hoverRevision );

            
this.set({
                
max:   this.revisions.length 1,
                
compareTwoModethis.frame.get('compareTwoMode'),
                
fromthis.frame.get('from'),
                
tothis.frame.get('to')
            });
            
this.updateSliderSettings();
        },

        
getSliderValue: function( a) {
            return 
isRtl this.revisions.length this.revisions.indexOfthis.get(a) ) - this.revisions.indexOfthis.get(b) );
        },

        
updateSliderSettings: function() {
            if ( 
this.get('compareTwoMode') ) {
                
this.set({
                    
values: [
                        
this.getSliderValue'to''from' ),
                        
this.getSliderValue'from''to' )
                    ],
                    
valuenull,
                    
rangetrue // ensures handles cannot cross
                
});
            } else {
                
this.set({
                    
valuethis.getSliderValue'to''to' ),
                    
valuesnull,
                    
rangefalse
                
});
            }
            
this.trigger'update:slider' );
        },

        
// Called when a revision is hovered
        
hoverRevision: function( modelvalue ) {
            
this.trigger'hovered:revision'value );
        },

        
// Called when `compareTwoMode` changes
        
updateMode: function( modelvalue ) {
            
this.set({ compareTwoModevalue });
        },

        
// Called when `from` or `to` changes in the local model
        
handleLocalChanges: function() {
            
this.frame.set({
                
fromthis.get('from'),
                
tothis.get('to')
            });
        },

        
// Receives revisions changes from outside the model
        
receiveRevisions: function( fromto ) {
            
// Bail if nothing changed
            
if ( this.get('from') === from && this.get('to') === to ) {
                return;
            }

            
this.set({ fromfromtoto }, { silenttrue });
            
this.trigger'update:revisions'fromto );
        }

    });

    
revisions.model.Tooltip Backbone.Model.extend({
        
defaults: {
            
revisionnull,
            
offset: {},
            
hoveringfalse// Whether the mouse is hovering
            
scrubbingfalse // Whether the mouse is scrubbing
        
},

        
initialize: function( options ) {
            
this.frame options.frame;
            
this.revisions options.revisions;
            
this.slider options.slider;

            
this.listenTothis.slider'hovered:revision'this.updateRevision );
            
this.listenTothis.slider'change:hovering'this.setHovering );
            
this.listenTothis.slider'change:scrubbing'this.setScrubbing );
        },


        
updateRevision: function( revision ) {
            
this.set({ revisionrevision });
        },

        
setHovering: function( modelvalue ) {
            
this.set({ hoveringvalue });
        },

        
setScrubbing: function( modelvalue ) {
            
this.set({ scrubbingvalue });
        }
    });

    
revisions.model.Revision Backbone.Model.extend({});

    
/**
     * wp.revisions.model.Revisions
     *
     * A collection of post revisions.
     */
    
revisions.model.Revisions Backbone.Collection.extend({
        
modelrevisions.model.Revision,

        
initialize: function() {
            
_.bindAllthis'next''prev' );
        },

        
next: function( revision ) {
            var 
index this.indexOfrevision );

            if ( 
index !== -&& index !== this.length ) {
                return 
this.atindex );
            }
        },

        
prev: function( revision ) {
            var 
index this.indexOfrevision );

            if ( 
index !== -&& index !== ) {
                return 
this.atindex );
            }
        }
    });

    
revisions.model.Field Backbone.Model.extend({});

    
revisions.model.Fields Backbone.Collection.extend({
        
modelrevisions.model.Field
    
});

    
revisions.model.Diff Backbone.Model.extend({
        
initialize: function() {
            var 
fields this.get('fields');
            
this.unset('fields');

            
this.fields = new revisions.model.Fieldsfields );
        }
    });

    
revisions.model.Diffs Backbone.Collection.extend({
        
initialize: function( modelsoptions ) {
            
_.bindAllthis'getClosestUnloaded' );
            
this.loadAll _.oncethis._loadAll );
            
this.revisions options.revisions;
            
this.postId options.postId;
            
this.requests  = {};
        },

        
modelrevisions.model.Diff,

        
ensure: function( idcontext ) {
            var 
diff     this.getid ),
                
request  this.requestsid ],
                
deferred = $.Deferred(),
                
ids      = {},
                
from     id.split(':')[0],
                
to       id.split(':')[1];
            
ids[id] = true;

            
wp.revisions.log'ensure'id );

            
this.trigger'ensure'idsfromtodeferred.promise() );

            if ( 
diff ) {
                
deferred.resolveWithcontext, [ diff ] );
            } else {
                
this.trigger'ensure:load'idsfromtodeferred.promise() );
                
_.eachids_.bind( function( id ) {
                    
// Remove anything that has an ongoing request
                    
if ( this.requestsid ] ) {
                        
delete idsid ];
                    }
                    
// Remove anything we already have
                    
if ( this.getid ) ) {
                        
delete idsid ];
                    }
                }, 
this ) );
                if ( ! 
request ) {
                    
// Always include the ID that started this ensure
                    
idsid ] = true;
                    
request   this.load_.keysids ) );
                }

                
request.done_.bind( function() {
                    
deferred.resolveWithcontext, [ this.getid ) ] );
                }, 
this ) ).fail_.bind( function() {
                    
deferred.reject();
                }) );
            }

            return 
deferred.promise();
        },

        
// Returns an array of proximal diffs
        
getClosestUnloaded: function( idscenterId ) {
            var 
self this;
            return 
_.chain([0].concatids )).initial().zipids ).sortBy( function( pair ) {
                return 
Math.abscenterId pair[1] );
            }).
map( function( pair ) {
                return 
pair.join(':');
            }).
filter( function( diffId ) {
                return 
_.isUndefinedself.getdiffId ) ) && ! self.requestsdiffId ];
            }).
value();
        },

        
_loadAll: function( allRevisionIdscenterIdnum ) {
            var 
self thisdeferred = $.Deferred(),
                
diffs _.firstthis.getClosestUnloadedallRevisionIdscenterId ), num );
            if ( 
_.sizediffs ) > ) {
                
this.loaddiffs ).done( function() {
                    
self._loadAllallRevisionIdscenterIdnum ).done( function() {
                        
deferred.resolve();
                    });
                }).
fail( function() {
                    if ( 
=== num ) { // Already tried 1. This just isn't working. Give up.
                        
deferred.reject();
                    } else { 
// Request fewer diffs this time
                        
self._loadAllallRevisionIdscenterIdMath.ceilnum ) ).done( function() {
                            
deferred.resolve();
                        });
                    }
                });
            } else {
                
deferred.resolve();
            }
            return 
deferred;
        },

        
load: function( comparisons ) {
            
wp.revisions.log'load'comparisons );
            
// Our collection should only ever grow, never shrink, so remove: false
            
return this.fetch({ data: { comparecomparisons }, removefalse }).done( function() {
                
wp.revisions.log'load:complete'comparisons );
            });
        },

        
sync: function( methodmodeloptions ) {
            if ( 
'read' === method ) {
                
options options || {};
                
options.context this;
                
options.data _.extendoptions.data || {}, {
                    
action'get-revision-diffs',
                    
post_idthis.postId
                
});

                var 
deferred wp.ajax.sendoptions ),
                    
requests this.requests;

                
// Record that we're requesting each diff.
                
if ( options.data.compare ) {
                    
_.eachoptions.data.compare, function( id ) {
                        
requestsid ] = deferred;
                    });
                }

                
// When the request completes, clear the stored request.
                
deferred.always( function() {
                    if ( 
options.data.compare ) {
                        
_.eachoptions.data.compare, function( id ) {
                            
delete requestsid ];
                        });
                    }
                });

                return 
deferred;

            
// Otherwise, fall back to `Backbone.sync()`.
            
} else {
                return 
Backbone.Model.prototype.sync.applythisarguments );
            }
        }
    });


    
/**
     * wp.revisions.model.FrameState
     *
     * The frame state.
     *
     * @see wp.revisions.view.Frame
     *
     * @param {object}                    attributes        Model attributes - none are required.
     * @param {object}                    options           Options for the model.
     * @param {revisions.model.Revisions} options.revisions A collection of revisions.
     */
    
revisions.model.FrameState Backbone.Model.extend({
        
defaults: {
            
loadingfalse,
            
errorfalse,
            
compareTwoModefalse
        
},

        
initialize: function( attributesoptions ) {
            var 
state this.get'initialDiffState' );
            
_.bindAllthis'receiveDiff' );
            
this._debouncedEnsureDiff _.debouncethis._ensureDiff200 );

            
this.revisions options.revisions;

            
this.diffs = new revisions.model.Diffs( [], {
                
revisionsthis.revisions,
                
postIdthis.get'postId' )
            } );

            
// Set the initial diffs collection.
            
this.diffs.setthis.get'diffData' ) );

            
// Set up internal listeners
            
this.listenTothis'change:from'this.changeRevisionHandler );
            
this.listenTothis'change:to'this.changeRevisionHandler );
            
this.listenTothis'change:compareTwoMode'this.changeMode );
            
this.listenTothis'update:revisions'this.updatedRevisions );
            
this.listenTothis.diffs'ensure:load'this.updateLoadingStatus );
            
this.listenTothis'update:diff'this.updateLoadingStatus );

            
// Set the initial revisions, baseUrl, and mode as provided through attributes.

            
this.set( {
                
to this.revisions.getstate.to ),
                
from this.revisions.getstate.from ),
                
compareTwoMode state.compareTwoMode
            
} );

            
// Start the router if browser supports History API
            
if ( window.history && window.history.pushState ) {
                
this.router = new revisions.Router({ modelthis });
                
Backbone.history.start({ pushStatetrue });
            }
        },

        
updateLoadingStatus: function() {
            
this.set'error'false );
            
this.set'loading', ! this.diff() );
        },

        
changeMode: function( modelvalue ) {
            var 
toIndex this.revisions.indexOfthis.get'to' ) );

            
// If we were on the first revision before switching to two-handled mode,
            // bump the 'to' position over one
            
if ( value && === toIndex ) {
                
this.set({
                    
fromthis.revisions.attoIndex ),
                    
to:   this.revisions.attoIndex )
                });
            }

            
// When switching back to single-handled mode, reset 'from' model to
            // one position before the 'to' model
            
if ( ! value && !== toIndex ) { // '! value' means switching to single-handled mode
                
this.set({
                    
fromthis.revisions.attoIndex ),
                    
to:   this.revisions.attoIndex )
                });
            }
        },

        
updatedRevisions: function( fromto ) {
            if ( 
this.get'compareTwoMode' ) ) {
                
// TODO: compare-two loading strategy
            
} else {
                
this.diffs.loadAllthis.revisions.pluck('id'), to.id40 );
            }
        },

        
// Fetch the currently loaded diff.
        
diff: function() {
            return 
this.diffs.getthis._diffId );
        },

        
// So long as `from` and `to` are changed at the same time, the diff
        // will only be updated once. This is because Backbone updates all of
        // the changed attributes in `set`, and then fires the `change` events.
        
updateDiff: function( options ) {
            var 
fromtodiffIddiff;

            
options options || {};
            
from this.get('from');
            
to this.get('to');
            
diffId = ( from from.id ) + ':' to.id;

            
// Check if we're actually changing the diff id.
            
if ( this._diffId === diffId ) {
                return $.
Deferred().reject().promise();
            }

            
this._diffId diffId;
            
this.trigger'update:revisions'fromto );

            
diff this.diffs.getdiffId );

            
// If we already have the diff, then immediately trigger the update.
            
if ( diff ) {
                
this.receiveDiffdiff );
                return $.
Deferred().resolve().promise();
            
// Otherwise, fetch the diff.
            
} else {
                if ( 
options.immediate ) {
                    return 
this._ensureDiff();
                } else {
                    
this._debouncedEnsureDiff();
                    return $.
Deferred().reject().promise();
                }
            }
        },

        
// A simple wrapper around `updateDiff` to prevent the change event's
        // parameters from being passed through.
        
changeRevisionHandler: function() {
            
this.updateDiff();
        },

        
receiveDiff: function( diff ) {
            
// Did we actually get a diff?
            
if ( _.isUndefineddiff ) || _.isUndefineddiff.id ) ) {
                
this.set({
                    
loadingfalse,
                    
errortrue
                
});
            } else if ( 
this._diffId === diff.id ) { // Make sure the current diff didn't change
                
this.trigger'update:diff'diff );
            }
        },

        
_ensureDiff: function() {
            return 
this.diffs.ensurethis._diffIdthis ).alwaysthis.receiveDiff );
        }
    });


    
/**
     * ========================================================================
     * VIEWS
     * ========================================================================
     */

    /**
     * wp.revisions.view.Frame
     *
     * Top level frame that orchestrates the revisions experience.
     *
     * @param {object}                     options       The options hash for the view.
     * @param {revisions.model.FrameState} options.model The frame state model.
     */
    
revisions.view.Frame wp.Backbone.View.extend({
        
className'revisions',
        
templatewp.template('revisions-frame'),

        
initialize: function() {
            
this.listenTothis.model'update:diff'this.renderDiff );
            
this.listenTothis.model'change:compareTwoMode'this.updateCompareTwoMode );
            
this.listenTothis.model'change:loading'this.updateLoadingStatus );
            
this.listenTothis.model'change:error'this.updateErrorStatus );

            
this.views.set'.revisions-control-frame', new revisions.view.Controls({
                
modelthis.model
            
}) );
        },

        
render: function() {
            
wp.Backbone.View.prototype.render.applythisarguments );

            $(
'html').css'overflow-y''scroll' );
            $(
'#wpbody-content .wrap').appendthis.el );
            
this.updateCompareTwoMode();
            
this.renderDiffthis.model.diff() );
            
this.views.ready();

            return 
this;
        },

        
renderDiff: function( diff ) {
            
this.views.set'.revisions-diff-frame', new revisions.view.Diff({
                
modeldiff
            
}) );
        },

        
updateLoadingStatus: function() {
            
this.$el.toggleClass'loading'this.model.get('loading') );
        },

        
updateErrorStatus: function() {
            
this.$el.toggleClass'diff-error'this.model.get('error') );
        },

        
updateCompareTwoMode: function() {
            
this.$el.toggleClass'comparing-two-revisions'this.model.get('compareTwoMode') );
        }
    });

    
/**
     * wp.revisions.view.Controls
     *
     * The controls view.
     *
     * Contains the revision slider, previous/next buttons, the meta info and the compare checkbox.
     */
    
revisions.view.Controls wp.Backbone.View.extend({
        
className'revisions-controls',

        
initialize: function() {
            
_.bindAllthis'setWidth' );

            
// Add the button view
            
this.views.add( new revisions.view.Buttons({
                
modelthis.model
            
}) );

            
// Add the checkbox view
            
this.views.add( new revisions.view.Checkbox({
                
modelthis.model
            
}) );

            
// Prep the slider model
            
var slider = new revisions.model.Slider({
                
framethis.model,
                
revisionsthis.model.revisions
            
}),

            
// Prep the tooltip model
            
tooltip = new revisions.model.Tooltip({
                
framethis.model,
                
revisionsthis.model.revisions,
                
sliderslider
            
});

            
// Add the tooltip view
            
this.views.add( new revisions.view.Tooltip({
                
modeltooltip
            
}) );

            
// Add the tickmarks view
            
this.views.add( new revisions.view.Tickmarks({
                
modeltooltip
            
}) );

            
// Add the slider view
            
this.views.add( new revisions.view.Slider({
                
modelslider
            
}) );

            
// Add the Metabox view
            
this.views.add( new revisions.view.Metabox({
                
modelthis.model
            
}) );
        },

        
ready: function() {
            
this.top this.$el.offset().top;
            
this.window = $(window);
            
this.window.on'scroll.wp.revisions', {controlsthis}, function(e) {
                var 
controls  e.data.controls,
                    
container controls.$el.parent(),
                    
scrolled  controls.window.scrollTop(),
                    
frame     controls.views.parent;

                if ( 
scrolled >= controls.top ) {
                    if ( ! 
frame.$el.hasClass('pinned') ) {
                        
controls.setWidth();
                        
container.css('height'container.height() + 'px' );
                        
controls.window.on('resize.wp.revisions.pinning click.wp.revisions.pinning', {controlscontrols}, function(e) {
                            
e.data.controls.setWidth();
                        });
                    }
                    
frame.$el.addClass('pinned');
                } else if ( 
frame.$el.hasClass('pinned') ) {
                    
controls.window.off('.wp.revisions.pinning');
                    
controls.$el.css('width''auto');
                    
frame.$el.removeClass('pinned');
                    
container.css('height''auto');
                    
controls.top controls.$el.offset().top;
                } else {
                    
controls.top controls.$el.offset().top;
                }
            });
        },

        
setWidth: function() {
            
this.$el.css('width'this.$el.parent().width() + 'px');
        }
    });

    
// The tickmarks view
    
revisions.view.Tickmarks wp.Backbone.View.extend({
        
className'revisions-tickmarks',
        
directionisRtl 'right' 'left',

        
initialize: function() {
            
this.listenTothis.model'change:revision'this.reportTickPosition );
        },

        
reportTickPosition: function( modelrevision ) {
            var 
offsetthisOffsetparentOffsettickindex this.model.revisions.indexOfrevision );
            
thisOffset this.$el.allOffsets();
            
parentOffset this.$el.parent().allOffsets();
            if ( 
index === this.model.revisions.length ) {
                
// Last one
                
offset = {
                    
rightPlusWidththisOffset.left parentOffset.left 1,
                    
leftPlusWidththisOffset.right parentOffset.right 1
                
};
            } else {
                
// Normal tick
                
tick this.$('div:nth-of-type(' + (index 1) + ')');
                
offset tick.allPositions();
                
_.extendoffset, {
                    
leftoffset.left thisOffset.left parentOffset.left,
                    
rightoffset.right thisOffset.right parentOffset.right
                
});
                
_.extendoffset, {
                    
leftPlusWidthoffset.left tick.outerWidth(),
                    
rightPlusWidthoffset.right tick.outerWidth()
                });
            }
            
this.model.set({ offsetoffset });
        },

        
ready: function() {
            var 
tickCounttickWidth;
            
tickCount this.model.revisions.length 1;
            
tickWidth tickCount;
            
this.$el.css('width', ( this.model.revisions.length 50 ) + 'px');

            
_(tickCount).times( function( index ){
                
this.$el.append'<div style="' this.direction ': ' + ( 100 tickWidth index ) + '%"></div>' );
            }, 
this );
        }
    });

    
// The metabox view
    
revisions.view.Metabox wp.Backbone.View.extend({
        
className'revisions-meta',

        
initialize: function() {
            
// Add the 'from' view
            
this.views.add( new revisions.view.MetaFrom({
                
modelthis.model,
                
className'diff-meta diff-meta-from'
            
}) );

            
// Add the 'to' view
            
this.views.add( new revisions.view.MetaTo({
                
modelthis.model
            
}) );
        }
    });

    
// The revision meta view (to be extended)
    
revisions.view.Meta wp.Backbone.View.extend({
        
templatewp.template('revisions-meta'),

        
events: {
            
'click .restore-revision''restoreRevision'
        
},

        
initialize: function() {
            
this.listenTothis.model'update:revisions'this.render );
        },

        
prepare: function() {
            return 
_.extendthis.model.toJSON()[this.type] || {}, {
                
typethis.type
            
});
        },

        
restoreRevision: function() {
            
document.location this.model.get('to').attributes.restoreUrl;
        }
    });

    
// The revision meta 'from' view
    
revisions.view.MetaFrom revisions.view.Meta.extend({
        
className'diff-meta diff-meta-from',
        
type'from'
    
});

    
// The revision meta 'to' view
    
revisions.view.MetaTo revisions.view.Meta.extend({
        
className'diff-meta diff-meta-to',
        
type'to'
    
});

    
// The checkbox view.
    
revisions.view.Checkbox wp.Backbone.View.extend({
        
className'revisions-checkbox',
        
templatewp.template('revisions-checkbox'),

        
events: {
            
'click .compare-two-revisions''compareTwoToggle'
        
},

        
initialize: function() {
            
this.listenTothis.model'change:compareTwoMode'this.updateCompareTwoMode );
        },

        
ready: function() {
            if ( 
this.model.revisions.length ) {
                $(
'.revision-toggle-compare-mode').hide();
            }
        },

        
updateCompareTwoMode: function() {
            
this.$('.compare-two-revisions').prop'checked'this.model.get('compareTwoMode') );
        },

        
// Toggle the compare two mode feature when the compare two checkbox is checked.
        
compareTwoToggle: function() {
            
// Activate compare two mode?
            
this.model.set({ compareTwoMode: $('.compare-two-revisions').prop('checked') });
        }
    });

    
// The tooltip view.
    // Encapsulates the tooltip.
    
revisions.view.Tooltip wp.Backbone.View.extend({
        
className'revisions-tooltip',
        
templatewp.template('revisions-meta'),

        
initialize: function() {
            
this.listenTothis.model'change:offset'this.render );
            
this.listenTothis.model'change:hovering'this.toggleVisibility );
            
this.listenTothis.model'change:scrubbing'this.toggleVisibility );
        },

        
prepare: function() {
            if ( 
_.isNullthis.model.get('revision') ) ) {
                return;
            } else {
                return 
_.extend( { type'tooltip' }, {
                    
attributesthis.model.get('revision').toJSON()
                });
            }
        },

        
render: function() {
            var 
otherDirection,
                
direction,
                
directionVal,
                
flipped,
                
css      = {},
                
position this.model.revisions.indexOfthis.model.get('revision') ) + 1;

            
flipped = ( position this.model.revisions.length ) > 0.5;
            if ( 
isRtl ) {
                
direction flipped 'left' 'right';
                
directionVal flipped 'leftPlusWidth' direction;
            } else {
                
direction flipped 'right' 'left';
                
directionVal flipped 'rightPlusWidth' direction;
            }
            
otherDirection 'right' === direction 'left''right';
            
wp.Backbone.View.prototype.render.applythisarguments );
            
css[direction] = this.model.get('offset')[directionVal] + 'px';
            
css[otherDirection] = '';
            
this.$el.toggleClass'flipped'flipped ).csscss );
        },

        
visible: function() {
            return 
this.model.get'scrubbing' ) || this.model.get'hovering' );
        },

        
toggleVisibility: function() {
            if ( 
this.visible() ) {
                
this.$el.stop().show().fadeTo100 this.el.style.opacity 100);
            } else {
                
this.$el.stop().fadeTothis.el.style.opacity 3000, function(){ $(this).hide(); } );
            }
            return;
        }
    });

    
// The buttons view.
    // Encapsulates all of the configuration for the previous/next buttons.
    
revisions.view.Buttons wp.Backbone.View.extend({
        
className'revisions-buttons',
        
templatewp.template('revisions-buttons'),

        
events: {
            
'click .revisions-next .button''nextRevision',
            
'click .revisions-previous .button''previousRevision'
        
},

        
initialize: function() {
            
this.listenTothis.model'update:revisions'this.disabledButtonCheck );
        },

        
ready: function() {
            
this.disabledButtonCheck();
        },

        
// Go to a specific model index
        
gotoModel: function( toIndex ) {
            var 
attributes = {
                
tothis.model.revisions.attoIndex )
            };
            
// If we're at the first revision, unset 'from'.
            
if ( toIndex ) {
                
attributes.from this.model.revisions.attoIndex );
            } else {
                
this.model.unset('from', { silenttrue });
            }

            
this.model.setattributes );
        },

        
// Go to the 'next' revision
        
nextRevision: function() {
            var 
toIndex this.model.revisions.indexOfthis.model.get('to') ) + 1;
            
this.gotoModeltoIndex );
        },

        
// Go to the 'previous' revision
        
previousRevision: function() {
            var 
toIndex this.model.revisions.indexOfthis.model.get('to') ) - 1;
            
this.gotoModeltoIndex );
        },

        
// Check to see if the Previous or Next buttons need to be disabled or enabled.
        
disabledButtonCheck: function() {
            var 
maxVal   this.model.revisions.length 1,
                
minVal   0,
                
next     = $('.revisions-next .button'),
                
previous = $('.revisions-previous .button'),
                
val      this.model.revisions.indexOfthis.model.get('to') );

            
// Disable "Next" button if you're on the last node.
            
next.prop'disabled', ( maxVal === val ) );

            
// Disable "Previous" button if you're on the first node.
            
previous.prop'disabled', ( minVal === val ) );
        }
    });


    
// The slider view.
    
revisions.view.Slider wp.Backbone.View.extend({
        
className'wp-slider',
        
directionisRtl 'right' 'left',

        
events: {
            
'mousemove' 'mouseMove'
        
},

        
initialize: function() {
            
_.bindAllthis'start''slide''stop''mouseMove''mouseEnter''mouseLeave' );
            
this.listenTothis.model'update:slider'this.applySliderSettings );
        },

        
ready: function() {
            
this.$el.css('width', ( this.model.revisions.length 50 ) + 'px');
            
this.$el.slider_.extendthis.model.toJSON(), {
                
startthis.start,
                
slidethis.slide,
                
stop:  this.stop
            
}) );

            
this.$el.hoverIntent({
                
overthis.mouseEnter,
                
outthis.mouseLeave,
                
timeout800
            
});

            
this.applySliderSettings();
        },

        
mouseMove: function( ) {
            var 
zoneCount         this.model.revisions.length 1// One fewer zone than models
                
sliderFrom        this.$el.allOffsets()[this.direction], // "From" edge of slider
                
sliderWidth       this.$el.width(), // Width of slider
                
tickWidth         sliderWidth zoneCount// Calculated width of zone
                
actualX           = ( isRtl ? $(window).width() - e.pageX e.pageX ) - sliderFrom// Flipped for RTL - sliderFrom;
                
currentModelIndex Math.floor( ( actualX  + ( tickWidth )  ) / tickWidth ); // Calculate the model index

            // Ensure sane value for currentModelIndex.
            
if ( currentModelIndex ) {
                
currentModelIndex 0;
            } else if ( 
currentModelIndex >= this.model.revisions.length ) {
                
currentModelIndex this.model.revisions.length 1;
            }

            
// Update the tooltip mode
            
this.model.set({ hoveredRevisionthis.model.revisions.atcurrentModelIndex ) });
        },

        
mouseLeave: function() {
            
this.model.set({ hoveringfalse });
        },

        
mouseEnter: function() {
            
this.model.set({ hoveringtrue });
        },

        
applySliderSettings: function() {
            
this.$el.slider_.pickthis.model.toJSON(), 'value''values''range' ) );
            var 
handles this.$('a.ui-slider-handle');

            if ( 
this.model.get('compareTwoMode') ) {
                
// in RTL mode the 'left handle' is the second in the slider, 'right' is first
                
handles.first()
                    .
toggleClass'to-handle', !! isRtl )
                    .
toggleClass'from-handle', ! isRtl );
                
handles.last()
                    .
toggleClass'from-handle', !! isRtl )
                    .
toggleClass'to-handle', ! isRtl );
            } else {
                
handles.removeClass('from-handle to-handle');
            }
        },

        
start: function( eventui ) {
            
this.model.set({ scrubbingtrue });

            
// Track the mouse position to enable smooth dragging,
            // overrides default jQuery UI step behavior.
            
$( window ).on'mousemove.wp.revisions', { viewthis }, function( ) {
                var 
handles,
                    
view              e.data.view,
                    
leftDragBoundary  view.$el.offset().left,
                    
sliderOffset      leftDragBoundary,
                    
sliderRightEdge   leftDragBoundary view.$el.width(),
                    
rightDragBoundary sliderRightEdge,
                    
leftDragReset     '0',
                    
rightDragReset    '100%',
                    
handle            = $( ui.handle );

                
// In two handle mode, ensure handles can't be dragged past each other.
                // Adjust left/right boundaries and reset points.
                
if ( view.model.get('compareTwoMode') ) {
                    
handles handle.parent().find('.ui-slider-handle');
                    if ( 
handle.ishandles.first() ) ) { // We're the left handle
                        
rightDragBoundary handles.last().offset().left;
                        
rightDragReset    rightDragBoundary sliderOffset;
                    } else { 
// We're the right handle
                        
leftDragBoundary handles.first().offset().left handles.first().width();
                        
leftDragReset    leftDragBoundary sliderOffset;
                    }
                }

                
// Follow mouse movements, as long as handle remains inside slider.
                
if ( e.pageX leftDragBoundary ) {
                    
handle.css'left'leftDragReset ); // Mouse to left of slider.
                
} else if ( e.pageX rightDragBoundary ) {
                    
handle.css'left'rightDragReset ); // Mouse to right of slider.
                
} else {
                    
handle.css'left'e.pageX sliderOffset ); // Mouse in slider.
                
}
            } );
        },

        
getPosition: function( position ) {
            return 
isRtl this.model.revisions.length position 1position;
        },

        
// Responds to slide events
        
slide: function( eventui ) {
            var 
attributesmovedRevision;
            
// Compare two revisions mode
            
if ( this.model.get('compareTwoMode') ) {
                
// Prevent sliders from occupying same spot
                
if ( ui.values[1] === ui.values[0] ) {
                    return 
false;
                }
                if ( 
isRtl ) {
                    
ui.values.reverse();
                }
                
attributes = {
                    
fromthis.model.revisions.atthis.getPositionui.values[0] ) ),
                    
tothis.model.revisions.atthis.getPositionui.values[1] ) )
                };
            } else {
                
attributes = {
                    
tothis.model.revisions.atthis.getPositionui.value ) )
                };
                
// If we're at the first revision, unset 'from'.
                
if ( this.getPositionui.value ) > ) {
                    
attributes.from this.model.revisions.atthis.getPositionui.value ) - );
                } else {
                    
attributes.from undefined;
                }
            }
            
movedRevision this.model.revisions.atthis.getPositionui.value ) );

            
// If we are scrubbing, a scrub to a revision is considered a hover
            
if ( this.model.get('scrubbing') ) {
                
attributes.hoveredRevision movedRevision;
            }

            
this.model.setattributes );
        },

        
stop: function() {
            $( 
window ).off('mousemove.wp.revisions');
            
this.model.updateSliderSettings(); // To snap us back to a tick mark
            
this.model.set({ scrubbingfalse });
        }
    });

    
// The diff view.
    // This is the view for the current active diff.
    
revisions.view.Diff wp.Backbone.View.extend({
        
className'revisions-diff',
        
template:  wp.template('revisions-diff'),

        
// Generate the options to be passed to the template.
        
prepare: function() {
            return 
_.extend({ fieldsthis.model.fields.toJSON() }, this.options );
        }
    });

    
// The revisions router.
    // Maintains the URL routes so browser URL matches state.
    
revisions.Router Backbone.Router.extend({
        
initialize: function( options ) {
            
this.model options.model;

            
// Maintain state and history when navigating
            
this.listenTothis.model'update:diff'_.debouncethis.updateUrl250 ) );
            
this.listenTothis.model'change:compareTwoMode'this.updateUrl );
        },

        
baseUrl: function( url ) {
            return 
this.model.get('baseUrl') + url;
        },

        
updateUrl: function() {
            var 
from this.model.has('from') ? this.model.get('from').id 0,
                
to   this.model.get('to').id;
            if ( 
this.model.get('compareTwoMode' ) ) {
                
this.navigatethis.baseUrl'?from=' from '&to=' to ), { replacetrue } );
            } else {
                
this.navigatethis.baseUrl'?revision=' to ), { replacetrue } );
            }
        },

        
handleRoute: function( a) {
            var 
compareTwo _.isUndefined);

            if ( ! 
compareTwo ) {
                
this.model.revisions.get);
                
this.model.revisions.prev);
                
b.id 0;
                
a.id 0;
            }
        }
    });

    
/**
     * Initialize the revisions UI for revision.php.
     */
    
revisions.init = function() {
        var 
state;

        
// Bail if the current page is not revision.php.
        
if ( ! window.adminpage || 'revision-php' !== window.adminpage ) {
            return;
        }

        
state = new revisions.model.FrameState({
            
initialDiffState: {
                
// wp_localize_script doesn't stringifies ints, so cast them.
                
toparseIntrevisions.settings.to10 ),
                
fromparseIntrevisions.settings.from10 ),
                
// wp_localize_script does not allow for top-level booleans so do a comparator here.
                
compareTwoMode: ( revisions.settings.compareTwoMode === '1' )
            },
            
diffDatarevisions.settings.diffData,
            
baseUrlrevisions.settings.baseUrl,
            
postIdparseIntrevisions.settings.postId10 )
        }, {
            
revisions: new revisions.model.Revisionsrevisions.settings.revisionData )
        });

        
revisions.view.frame = new revisions.view.Frame({
            
modelstate
        
}).render();
    };

    $( 
revisions.init );
}(
jQuery));
?>
Онлайн: 0
Реклама