at path:ROOT / wp-admin / js / revisions.js
run:R W Run
DIR
2026-03-11 16:18:51
R W Run
2.86 KB
2026-03-11 16:18:51
R W Run
758 By
2026-03-11 16:18:51
R W Run
6.24 KB
2026-03-11 16:18:51
R W Run
2.95 KB
2026-03-11 16:18:51
R W Run
5.66 KB
2026-03-11 16:18:51
R W Run
2.04 KB
2026-03-11 16:18:51
R W Run
11.32 KB
2026-03-11 16:18:51
R W Run
3.01 KB
2026-03-11 16:18:51
R W Run
9.54 KB
2026-03-11 16:18:51
R W Run
3.4 KB
2026-03-11 16:18:51
R W Run
2.85 KB
2026-03-11 16:18:51
R W Run
1.28 KB
2026-03-11 16:18:51
R W Run
61.15 KB
2026-03-11 16:18:51
R W Run
23.12 KB
2026-03-11 16:18:51
R W Run
3.35 KB
2026-03-11 16:18:51
R W Run
1.18 KB
2026-03-11 16:18:51
R W Run
1.98 KB
2026-03-11 16:18:51
R W Run
288.41 KB
2026-03-11 16:18:51
R W Run
109.69 KB
2026-03-11 16:18:51
R W Run
111.46 KB
2026-03-11 16:18:51
R W Run
47.14 KB
2026-03-11 16:18:51
R W Run
70.05 KB
2026-03-11 16:18:51
R W Run
27.41 KB
2026-03-11 16:18:51
R W Run
27.02 KB
2026-03-11 16:18:51
R W Run
8.65 KB
2026-03-11 16:18:51
R W Run
37.12 KB
2026-03-11 16:18:51
R W Run
15.13 KB
2026-03-11 16:18:51
R W Run
41.61 KB
2026-03-11 16:18:51
R W Run
13.14 KB
2026-03-11 16:18:51
R W Run
44 KB
2026-03-11 16:18:51
R W Run
12.78 KB
2026-03-11 16:18:51
R W Run
7.67 KB
2026-03-11 16:18:51
R W Run
5.41 KB
2026-03-11 16:18:51
R W Run
3.65 KB
2026-03-11 16:18:51
R W Run
39.98 KB
2026-03-11 16:18:51
R W Run
15.15 KB
2026-03-11 16:18:51
R W Run
20.17 KB
2026-03-11 16:18:51
R W Run
9.41 KB
2026-03-11 16:18:51
R W Run
7.61 KB
2026-03-11 16:18:51
R W Run
2.93 KB
2026-03-11 16:18:51
R W Run
23.09 KB
2026-03-11 16:18:51
R W Run
890 By
2026-03-11 16:18:51
R W Run
423 By
2026-03-11 16:18:51
R W Run
3.89 KB
2026-03-11 16:18:51
R W Run
1.7 KB
2026-03-11 16:18:51
R W Run
1.27 KB
2026-03-11 16:18:51
R W Run
611 By
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
1.13 KB
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
2.38 KB
2026-03-11 16:18:51
R W Run
61.15 KB
2026-03-11 16:18:51
R W Run
30.06 KB
2026-03-11 16:18:51
R W Run
4.14 KB
2026-03-11 16:18:51
R W Run
1.1 KB
2026-03-11 16:18:51
R W Run
1.31 KB
2026-03-11 16:18:51
R W Run
847 By
2026-03-11 16:18:51
R W Run
6.92 KB
2026-03-11 16:18:51
R W Run
2.35 KB
2026-03-11 16:18:51
R W Run
38.68 KB
2026-03-11 16:18:51
R W Run
18.4 KB
2026-03-11 16:18:51
R W Run
18.49 KB
2026-03-11 16:18:51
R W Run
6.6 KB
2026-03-11 16:18:51
R W Run
10.67 KB
2026-03-11 16:18:51
R W Run
5.03 KB
2026-03-11 16:18:51
R W Run
33.92 KB
2026-03-11 16:18:51
R W Run
17.97 KB
2026-03-11 16:18:51
R W Run
876 By
2026-03-11 16:18:51
R W Run
620 By
2026-03-11 16:18:51
R W Run
13.15 KB
2026-03-11 16:18:51
R W Run
6.13 KB
2026-03-11 16:18:51
R W Run
6.1 KB
2026-03-11 16:18:51
R W Run
2.2 KB
2026-03-11 16:18:51
R W Run
3.2 KB
2026-03-11 16:18:51
R W Run
1.53 KB
2026-03-11 16:18:51
R W Run
10.88 KB
2026-03-11 16:18:51
R W Run
3 KB
2026-03-11 16:18:51
R W Run
5.64 KB
2026-03-11 16:18:51
R W Run
2.22 KB
2026-03-11 16:18:51
R W Run
5.96 KB
2026-03-11 16:18:51
R W Run
2.41 KB
2026-03-11 16:18:51
R W Run
24.77 KB
2026-03-11 16:18:51
R W Run
11.43 KB
2026-03-11 16:18:51
R W Run
54.94 KB
2026-03-11 16:18:51
R W Run
26.51 KB
2026-03-11 16:18:51
R W Run
109.37 KB
2026-03-11 16:18:51
R W Run
47.31 KB
2026-03-11 16:18:51
R W Run
17.91 KB
2026-03-11 16:18:51
R W Run
7.81 KB
2026-03-11 16:18:51
R W Run
2.25 KB
2026-03-11 16:18:51
R W Run
676 By
2026-03-11 16:18:51
R W Run
22.56 KB
2026-03-11 16:18:51
R W Run
12.31 KB
2026-03-11 16:18:51
R W Run
7.52 KB
2026-03-11 16:18:51
R W Run
1.49 KB
2026-03-11 16:18:51
R W Run
740 By
2026-03-11 16:18:51
R W Run
458 By
2026-03-11 16:18:51
R W Run
error_log
📄revisions.js
1/**
2 * @file Revisions interface functions, Backbone classes and
3 * the revisions.php document.ready bootstrap.
4 *
5 * @output wp-admin/js/revisions.js
6 */
7
8/* global isRtl */
9
10window.wp = window.wp || {};
11
12(function($) {
13 var revisions;
14 /**
15 * Expose the module in window.wp.revisions.
16 */
17 revisions = wp.revisions = { model: {}, view: {}, controller: {} };
18
19 // Link post revisions data served from the back end.
20 revisions.settings = window._wpRevisionsSettings || {};
21
22 // For debugging.
23 revisions.debug = false;
24
25 /**
26 * wp.revisions.log
27 *
28 * A debugging utility for revisions. Works only when a
29 * debug flag is on and the browser supports it.
30 */
31 revisions.log = function() {
32 if ( window.console && revisions.debug ) {
33 window.console.log.apply( window.console, arguments );
34 }
35 };
36
37 // Handy functions to help with positioning.
38 $.fn.allOffsets = function() {
39 var offset = this.offset() || {top: 0, left: 0}, win = $(window);
40 return _.extend( offset, {
41 right: win.width() - offset.left - this.outerWidth(),
42 bottom: win.height() - offset.top - this.outerHeight()
43 });
44 };
45
46 $.fn.allPositions = function() {
47 var position = this.position() || {top: 0, left: 0}, parent = this.parent();
48 return _.extend( position, {
49 right: parent.outerWidth() - position.left - this.outerWidth(),
50 bottom: parent.outerHeight() - position.top - this.outerHeight()
51 });
52 };
53
54 /**
55 * ========================================================================
56 * MODELS
57 * ========================================================================
58 */
59 revisions.model.Slider = Backbone.Model.extend({
60 defaults: {
61 value: null,
62 values: null,
63 min: 0,
64 max: 1,
65 step: 1,
66 range: false,
67 compareTwoMode: false
68 },
69
70 initialize: function( options ) {
71 this.frame = options.frame;
72 this.revisions = options.revisions;
73
74 // Listen for changes to the revisions or mode from outside.
75 this.listenTo( this.frame, 'update:revisions', this.receiveRevisions );
76 this.listenTo( this.frame, 'change:compareTwoMode', this.updateMode );
77
78 // Listen for internal changes.
79 this.on( 'change:from', this.handleLocalChanges );
80 this.on( 'change:to', this.handleLocalChanges );
81 this.on( 'change:compareTwoMode', this.updateSliderSettings );
82 this.on( 'update:revisions', this.updateSliderSettings );
83
84 // Listen for changes to the hovered revision.
85 this.on( 'change:hoveredRevision', this.hoverRevision );
86
87 this.set({
88 max: this.revisions.length - 1,
89 compareTwoMode: this.frame.get('compareTwoMode'),
90 from: this.frame.get('from'),
91 to: this.frame.get('to')
92 });
93 this.updateSliderSettings();
94 },
95
96 getSliderValue: function( a, b ) {
97 return isRtl ? this.revisions.length - this.revisions.indexOf( this.get(a) ) - 1 : this.revisions.indexOf( this.get(b) );
98 },
99
100 updateSliderSettings: function() {
101 if ( this.get('compareTwoMode') ) {
102 this.set({
103 values: [
104 this.getSliderValue( 'to', 'from' ),
105 this.getSliderValue( 'from', 'to' )
106 ],
107 value: null,
108 range: true // Ensures handles cannot cross.
109 });
110 } else {
111 this.set({
112 value: this.getSliderValue( 'to', 'to' ),
113 values: null,
114 range: false
115 });
116 }
117 this.trigger( 'update:slider' );
118 },
119
120 // Called when a revision is hovered.
121 hoverRevision: function( model, value ) {
122 this.trigger( 'hovered:revision', value );
123 },
124
125 // Called when `compareTwoMode` changes.
126 updateMode: function( model, value ) {
127 this.set({ compareTwoMode: value });
128 },
129
130 // Called when `from` or `to` changes in the local model.
131 handleLocalChanges: function() {
132 this.frame.set({
133 from: this.get('from'),
134 to: this.get('to')
135 });
136 },
137
138 // Receives revisions changes from outside the model.
139 receiveRevisions: function( from, to ) {
140 // Bail if nothing changed.
141 if ( this.get('from') === from && this.get('to') === to ) {
142 return;
143 }
144
145 this.set({ from: from, to: to }, { silent: true });
146 this.trigger( 'update:revisions', from, to );
147 }
148
149 });
150
151 revisions.model.Tooltip = Backbone.Model.extend({
152 defaults: {
153 revision: null,
154 offset: {},
155 hovering: false, // Whether the mouse is hovering.
156 scrubbing: false // Whether the mouse is scrubbing.
157 },
158
159 initialize: function( options ) {
160 this.frame = options.frame;
161 this.revisions = options.revisions;
162 this.slider = options.slider;
163
164 this.listenTo( this.slider, 'hovered:revision', this.updateRevision );
165 this.listenTo( this.slider, 'change:hovering', this.setHovering );
166 this.listenTo( this.slider, 'change:scrubbing', this.setScrubbing );
167 },
168
169
170 updateRevision: function( revision ) {
171 this.set({ revision: revision });
172 },
173
174 setHovering: function( model, value ) {
175 this.set({ hovering: value });
176 },
177
178 setScrubbing: function( model, value ) {
179 this.set({ scrubbing: value });
180 }
181 });
182
183 revisions.model.Revision = Backbone.Model.extend({});
184
185 /**
186 * wp.revisions.model.Revisions
187 *
188 * A collection of post revisions.
189 */
190 revisions.model.Revisions = Backbone.Collection.extend({
191 model: revisions.model.Revision,
192
193 initialize: function() {
194 _.bindAll( this, 'next', 'prev' );
195 },
196
197 next: function( revision ) {
198 var index = this.indexOf( revision );
199
200 if ( index !== -1 && index !== this.length - 1 ) {
201 return this.at( index + 1 );
202 }
203 },
204
205 prev: function( revision ) {
206 var index = this.indexOf( revision );
207
208 if ( index !== -1 && index !== 0 ) {
209 return this.at( index - 1 );
210 }
211 }
212 });
213
214 revisions.model.Field = Backbone.Model.extend({});
215
216 revisions.model.Fields = Backbone.Collection.extend({
217 model: revisions.model.Field
218 });
219
220 revisions.model.Diff = Backbone.Model.extend({
221 initialize: function() {
222 var fields = this.get('fields');
223 this.unset('fields');
224
225 this.fields = new revisions.model.Fields( fields );
226 }
227 });
228
229 revisions.model.Diffs = Backbone.Collection.extend({
230 initialize: function( models, options ) {
231 _.bindAll( this, 'getClosestUnloaded' );
232 this.loadAll = _.once( this._loadAll );
233 this.revisions = options.revisions;
234 this.postId = options.postId;
235 this.requests = {};
236 },
237
238 model: revisions.model.Diff,
239
240 ensure: function( id, context ) {
241 var diff = this.get( id ),
242 request = this.requests[ id ],
243 deferred = $.Deferred(),
244 ids = {},
245 from = id.split(':')[0],
246 to = id.split(':')[1];
247 ids[id] = true;
248
249 wp.revisions.log( 'ensure', id );
250
251 this.trigger( 'ensure', ids, from, to, deferred.promise() );
252
253 if ( diff ) {
254 deferred.resolveWith( context, [ diff ] );
255 } else {
256 this.trigger( 'ensure:load', ids, from, to, deferred.promise() );
257 _.each( ids, _.bind( function( id ) {
258 // Remove anything that has an ongoing request.
259 if ( this.requests[ id ] ) {
260 delete ids[ id ];
261 }
262 // Remove anything we already have.
263 if ( this.get( id ) ) {
264 delete ids[ id ];
265 }
266 }, this ) );
267 if ( ! request ) {
268 // Always include the ID that started this ensure.
269 ids[ id ] = true;
270 request = this.load( _.keys( ids ) );
271 }
272
273 request.done( _.bind( function() {
274 deferred.resolveWith( context, [ this.get( id ) ] );
275 }, this ) ).fail( _.bind( function() {
276 deferred.reject();
277 }) );
278 }
279
280 return deferred.promise();
281 },
282
283 // Returns an array of proximal diffs.
284 getClosestUnloaded: function( ids, centerId ) {
285 var self = this;
286 return _.chain([0].concat( ids )).initial().zip( ids ).sortBy( function( pair ) {
287 return Math.abs( centerId - pair[1] );
288 }).map( function( pair ) {
289 return pair.join(':');
290 }).filter( function( diffId ) {
291 return _.isUndefined( self.get( diffId ) ) && ! self.requests[ diffId ];
292 }).value();
293 },
294
295 _loadAll: function( allRevisionIds, centerId, num ) {
296 var self = this, deferred = $.Deferred(),
297 diffs = _.first( this.getClosestUnloaded( allRevisionIds, centerId ), num );
298 if ( _.size( diffs ) > 0 ) {
299 this.load( diffs ).done( function() {
300 self._loadAll( allRevisionIds, centerId, num ).done( function() {
301 deferred.resolve();
302 });
303 }).fail( function() {
304 if ( 1 === num ) { // Already tried 1. This just isn't working. Give up.
305 deferred.reject();
306 } else { // Request fewer diffs this time.
307 self._loadAll( allRevisionIds, centerId, Math.ceil( num / 2 ) ).done( function() {
308 deferred.resolve();
309 });
310 }
311 });
312 } else {
313 deferred.resolve();
314 }
315 return deferred;
316 },
317
318 load: function( comparisons ) {
319 wp.revisions.log( 'load', comparisons );
320 // Our collection should only ever grow, never shrink, so `remove: false`.
321 return this.fetch({ data: { compare: comparisons }, remove: false }).done( function() {
322 wp.revisions.log( 'load:complete', comparisons );
323 });
324 },
325
326 sync: function( method, model, options ) {
327 if ( 'read' === method ) {
328 options = options || {};
329 options.context = this;
330 options.data = _.extend( options.data || {}, {
331 action: 'get-revision-diffs',
332 post_id: this.postId
333 });
334
335 var deferred = wp.ajax.send( options ),
336 requests = this.requests;
337
338 // Record that we're requesting each diff.
339 if ( options.data.compare ) {
340 _.each( options.data.compare, function( id ) {
341 requests[ id ] = deferred;
342 });
343 }
344
345 // When the request completes, clear the stored request.
346 deferred.always( function() {
347 if ( options.data.compare ) {
348 _.each( options.data.compare, function( id ) {
349 delete requests[ id ];
350 });
351 }
352 });
353
354 return deferred;
355
356 // Otherwise, fall back to `Backbone.sync()`.
357 } else {
358 return Backbone.Model.prototype.sync.apply( this, arguments );
359 }
360 }
361 });
362
363
364 /**
365 * wp.revisions.model.FrameState
366 *
367 * The frame state.
368 *
369 * @see wp.revisions.view.Frame
370 *
371 * @param {object} attributes Model attributes - none are required.
372 * @param {object} options Options for the model.
373 * @param {revisions.model.Revisions} options.revisions A collection of revisions.
374 */
375 revisions.model.FrameState = Backbone.Model.extend({
376 defaults: {
377 loading: false,
378 error: false,
379 compareTwoMode: false
380 },
381
382 initialize: function( attributes, options ) {
383 var state = this.get( 'initialDiffState' );
384 _.bindAll( this, 'receiveDiff' );
385 this._debouncedEnsureDiff = _.debounce( this._ensureDiff, 200 );
386
387 this.revisions = options.revisions;
388
389 this.diffs = new revisions.model.Diffs( [], {
390 revisions: this.revisions,
391 postId: this.get( 'postId' )
392 } );
393
394 // Set the initial diffs collection.
395 this.diffs.set( this.get( 'diffData' ) );
396
397 // Set up internal listeners.
398 this.listenTo( this, 'change:from', this.changeRevisionHandler );
399 this.listenTo( this, 'change:to', this.changeRevisionHandler );
400 this.listenTo( this, 'change:compareTwoMode', this.changeMode );
401 this.listenTo( this, 'update:revisions', this.updatedRevisions );
402 this.listenTo( this.diffs, 'ensure:load', this.updateLoadingStatus );
403 this.listenTo( this, 'update:diff', this.updateLoadingStatus );
404
405 // Set the initial revisions, baseUrl, and mode as provided through attributes.
406
407 this.set( {
408 to : this.revisions.get( state.to ),
409 from : this.revisions.get( state.from ),
410 compareTwoMode : state.compareTwoMode
411 } );
412
413 // Start the router if browser supports History API.
414 if ( window.history && window.history.pushState ) {
415 this.router = new revisions.Router({ model: this });
416 if ( Backbone.History.started ) {
417 Backbone.history.stop();
418 }
419 Backbone.history.start({ pushState: true });
420 }
421 },
422
423 updateLoadingStatus: function() {
424 this.set( 'error', false );
425 this.set( 'loading', ! this.diff() );
426 },
427
428 changeMode: function( model, value ) {
429 var toIndex = this.revisions.indexOf( this.get( 'to' ) );
430
431 // If we were on the first revision before switching to two-handled mode,
432 // bump the 'to' position over one.
433 if ( value && 0 === toIndex ) {
434 this.set({
435 from: this.revisions.at( toIndex ),
436 to: this.revisions.at( toIndex + 1 )
437 });
438 }
439
440 // When switching back to single-handled mode, reset 'from' model to
441 // one position before the 'to' model.
442 if ( ! value && 0 !== toIndex ) { // '! value' means switching to single-handled mode.
443 this.set({
444 from: this.revisions.at( toIndex - 1 ),
445 to: this.revisions.at( toIndex )
446 });
447 }
448 },
449
450 updatedRevisions: function( from, to ) {
451 if ( this.get( 'compareTwoMode' ) ) {
452 // @todo Compare-two loading strategy.
453 } else {
454 this.diffs.loadAll( this.revisions.pluck('id'), to.id, 40 );
455 }
456 },
457
458 // Fetch the currently loaded diff.
459 diff: function() {
460 return this.diffs.get( this._diffId );
461 },
462
463 /*
464 * So long as `from` and `to` are changed at the same time, the diff
465 * will only be updated once. This is because Backbone updates all of
466 * the changed attributes in `set`, and then fires the `change` events.
467 */
468 updateDiff: function( options ) {
469 var from, to, diffId, diff;
470
471 options = options || {};
472 from = this.get('from');
473 to = this.get('to');
474 diffId = ( from ? from.id : 0 ) + ':' + to.id;
475
476 // Check if we're actually changing the diff id.
477 if ( this._diffId === diffId ) {
478 return $.Deferred().reject().promise();
479 }
480
481 this._diffId = diffId;
482 this.trigger( 'update:revisions', from, to );
483
484 diff = this.diffs.get( diffId );
485
486 // If we already have the diff, then immediately trigger the update.
487 if ( diff ) {
488 this.receiveDiff( diff );
489 return $.Deferred().resolve().promise();
490 // Otherwise, fetch the diff.
491 } else {
492 if ( options.immediate ) {
493 return this._ensureDiff();
494 } else {
495 this._debouncedEnsureDiff();
496 return $.Deferred().reject().promise();
497 }
498 }
499 },
500
501 // A simple wrapper around `updateDiff` to prevent the change event's
502 // parameters from being passed through.
503 changeRevisionHandler: function() {
504 this.updateDiff();
505 },
506
507 receiveDiff: function( diff ) {
508 // Did we actually get a diff?
509 if ( _.isUndefined( diff ) || _.isUndefined( diff.id ) ) {
510 this.set({
511 loading: false,
512 error: true
513 });
514 } else if ( this._diffId === diff.id ) { // Make sure the current diff didn't change.
515 this.trigger( 'update:diff', diff );
516 }
517 },
518
519 _ensureDiff: function() {
520 return this.diffs.ensure( this._diffId, this ).always( this.receiveDiff );
521 }
522 });
523
524
525 /**
526 * ========================================================================
527 * VIEWS
528 * ========================================================================
529 */
530
531 /**
532 * wp.revisions.view.Frame
533 *
534 * Top level frame that orchestrates the revisions experience.
535 *
536 * @param {object} options The options hash for the view.
537 * @param {revisions.model.FrameState} options.model The frame state model.
538 */
539 revisions.view.Frame = wp.Backbone.View.extend({
540 className: 'revisions',
541 template: wp.template('revisions-frame'),
542
543 initialize: function() {
544 this.listenTo( this.model, 'update:diff', this.renderDiff );
545 this.listenTo( this.model, 'change:compareTwoMode', this.updateCompareTwoMode );
546 this.listenTo( this.model, 'change:loading', this.updateLoadingStatus );
547 this.listenTo( this.model, 'change:error', this.updateErrorStatus );
548
549 this.views.set( '.revisions-control-frame', new revisions.view.Controls({
550 model: this.model
551 }) );
552 },
553
554 render: function() {
555 wp.Backbone.View.prototype.render.apply( this, arguments );
556
557 $('html').css( 'overflow-y', 'scroll' );
558 $('#wpbody-content .wrap').append( this.el );
559 this.updateCompareTwoMode();
560 this.renderDiff( this.model.diff() );
561 this.views.ready();
562
563 return this;
564 },
565
566 renderDiff: function( diff ) {
567 this.views.set( '.revisions-diff-frame', new revisions.view.Diff({
568 model: diff
569 }) );
570 },
571
572 updateLoadingStatus: function() {
573 this.$el.toggleClass( 'loading', this.model.get('loading') );
574 },
575
576 updateErrorStatus: function() {
577 this.$el.toggleClass( 'diff-error', this.model.get('error') );
578 },
579
580 updateCompareTwoMode: function() {
581 this.$el.toggleClass( 'comparing-two-revisions', this.model.get('compareTwoMode') );
582 }
583 });
584
585 /**
586 * wp.revisions.view.Controls
587 *
588 * The controls view.
589 *
590 * Contains the revision slider, previous/next buttons, the meta info and the compare checkbox.
591 */
592 revisions.view.Controls = wp.Backbone.View.extend({
593 className: 'revisions-controls',
594
595 initialize: function() {
596 _.bindAll( this, 'setWidth' );
597
598 // Add the checkbox view.
599 this.views.add( new revisions.view.Checkbox({
600 model: this.model
601 }) );
602
603 // Add the button view.
604 this.views.add( new revisions.view.Buttons({
605 model: this.model
606 }) );
607
608 // Prep the slider model.
609 var slider = new revisions.model.Slider({
610 frame: this.model,
611 revisions: this.model.revisions
612 }),
613
614 // Prep the tooltip model.
615 tooltip = new revisions.model.Tooltip({
616 frame: this.model,
617 revisions: this.model.revisions,
618 slider: slider
619 });
620
621 // Add the tooltip view.
622 this.views.add( new revisions.view.Tooltip({
623 model: tooltip
624 }) );
625
626 // Add the tickmarks view.
627 this.views.add( new revisions.view.Tickmarks({
628 model: tooltip
629 }) );
630
631 // Add the visually hidden slider help view.
632 this.views.add( new revisions.view.SliderHelp() );
633
634 // Add the slider view.
635 this.views.add( new revisions.view.Slider({
636 model: slider
637 }) );
638
639 // Add the Metabox view.
640 this.views.add( new revisions.view.Metabox({
641 model: this.model
642 }) );
643 },
644
645 ready: function() {
646 this.top = this.$el.offset().top;
647 this.window = $(window);
648 this.window.on( 'scroll.wp.revisions', {controls: this}, function(e) {
649 var controls = e.data.controls,
650 container = controls.$el.parent(),
651 scrolled = controls.window.scrollTop(),
652 frame = controls.views.parent;
653
654 if ( scrolled >= controls.top ) {
655 if ( ! frame.$el.hasClass('pinned') ) {
656 controls.setWidth();
657 container.css('height', container.height() + 'px' );
658 controls.window.on('resize.wp.revisions.pinning click.wp.revisions.pinning', {controls: controls}, function(e) {
659 e.data.controls.setWidth();
660 });
661 }
662 frame.$el.addClass('pinned');
663 } else if ( frame.$el.hasClass('pinned') ) {
664 controls.window.off('.wp.revisions.pinning');
665 controls.$el.css('width', 'auto');
666 frame.$el.removeClass('pinned');
667 container.css('height', 'auto');
668 controls.top = controls.$el.offset().top;
669 } else {
670 controls.top = controls.$el.offset().top;
671 }
672 });
673 },
674
675 setWidth: function() {
676 this.$el.css('width', this.$el.parent().width() + 'px');
677 }
678 });
679
680 // The tickmarks view.
681 revisions.view.Tickmarks = wp.Backbone.View.extend({
682 className: 'revisions-tickmarks',
683 direction: isRtl ? 'right' : 'left',
684
685 initialize: function() {
686 this.listenTo( this.model, 'change:revision', this.reportTickPosition );
687 },
688
689 reportTickPosition: function( model, revision ) {
690 var offset, thisOffset, parentOffset, tick, index = this.model.revisions.indexOf( revision );
691 thisOffset = this.$el.allOffsets();
692 parentOffset = this.$el.parent().allOffsets();
693 if ( index === this.model.revisions.length - 1 ) {
694 // Last one.
695 offset = {
696 rightPlusWidth: thisOffset.left - parentOffset.left + 1,
697 leftPlusWidth: thisOffset.right - parentOffset.right + 1
698 };
699 } else {
700 // Normal tick.
701 tick = this.$('div:nth-of-type(' + (index + 1) + ')');
702 offset = tick.allPositions();
703 _.extend( offset, {
704 left: offset.left + thisOffset.left - parentOffset.left,
705 right: offset.right + thisOffset.right - parentOffset.right
706 });
707 _.extend( offset, {
708 leftPlusWidth: offset.left + tick.outerWidth(),
709 rightPlusWidth: offset.right + tick.outerWidth()
710 });
711 }
712 this.model.set({ offset: offset });
713 },
714
715 ready: function() {
716 var tickCount, tickWidth;
717 tickCount = this.model.revisions.length - 1;
718 tickWidth = 1 / tickCount;
719 this.$el.css('width', ( this.model.revisions.length * 50 ) + 'px');
720
721 _(tickCount).times( function( index ){
722 this.$el.append( '<div style="' + this.direction + ': ' + ( 100 * tickWidth * index ) + '%"></div>' );
723 }, this );
724 }
725 });
726
727 // The metabox view.
728 revisions.view.Metabox = wp.Backbone.View.extend({
729 className: 'revisions-meta',
730
731 initialize: function() {
732 // Add the 'from' view.
733 this.views.add( new revisions.view.MetaFrom({
734 model: this.model,
735 className: 'diff-meta diff-meta-from'
736 }) );
737
738 // Add the 'to' view.
739 this.views.add( new revisions.view.MetaTo({
740 model: this.model
741 }) );
742 }
743 });
744
745 // The revision meta view (to be extended).
746 revisions.view.Meta = wp.Backbone.View.extend({
747 template: wp.template('revisions-meta'),
748
749 events: {
750 'click .restore-revision': 'restoreRevision'
751 },
752
753 initialize: function() {
754 this.listenTo( this.model, 'update:revisions', this.render );
755 },
756
757 prepare: function() {
758 return _.extend( this.model.toJSON()[this.type] || {}, {
759 type: this.type
760 });
761 },
762
763 restoreRevision: function() {
764 document.location = this.model.get('to').attributes.restoreUrl;
765 }
766 });
767
768 // The revision meta 'from' view.
769 revisions.view.MetaFrom = revisions.view.Meta.extend({
770 className: 'diff-meta diff-meta-from',
771 type: 'from'
772 });
773
774 // The revision meta 'to' view.
775 revisions.view.MetaTo = revisions.view.Meta.extend({
776 className: 'diff-meta diff-meta-to',
777 type: 'to'
778 });
779
780 // The checkbox view.
781 revisions.view.Checkbox = wp.Backbone.View.extend({
782 className: 'revisions-checkbox',
783 template: wp.template('revisions-checkbox'),
784
785 events: {
786 'click .compare-two-revisions': 'compareTwoToggle'
787 },
788
789 initialize: function() {
790 this.listenTo( this.model, 'change:compareTwoMode', this.updateCompareTwoMode );
791 },
792
793 ready: function() {
794 if ( this.model.revisions.length < 3 ) {
795 $('.revision-toggle-compare-mode').hide();
796 }
797 },
798
799 updateCompareTwoMode: function() {
800 this.$('.compare-two-revisions').prop( 'checked', this.model.get('compareTwoMode') );
801 },
802
803 // Toggle the compare two mode feature when the compare two checkbox is checked.
804 compareTwoToggle: function() {
805 // Activate compare two mode?
806 this.model.set({ compareTwoMode: $('.compare-two-revisions').prop('checked') });
807 }
808 });
809
810 // The slider visually hidden help view.
811 revisions.view.SliderHelp = wp.Backbone.View.extend({
812 className: 'revisions-slider-hidden-help',
813 template: wp.template( 'revisions-slider-hidden-help' )
814 });
815
816 // The tooltip view.
817 // Encapsulates the tooltip.
818 revisions.view.Tooltip = wp.Backbone.View.extend({
819 className: 'revisions-tooltip',
820 template: wp.template('revisions-meta'),
821
822 initialize: function() {
823 this.listenTo( this.model, 'change:offset', this.render );
824 this.listenTo( this.model, 'change:hovering', this.toggleVisibility );
825 this.listenTo( this.model, 'change:scrubbing', this.toggleVisibility );
826 },
827
828 prepare: function() {
829 if ( _.isNull( this.model.get('revision') ) ) {
830 return;
831 } else {
832 return _.extend( { type: 'tooltip' }, {
833 attributes: this.model.get('revision').toJSON()
834 });
835 }
836 },
837
838 render: function() {
839 var otherDirection,
840 direction,
841 directionVal,
842 flipped,
843 css = {},
844 position = this.model.revisions.indexOf( this.model.get('revision') ) + 1;
845
846 flipped = ( position / this.model.revisions.length ) > 0.5;
847 if ( isRtl ) {
848 direction = flipped ? 'left' : 'right';
849 directionVal = flipped ? 'leftPlusWidth' : direction;
850 } else {
851 direction = flipped ? 'right' : 'left';
852 directionVal = flipped ? 'rightPlusWidth' : direction;
853 }
854 otherDirection = 'right' === direction ? 'left': 'right';
855 wp.Backbone.View.prototype.render.apply( this, arguments );
856 css[direction] = this.model.get('offset')[directionVal] + 'px';
857 css[otherDirection] = '';
858 this.$el.toggleClass( 'flipped', flipped ).css( css );
859 },
860
861 visible: function() {
862 return this.model.get( 'scrubbing' ) || this.model.get( 'hovering' );
863 },
864
865 toggleVisibility: function() {
866 if ( this.visible() ) {
867 this.$el.stop().show().fadeTo( 100 - this.el.style.opacity * 100, 1 );
868 } else {
869 this.$el.stop().fadeTo( this.el.style.opacity * 300, 0, function(){ $(this).hide(); } );
870 }
871 return;
872 }
873 });
874
875 // The buttons view.
876 // Encapsulates all of the configuration for the previous/next buttons.
877 revisions.view.Buttons = wp.Backbone.View.extend({
878 className: 'revisions-buttons',
879 template: wp.template('revisions-buttons'),
880
881 events: {
882 'click .revisions-next .button': 'nextRevision',
883 'click .revisions-previous .button': 'previousRevision'
884 },
885
886 initialize: function() {
887 this.listenTo( this.model, 'update:revisions', this.disabledButtonCheck );
888 },
889
890 ready: function() {
891 this.disabledButtonCheck();
892 },
893
894 // Go to a specific model index.
895 gotoModel: function( toIndex ) {
896 var attributes = {
897 to: this.model.revisions.at( toIndex )
898 };
899 // If we're at the first revision, unset 'from'.
900 if ( toIndex ) {
901 attributes.from = this.model.revisions.at( toIndex - 1 );
902 } else {
903 this.model.unset('from', { silent: true });
904 }
905
906 this.model.set( attributes );
907 },
908
909 // Go to the 'next' revision.
910 nextRevision: function() {
911 var toIndex = this.model.revisions.indexOf( this.model.get('to') ) + 1;
912 this.gotoModel( toIndex );
913 },
914
915 // Go to the 'previous' revision.
916 previousRevision: function() {
917 var toIndex = this.model.revisions.indexOf( this.model.get('to') ) - 1;
918 this.gotoModel( toIndex );
919 },
920
921 // Check to see if the Previous or Next buttons need to be disabled or enabled.
922 disabledButtonCheck: function() {
923 var maxVal = this.model.revisions.length - 1,
924 minVal = 0,
925 next = $('.revisions-next .button'),
926 previous = $('.revisions-previous .button'),
927 val = this.model.revisions.indexOf( this.model.get('to') );
928
929 // Disable "Next" button if you're on the last node.
930 next.prop( 'disabled', ( maxVal === val ) );
931
932 // Disable "Previous" button if you're on the first node.
933 previous.prop( 'disabled', ( minVal === val ) );
934 }
935 });
936
937
938 // The slider view.
939 revisions.view.Slider = wp.Backbone.View.extend({
940 className: 'wp-slider',
941 direction: isRtl ? 'right' : 'left',
942
943 events: {
944 'mousemove' : 'mouseMove'
945 },
946
947 initialize: function() {
948 _.bindAll( this, 'start', 'slide', 'stop', 'mouseMove', 'mouseEnter', 'mouseLeave' );
949 this.listenTo( this.model, 'update:slider', this.applySliderSettings );
950 },
951
952 ready: function() {
953 this.$el.css('width', ( this.model.revisions.length * 50 ) + 'px');
954 this.$el.slider( _.extend( this.model.toJSON(), {
955 start: this.start,
956 slide: this.slide,
957 stop: this.stop
958 }) );
959
960 this.$el.hoverIntent({
961 over: this.mouseEnter,
962 out: this.mouseLeave,
963 timeout: 800
964 });
965
966 this.applySliderSettings();
967 },
968
969 accessibilityHelper: function() {
970 var handles = $( '.ui-slider-handle' );
971 handles.first().attr( {
972 role: 'button',
973 'aria-labelledby': 'diff-title-from diff-title-author',
974 'aria-describedby': 'revisions-slider-hidden-help',
975 } );
976 handles.last().attr( {
977 role: 'button',
978 'aria-labelledby': 'diff-title-to diff-title-author',
979 'aria-describedby': 'revisions-slider-hidden-help',
980 } );
981 },
982
983 mouseMove: function( e ) {
984 var zoneCount = this.model.revisions.length - 1, // One fewer zone than models.
985 sliderFrom = this.$el.allOffsets()[this.direction], // "From" edge of slider.
986 sliderWidth = this.$el.width(), // Width of slider.
987 tickWidth = sliderWidth / zoneCount, // Calculated width of zone.
988 actualX = ( isRtl ? $(window).width() - e.pageX : e.pageX ) - sliderFrom, // Flipped for RTL - sliderFrom.
989 currentModelIndex = Math.floor( ( actualX + ( tickWidth / 2 ) ) / tickWidth ); // Calculate the model index.
990
991 // Ensure sane value for currentModelIndex.
992 if ( currentModelIndex < 0 ) {
993 currentModelIndex = 0;
994 } else if ( currentModelIndex >= this.model.revisions.length ) {
995 currentModelIndex = this.model.revisions.length - 1;
996 }
997
998 // Update the tooltip mode.
999 this.model.set({ hoveredRevision: this.model.revisions.at( currentModelIndex ) });
1000 },
1001
1002 mouseLeave: function() {
1003 this.model.set({ hovering: false });
1004 },
1005
1006 mouseEnter: function() {
1007 this.model.set({ hovering: true });
1008 },
1009
1010 applySliderSettings: function() {
1011 this.$el.slider( _.pick( this.model.toJSON(), 'value', 'values', 'range' ) );
1012 var handles = this.$('a.ui-slider-handle');
1013
1014 if ( this.model.get('compareTwoMode') ) {
1015 // In RTL mode the 'left handle' is the second in the slider, 'right' is first.
1016 handles.first()
1017 .toggleClass( 'to-handle', !! isRtl )
1018 .toggleClass( 'from-handle', ! isRtl );
1019 handles.last()
1020 .toggleClass( 'from-handle', !! isRtl )
1021 .toggleClass( 'to-handle', ! isRtl );
1022 this.accessibilityHelper();
1023 } else {
1024 handles.removeClass('from-handle to-handle');
1025 this.accessibilityHelper();
1026 }
1027
1028 },
1029
1030 start: function( event, ui ) {
1031 this.model.set({ scrubbing: true });
1032
1033 // Track the mouse position to enable smooth dragging,
1034 // overrides default jQuery UI step behavior.
1035 $( window ).on( 'mousemove.wp.revisions', { view: this }, function( e ) {
1036 var handles,
1037 view = e.data.view,
1038 leftDragBoundary = view.$el.offset().left,
1039 sliderOffset = leftDragBoundary,
1040 sliderRightEdge = leftDragBoundary + view.$el.width(),
1041 rightDragBoundary = sliderRightEdge,
1042 leftDragReset = '0',
1043 rightDragReset = '100%',
1044 handle = $( ui.handle );
1045
1046 // In two handle mode, ensure handles can't be dragged past each other.
1047 // Adjust left/right boundaries and reset points.
1048 if ( view.model.get('compareTwoMode') ) {
1049 handles = handle.parent().find('.ui-slider-handle');
1050 if ( handle.is( handles.first() ) ) {
1051 // We're the left handle.
1052 rightDragBoundary = handles.last().offset().left;
1053 rightDragReset = rightDragBoundary - sliderOffset;
1054 } else {
1055 // We're the right handle.
1056 leftDragBoundary = handles.first().offset().left + handles.first().width();
1057 leftDragReset = leftDragBoundary - sliderOffset;
1058 }
1059 }
1060
1061 // Follow mouse movements, as long as handle remains inside slider.
1062 if ( e.pageX < leftDragBoundary ) {
1063 handle.css( 'left', leftDragReset ); // Mouse to left of slider.
1064 } else if ( e.pageX > rightDragBoundary ) {
1065 handle.css( 'left', rightDragReset ); // Mouse to right of slider.
1066 } else {
1067 handle.css( 'left', e.pageX - sliderOffset ); // Mouse in slider.
1068 }
1069 } );
1070 },
1071
1072 getPosition: function( position ) {
1073 return isRtl ? this.model.revisions.length - position - 1: position;
1074 },
1075
1076 // Responds to slide events.
1077 slide: function( event, ui ) {
1078 var attributes, movedRevision;
1079 // Compare two revisions mode.
1080 if ( this.model.get('compareTwoMode') ) {
1081 // Prevent sliders from occupying same spot.
1082 if ( ui.values[1] === ui.values[0] ) {
1083 return false;
1084 }
1085 if ( isRtl ) {
1086 ui.values.reverse();
1087 }
1088 attributes = {
1089 from: this.model.revisions.at( this.getPosition( ui.values[0] ) ),
1090 to: this.model.revisions.at( this.getPosition( ui.values[1] ) )
1091 };
1092 } else {
1093 attributes = {
1094 to: this.model.revisions.at( this.getPosition( ui.value ) )
1095 };
1096 // If we're at the first revision, unset 'from'.
1097 if ( this.getPosition( ui.value ) > 0 ) {
1098 attributes.from = this.model.revisions.at( this.getPosition( ui.value ) - 1 );
1099 } else {
1100 attributes.from = undefined;
1101 }
1102 }
1103 movedRevision = this.model.revisions.at( this.getPosition( ui.value ) );
1104
1105 // If we are scrubbing, a scrub to a revision is considered a hover.
1106 if ( this.model.get('scrubbing') ) {
1107 attributes.hoveredRevision = movedRevision;
1108 }
1109
1110 this.model.set( attributes );
1111 },
1112
1113 stop: function() {
1114 $( window ).off('mousemove.wp.revisions');
1115 this.model.updateSliderSettings(); // To snap us back to a tick mark.
1116 this.model.set({ scrubbing: false });
1117 }
1118 });
1119
1120 // The diff view.
1121 // This is the view for the current active diff.
1122 revisions.view.Diff = wp.Backbone.View.extend({
1123 className: 'revisions-diff',
1124 template: wp.template('revisions-diff'),
1125
1126 // Generate the options to be passed to the template.
1127 prepare: function() {
1128 return _.extend({ fields: this.model.fields.toJSON() }, this.options );
1129 }
1130 });
1131
1132 // The revisions router.
1133 // Maintains the URL routes so browser URL matches state.
1134 revisions.Router = Backbone.Router.extend({
1135 initialize: function( options ) {
1136 this.model = options.model;
1137
1138 // Maintain state and history when navigating.
1139 this.listenTo( this.model, 'update:diff', _.debounce( this.updateUrl, 250 ) );
1140 this.listenTo( this.model, 'change:compareTwoMode', this.updateUrl );
1141 },
1142
1143 baseUrl: function( url ) {
1144 return this.model.get('baseUrl') + url;
1145 },
1146
1147 updateUrl: function() {
1148 var from = this.model.has('from') ? this.model.get('from').id : 0,
1149 to = this.model.get('to').id;
1150 if ( this.model.get('compareTwoMode' ) ) {
1151 this.navigate( this.baseUrl( '?from=' + from + '&to=' + to ), { replace: true } );
1152 } else {
1153 this.navigate( this.baseUrl( '?revision=' + to ), { replace: true } );
1154 }
1155 },
1156
1157 handleRoute: function( a, b ) {
1158 var compareTwo = _.isUndefined( b );
1159
1160 if ( ! compareTwo ) {
1161 b = this.model.revisions.get( a );
1162 a = this.model.revisions.prev( b );
1163 b = b ? b.id : 0;
1164 a = a ? a.id : 0;
1165 }
1166 }
1167 });
1168
1169 /**
1170 * Initialize the revisions UI for revision.php.
1171 */
1172 revisions.init = function() {
1173 var state;
1174
1175 // Bail if the current page is not revision.php.
1176 if ( ! window.adminpage || 'revision-php' !== window.adminpage ) {
1177 return;
1178 }
1179
1180 state = new revisions.model.FrameState({
1181 initialDiffState: {
1182 // wp_localize_script doesn't stringifies ints, so cast them.
1183 to: parseInt( revisions.settings.to, 10 ),
1184 from: parseInt( revisions.settings.from, 10 ),
1185 // wp_localize_script does not allow for top-level booleans so do a comparator here.
1186 compareTwoMode: ( revisions.settings.compareTwoMode === '1' )
1187 },
1188 diffData: revisions.settings.diffData,
1189 baseUrl: revisions.settings.baseUrl,
1190 postId: parseInt( revisions.settings.postId, 10 )
1191 }, {
1192 revisions: new revisions.model.Revisions( revisions.settings.revisionData )
1193 });
1194
1195 revisions.view.frame = new revisions.view.Frame({
1196 model: state
1197 }).render();
1198 };
1199
1200 $( revisions.init );
1201}(jQuery));
1202
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1