Revisions: Re-work how tick marks and tooltips are aligned. IE fixes.

* Pixel-based alignment of tooltips.
* Bottom-based alignment, so arrow lines up using CSS only.
* Better RTL styles (mostly mirror-imaged).
* Better RTL calculations in `revisions.js` (less logic).
* Better IE support.

See #24736. Props markjaquith, adamsilverstein, ocean90.

git-svn-id: http://core.svn.wordpress.org/trunk@24751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Mark Jaquith 2013-07-19 13:49:15 +00:00
parent 924ee94b0b
commit 65b08eeece
7 changed files with 190 additions and 134 deletions

View File

@ -1486,7 +1486,7 @@ table.diff .diff-addedline ins {
}
.revisions-tooltip,
.revisions-tooltip-arrow:after {
.revisions-tooltip-arrow span {
border-color: #d1e5ee;
background-color: #fff;
}

View File

@ -1380,16 +1380,11 @@ table.diff .diff-addedline ins {
}
.revisions-tooltip,
.revisions-tooltip-arrow:after {
.revisions-tooltip-arrow span {
border-color: #d7d7d7;
background-color: #fff;
}
.revisions-tickmarks {
background-color: #f7f7f7;
}
.revisions-tickmarks > div {
border-color: #aaa;
}

View File

@ -630,3 +630,16 @@ table.ie-fixed {
* html #adminmenu div.wp-menu-image {
height: 29px;
}
/* Revisions */
.revisions-tooltip-arrow span {
left: 25px;
top: -24px;
filter: progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476); /* IE7 */
}
.revisions-controls .revisions-tickmarks > div {
margin-right: -1px;
border-width: 0 0 0 0;
border-style: none;
}

View File

@ -954,18 +954,18 @@ th.sorted a span {
/*------------------------------------------------------------------------------
11.2 - Post Revisions
------------------------------------------------------------------------------*/
.wp-slider .ui-slider-handle.left-handle:before,
.wp-slider .ui-slider-handle.right-handle:before {
.wp-slider .ui-slider-handle.from-handle:before,
.wp-slider .ui-slider-handle.to-handle:before {
height: 8px;
width: 7px;
}
.wp-slider .ui-slider-handle.left-handle:before {
.wp-slider .ui-slider-handle.from-handle:before {
background-position: -5px -10px;
left: 6px;
}
.wp-slider .ui-slider-handle.right-handle:before {
.wp-slider .ui-slider-handle.to-handle:before {
background-position: -4px -29px;
left: 6px;
}
@ -1025,8 +1025,8 @@ th.sorted a span {
}
.revisions-tooltip {
margin-right: -73px;
margin-left: 0;
margin-right: -70px;
-webkit-transition: right 15ms;
-moz-transition: right 15ms;
-ms-transition: right 15ms;
@ -1034,17 +1034,30 @@ th.sorted a span {
transition: right 15ms;
}
.ie8 .revisions-tooltip {
margin-right: -75px;
}
.revisions-tooltip-arrow {
right: 0;
margin-left: 0;
margin-right: 35px;
}
.revisions-tooltip-image {
.revisions-tooltip-arrow > span {
right: 20px;
}
.revisions-tooltip img {
float: right;
margin: 2px 0 0 5px;
}
.revisions-tickmarks > div {
float: right;
border-width: 0 0 0 1px;
}
/*------------------------------------------------------------------------------
11.3 - Featured Images
------------------------------------------------------------------------------*/

View File

@ -3511,10 +3511,6 @@ td.plugin-title p {
/*------------------------------------------------------------------------------
11.2 - Post Revisions
------------------------------------------------------------------------------*/
body.revision-php {
overflow-y: scroll; /* Force a scrollbar, so centering doesn't jump */
}
.revisions-control-frame,
.revisions-diff-frame {
position: relative;
@ -3533,14 +3529,14 @@ body.revision-php {
.revisions-tickmarks {
position: relative;
margin: 0 auto 0;
margin: 0 auto;
height: 0.8em;
z-index: 2;
top: 7px;
width: 70%;
width: 100%;
padding: 0 15%;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box; /* ie8 only */
box-sizing: border-box;
}
@ -3548,17 +3544,16 @@ body.revision-php {
position: relative;
height: 100%;
float: left;
z-index: 10002;
z-index: 3;
border-style: solid;
border-width: 0 0 0 1px;
border-width: 0 1px 0 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box; /* ie8 only */
box-sizing: border-box;
}
.revisions-tickmarks > div:first-of-type {
border-left-width: 0;
.revisions-tickmarks > div:last-child {
border-width: 0;
}
.comparing-two-revisions .revisions-controls {
@ -3588,6 +3583,7 @@ body.revision-php {
-ms-transition: opacity 0.5s;
-o-transition: opacity 0.5s;
transition: opacity 0.5s;
filter: alpha(opacity=0); /* ie8 and earlier */
}
.revisions .loading-indicator span.spinner {
@ -3598,6 +3594,7 @@ body.revision-php {
.revisions.loading .loading-indicator {
opacity: 1;
filter: alpha(opacity=100); /* ie8 and earlier */
}
.revisions .diff {
@ -3610,6 +3607,7 @@ body.revision-php {
.revisions.loading .diff {
opacity: 0.5;
filter: alpha(opacity=50); /* ie8 and earlier */
}
.revisions.diff-error .diff {
@ -3631,6 +3629,12 @@ body.revision-php {
display: none;
}
.revisions-previous,
.revisions-next {
position: relative;
z-index: 4;
}
.revisions-previous {
float: left;
}
@ -3641,7 +3645,7 @@ body.revision-php {
.wp-slider {
width: 70%;
margin: 0 auto 0;
margin: 0 auto;
top: -3px;
}
@ -3736,7 +3740,8 @@ table.diff .diff-addedline ins {
.revisions-tooltip {
position: absolute;
bottom: 105px;
margin-left: -69px;
margin-right: 0;
margin-left: -70px;
line-height: 28px;
z-index: 9999;
max-width: 350px;
@ -3773,7 +3778,7 @@ table.diff .diff-addedline ins {
z-index: 10000;
}
.revisions-tooltip-arrow:after {
.revisions-tooltip-arrow > span {
content: "";
position: absolute;
left: 20px;
@ -3787,8 +3792,14 @@ table.diff .diff-addedline ins {
tranform: rotate(45deg);
}
.ie8 .revisions-tooltip-arrow > span {
left: 14px;
top: -25px;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"; /* IE8 */
}
.revisions-tooltip,
.revisions-tooltip-arrow:after {
.revisions-tooltip-arrow > span {
border-width: 1px;
border-style: solid;
}
@ -3828,18 +3839,18 @@ div.revisions-controls > .wp-slider > .ui-slider-handle {
background: url(../images/arrows-pr.png) no-repeat -2px -47px;
}
.wp-slider .ui-slider-handle.left-handle:before,
.wp-slider .ui-slider-handle.right-handle:before {
.wp-slider .ui-slider-handle.from-handle:before,
.wp-slider .ui-slider-handle.to-handle:before {
height: 8px;
width: 7px;
}
.wp-slider .ui-slider-handle.left-handle:before {
.wp-slider .ui-slider-handle.from-handle:before {
background-position: -5px -84px;
left: 7px;
}
.wp-slider .ui-slider-handle.right-handle:before {
.wp-slider .ui-slider-handle.to-handle:before {
background-position: -4px -65px;
left: 5px;
}

View File

@ -16,6 +16,23 @@ window.wp = window.wp || {};
console.log.apply( console, arguments );
};
// Handy functions to help with positioning
$.fn.allOffsets = function() {
var offset = this.offset() || {top: 0, left: 0}, win = $(window);
return _.extend( offset, {
right: win.width() - offset.left - this.outerWidth(),
bottom: win.height() - offset.top - this.outerHeight()
});
};
$.fn.allPositions = function() {
var position = this.position() || {top: 0, left: 0}, parent = this.parent();
return _.extend( position, {
right: parent.outerWidth() - position.left - this.outerWidth(),
bottom: parent.outerHeight() - position.top - this.outerHeight()
});
};
// wp_localize_script transforms top-level numbers into strings. Undo that.
if ( revisions.settings.to )
revisions.settings.to = parseInt( revisions.settings.to, 10 );
@ -125,19 +142,24 @@ window.wp = window.wp || {};
revisions.model.Tooltip = Backbone.Model.extend({
defaults: {
revision: null,
offset: {},
hovering: false, // Whether the mouse is hovering
scrubbing: false // Whether the mouse is scrubbing
},
initialize: function( options ) {
this.frame = options.frame;
this.revisions = options.revisions;
this.slider = options.slider;
this.listenTo( this.slider, 'hovered:revision', this.updateRevision );
this.listenTo( this.slider, 'change:hovering', this.setHovering );
this.listenTo( this.slider, 'change:scrubbing', this.setScrubbing );
this.set({ revision: this.frame.diff() });
},
updateRevision: function( revision ) {
this.set({ revision: revision });
},
@ -475,6 +497,7 @@ window.wp = window.wp || {};
render: function() {
wp.Backbone.View.prototype.render.apply( this, arguments );
$('html').css( 'overflow-y', 'scroll' );
$('#wpbody-content .wrap').append( this.el );
this.updateCompareTwoMode();
this.renderDiff( this.model.diff() );
@ -524,17 +547,21 @@ window.wp = window.wp || {};
revisions: this.model.revisions
});
// Prep the tooltip model
var tooltip = new revisions.model.Tooltip({
frame: this.model,
revisions: this.model.revisions,
slider: slider
});
// Add the tooltip view
this.views.add( new revisions.view.Tooltip({
model: new revisions.model.Tooltip({
revisions: this.model.revisions,
slider: slider
})
model: tooltip
}) );
// Add the tickmarks view
this.views.add( new revisions.view.Tickmarks({
model: this.model
model: tooltip
}) );
// Add the slider view
@ -554,12 +581,37 @@ window.wp = window.wp || {};
revisions.view.Tickmarks = wp.Backbone.View.extend({
className: 'revisions-tickmarks',
initialize: function() {
this.listenTo( this.model, 'change:revision', this.reportTickPosition );
},
reportTickPosition: function( model, revision ) {
var elWidth, offset, tick, index = this.model.revisions.indexOf( revision );
if ( index === this.model.revisions.length - 1 ) {
// Last one
tick = this.$('div:nth-of-type(' + index + ')');
offset = tick.allPositions();
elWidth = tick.outerWidth();
// adjust
_.extend( offset, {
right: offset.right + elWidth + 1,
left: offset.left + elWidth + 1
});
} else {
// Normal tick
tick = this.$('div:nth-of-type(' + (index + 1) + ')');
offset = tick.allPositions();
}
this.model.set({ offset: offset });
},
ready: function() {
var tickCount, tickWidth;
tickCount = this.model.revisions.length - 1;
tickWidth = 1 / tickCount;
_(tickCount).times( function(){ this.$el.append( '<div></div>' ); }, this );
this.$('div').css( 'width', ( 100 * tickWidth ) + '%' );
}
});
@ -625,13 +677,25 @@ window.wp = window.wp || {};
revisions.view.Tooltip = wp.Backbone.View.extend({
className: 'revisions-tooltip',
template: wp.template('revisions-tooltip'),
direction: isRtl ? 'right' : 'left',
initialize: function( options ) {
this.listenTo( this.model, 'change:revision', this.render );
this.listenTo( this.model, 'change:offset', this.render );
this.listenTo( this.model, 'change:hovering', this.toggleVisibility );
this.listenTo( this.model, 'change:scrubbing', this.toggleVisibility );
},
prepare: function() {
return this.model.get('revision').toJSON();
},
render: function() {
var css = {};
wp.Backbone.View.prototype.render.apply( this, arguments );
css[this.direction] = this.model.get('offset')[this.direction] + 'px';
this.$el.css( css );
},
visible: function() {
return this.model.get( 'scrubbing' ) || this.model.get( 'hovering' );
},
@ -642,23 +706,6 @@ window.wp = window.wp || {};
else
this.$el.stop().fadeTo( this.el.style.opacity * 300, 0, function(){ $(this).hide(); } );
return;
},
render: function() {
var offset;
// Check if a revision exists.
if ( _.isNull( this.model.get('revision') ) )
return;
this.$el.html( this.template( this.model.get('revision').toJSON() ) );
// Set the position.
offset = this.model.revisions.indexOf( this.model.get('revision') ) / ( this.model.revisions.length - 1 );
// 15% to get us to the start of the slider
// 0.7 to convert the slider-relative percentage to a page-relative percentage
// 100 to convert to a percentage
offset = 15 + (0.7 * offset * 100 ); // Now in a percentage
this.$el.css( isRtl ? 'right' : 'left', offset + '%' );
}
});
@ -681,31 +728,29 @@ window.wp = window.wp || {};
this.disabledButtonCheck();
},
// Go to a specific modelindex, taking into account RTL mode.
// Go to a specific model index
gotoModel: function( toIndex ) {
var attributes = {
to: this.model.revisions.at( isRtl ? this.model.revisions.length - toIndex - 1 : toIndex ) // Reverse directions for RTL.
to: this.model.revisions.at( toIndex )
};
// If we're at the first revision, unset 'from'.
if ( isRtl ? this.model.revisions.length - toIndex - 1 : toIndex ) // Reverse directions for RTL
attributes.from = this.model.revisions.at( isRtl ? this.model.revisions.length - toIndex - 2 : toIndex - 1 );
if ( toIndex )
attributes.from = this.model.revisions.at( toIndex - 1 );
else
this.model.unset('from', { silent: true });
this.model.set( attributes );
},
// Go to the 'next' revision, direction takes into account RTL mode.
// Go to the 'next' revision
nextRevision: function() {
var toIndex = isRtl ? this.model.revisions.length - this.model.revisions.indexOf( this.model.get('to') ) - 1 : this.model.revisions.indexOf( this.model.get('to') );
toIndex = isRtl ? toIndex - 1 : toIndex + 1;
var toIndex = this.model.revisions.indexOf( this.model.get('to') ) + 1;
this.gotoModel( toIndex );
},
// Go to the 'previous' revision, direction takes into account RTL mode.
// Go to the 'previous' revision
previousRevision: function() {
var toIndex = isRtl ? this.model.revisions.length - this.model.revisions.indexOf( this.model.get('to') ) - 1 : this.model.revisions.indexOf( this.model.get('to') );
toIndex = isRtl ? toIndex + 1 : toIndex - 1;
var toIndex = this.model.revisions.indexOf( this.model.get('to') ) - 1;
this.gotoModel( toIndex );
},
@ -729,6 +774,7 @@ window.wp = window.wp || {};
// The slider view.
revisions.view.Slider = wp.Backbone.View.extend({
className: 'wp-slider',
direction: isRtl ? 'right' : 'left',
events: {
'mousemove' : 'mouseMove'
@ -757,15 +803,12 @@ window.wp = window.wp || {};
mouseMove: function( e ) {
var zoneCount = this.model.revisions.length - 1, // One fewer zone than models
sliderLeft = this.$el.offset().left, // Left edge of slider
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 = e.clientX - sliderLeft, // Offset of mouse position in slider
currentModelIndex = Math.floor( ( actualX + ( tickWidth / 2 ) ) / tickWidth ); // Calculate the model index
// Reverse direction in RTL mode.
if ( isRtl )
currentModelIndex = this.model.revisions.length - currentModelIndex - 1;
actualX = isRtl? $(window).width() - e.pageX : e.pageX; // Flipped for RTL - sliderFrom;
actualX = actualX - sliderFrom; // Offset of mouse position in slider
var currentModelIndex = Math.floor( ( actualX + ( tickWidth / 2 ) ) / tickWidth ); // Calculate the model index
// Ensure sane value for currentModelIndex.
if ( currentModelIndex < 0 )
@ -773,7 +816,7 @@ window.wp = window.wp || {};
else if ( currentModelIndex >= this.model.revisions.length )
currentModelIndex = this.model.revisions.length - 1;
// Update the tooltip model
// Update the tooltip mode
this.model.set({ hoveredRevision: this.model.revisions.at( currentModelIndex ) });
},
@ -792,103 +835,84 @@ window.wp = window.wp || {};
if ( this.model.get('compareTwoMode') ) {
// in RTL mode the 'left handle' is the second in the slider, 'right' is first
handles.first()
.toggleClass( 'right-handle', !! isRtl )
.toggleClass( 'left-handle', ! isRtl );
.toggleClass( 'to-handle', !! isRtl )
.toggleClass( 'from-handle', ! isRtl );
handles.last()
.toggleClass( 'left-handle', !! isRtl )
.toggleClass( 'right-handle', ! isRtl );
.toggleClass( 'from-handle', !! isRtl )
.toggleClass( 'to-handle', ! isRtl );
} else {
handles.removeClass('left-handle right-handle');
handles.removeClass('from-handle to-handle');
}
},
getSliderPosition: function( ui ){
return isRtl ? this.model.revisions.length - ui.value - 1 : ui.value;
},
start: function( event, ui ) {
this.model.set({ scrubbing: true });
// Track the mouse position to enable smooth dragging,
// overrides default jQuery UI step behavior.
$( window ).on( 'mousemove.wp.revisions', { view: this }, function( e ) {
var view = e.data.view,
leftDragBoundary = view.$el.offset().left, // Initial left boundary
sliderOffset = leftDragBoundary,
sliderRightEdge = leftDragBoundary + view.$el.width(),
rightDragBoundary = sliderRightEdge, // Initial right boundary
leftDragReset = 0, // Initial left drag reset
rightDragReset = sliderRightEdge - sliderOffset; // Initial right drag reset
var 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') ) {
var rightHandle = $( ui.handle ).parent().find('.right-handle'),
leftHandle = $( ui.handle ).parent().find('.left-handle');
if ( $( ui.handle ).hasClass('left-handle') ) {
// Dragging the left handle, boundary is right handle.
// RTL mode calculations reverse directions.
if ( isRtl ) {
leftDragBoundary = rightHandle.offset().left + rightHandle.width();
leftDragReset = leftDragBoundary - sliderOffset;
} else {
rightDragBoundary = rightHandle.offset().left;
rightDragReset = rightDragBoundary - sliderOffset;
}
} else {
// Dragging the right handle, boundary is the left handle.
// RTL mode calculations reverse directions.
if ( isRtl ) {
rightDragBoundary = leftHandle.offset().left;
rightDragReset = rightDragBoundary - sliderOffset;
} else {
leftDragBoundary = leftHandle.offset().left + leftHandle.width() ;
leftDragReset = leftDragBoundary - sliderOffset;
}
var handles = handle.parent().find('.ui-slider-handle');
if ( handle.is( handles.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.clientX < leftDragBoundary ) {
$( ui.handle ).css( 'left', leftDragReset ); // Mouse to left of slider.
} else if ( e.clientX > rightDragBoundary ) {
$( ui.handle ).css( 'left', rightDragReset ); // Mouse to right of 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 {
$( ui.handle ).css( 'left', e.clientX - sliderOffset ); // Mouse in slider.
handle.css( 'left', e.pageX - sliderOffset ); // Mouse in slider.
}
} );
},
getPosition: function( position ) {
return isRtl ? this.model.revisions.length - position - 1: position;
},
// Responds to slide events
slide: function( event, ui ) {
var attributes, movedRevision, sliderPosition;
var attributes, movedRevision;
// Compare two revisions mode
if ( this.model.get('compareTwoMode') ) {
// Prevent sliders from occupying same spot
if ( ui.values[1] === ui.values[0] )
return false;
attributes = {
to: this.model.revisions.at( isRtl ? this.model.revisions.length - ui.values[0] - 1 : ui.values[1] ),
from: this.model.revisions.at( isRtl ? this.model.revisions.length - ui.values[1] - 1 : ui.values[0] )
};
if ( isRtl )
movedRevision = ui.value === ui.values[1] ? attributes.from : attributes.to;
else
movedRevision = ui.value === ui.values[0] ? attributes.from : attributes.to;
} else {
sliderPosition = this.getSliderPosition( ui );
ui.values.reverse();
attributes = {
to: this.model.revisions.at( sliderPosition )
from: this.model.revisions.at( this.getPosition( ui.values[0] ) ),
to: this.model.revisions.at( this.getPosition( ui.values[1] ) )
};
} else {
attributes = {
to: this.model.revisions.at( this.getPosition( ui.value ) )
};
movedRevision = attributes.to;
// If we're at the first revision, unset 'from'.
if ( sliderPosition ) // Reverse directions for RTL.
attributes.from = this.model.revisions.at( sliderPosition - 1 );
if ( this.getPosition( ui.value ) > 0 )
attributes.from = this.model.revisions.at( this.getPosition( ui.value ) - 1 );
else
attributes.from = undefined;
}
movedRevision = this.model.revisions.at( this.getPosition( ui.value ) );
// If we are scrubbing, a scrub to a revision is considered a hover
if ( this.model.get('scrubbing') )

View File

@ -138,7 +138,7 @@ require_once( './admin-header.php' );
({{ data.dateShort }})
<# } #>
</div>
<div class="revisions-tooltip-arrow"></div>
<div class="revisions-tooltip-arrow"><span></span></div>
</script>
<script id="tmpl-revisions-checkbox" type="text/html">