RTL Improvements

Objectives:

* Make option widget icons correctly placed in RTL
* Make embedded context toolbar correctly placed in RTL

Approach:

Use separate elements for icons within option widgets which have more
flexibility when rendering in either LTR or RTL when compared to CSS
background position. The simpler approach, using CSS background
position offsets, isn't cross-browser compatible at this time.

Changes:

ve.ui.OutlineItemWidget.js
* Remove custom icon implementation, using parent class implementation
  instead

ve.ui.OptionWidget.js
* Add icon option, which adds an icon element only if an icon was
  specified

ve.ui.MenuItemWidget.js, ve-mw/ve.ui.MWParameterResultWidget.js
* Add override for icon config option
* Document icon config as private

ve.ui.Context.js
* Add detection and special handling for positioning embedded context
  toolbar when rendering in RTL

ve.ui.Widget.css
* Add styles for option widget's new icon option
* Add styles to make indentation still work for outline item widgets
* Adjust styles for menu item widget as per changes in option widget

ve-mw/ve.ui.Widget.css
* Adjust styles for parameter result widget as per changes in option
  widget

Change-Id: Ibfa4b613e0fd7902f8a2c78b5717de402c5f82b8
This commit is contained in:
Trevor Parscal 2013-07-09 15:48:08 -07:00 committed by Catrope
parent e9ca44c86c
commit 3a6e91dfb7
7 changed files with 82 additions and 25 deletions

View file

@ -291,8 +291,11 @@
.ve-ui-mwParameterResultWidget {
padding-right: 0.25em;
background-position: 0.5em 0.25em;
background-repeat: no-repeat;
}
.ve-ui-mwParameterResultWidget .ve-ui-optionWidget-icon {
top: 0.25em;
margin-top: 0;
}
.ve-ui-mwParameterResultWidget.ve-ui-widget-disabled {

View file

@ -16,14 +16,22 @@
* @param {Object} [config] Config options
*/
ve.ui.MWParameterResultWidget = function VeUiMWParameterResultWidget( data, config ) {
// Configuration initialization
config = ve.extendObject( {}, config, { 'icon': 'parameter' } );
// Parent constructor
ve.ui.OptionWidget.call( this, data, config );
// Initialization
this.$.addClass( 've-ui-mwParameterResultWidget ve-ui-icon-parameter' );
this.$.addClass( 've-ui-mwParameterResultWidget' );
this.setLabel( this.buildLabel() );
};
/**
* @private
* @cfg {string} icon
*/
/* Inheritance */
ve.inheritClass( ve.ui.MWParameterResultWidget, ve.ui.OptionWidget );

View file

@ -182,9 +182,21 @@
cursor: default;
}
.ve-ui-optionWidget .ve-ui-optionWidget-icon {
position: absolute;
top: 50%;
left: 0.5em;
width: 2em;
height: 2em;
margin-top: -1em;
background-repeat: no-repeat;
background-position: center center;
}
/* ve.ui.OutlineItemWidget */
.ve-ui-outlineItemWidget {
position: relative;
padding: 1.25em 1.25em 1.25em 3.5em;
background-position: 1em center;
background-repeat: no-repeat;
@ -211,6 +223,18 @@
text-shadow: 0 1px 1px rgba(255,255,255,0.5);
}
.ve-ui-outlineItemWidget-level-0 .ve-ui-optionWidget-icon {
left: 1em;
}
.ve-ui-outlineItemWidget-level-1 .ve-ui-optionWidget-icon {
left: 3em;
}
.ve-ui-outlineItemWidget-level-2 .ve-ui-optionWidget-icon {
left: 5em;
}
/* ve.ui.OutlineControlsWidget */
.ve-ui-outlineControlsWidget {
@ -360,8 +384,19 @@
/* ve.ui.MenuItemWidget */
.ve-ui-menuItemWidget {
background-position: 1em center;
background-repeat: no-repeat;
position: relative;
}
.ve-ui-menuItemWidget.ve-ui-optionWidget-selected:not(.ve-ui-optionWidget-highlighted) {
background-color: transparent;
}
.ve-ui-menuItemWidget .ve-ui-optionWidget-icon {
display: none;
}
.ve-ui-menuItemWidget.ve-ui-optionWidget-selected .ve-ui-optionWidget-icon {
display: block;
}
/* ve.ui.MenuSectionItemWidget */

View file

@ -260,8 +260,15 @@ ve.ui.Context.prototype.updateDimensions = function ( transition ) {
);
focusableWidth = focusedNode.$focusable.outerWidth();
$container = this.$menu;
position = { 'x': focusableOffset.left + focusableWidth, 'y': focusableOffset.top };
this.popup.align = 'right';
position = { 'y': focusableOffset.top };
// HACK: Proper RTL detection plz!
if ( $( 'body' ).is( '.rtl,.ve-rtl' ) ) {
position.x = focusableOffset.left;
this.popup.align = 'left';
} else {
position.x = focusableOffset.left + focusableWidth;
this.popup.align = 'right';
}
} else {
$container = inspector ? this.inspectors.$ : this.$menu;
this.popup.align = 'center';

View file

@ -16,6 +16,9 @@
* @param {Object} [config] Config options
*/
ve.ui.MenuItemWidget = function VeUiMenuItemWidget( data, config ) {
// Configuration initialization
config = ve.extendObject( {}, config, { 'icon': 'check' } );
// Parent constructor
ve.ui.OptionWidget.call( this, data, config );
@ -23,10 +26,11 @@ ve.ui.MenuItemWidget = function VeUiMenuItemWidget( data, config ) {
this.$.addClass( 've-ui-menuItemWidget' );
};
/**
* @private
* @cfg {string} icon
*/
/* Inheritance */
ve.inheritClass( ve.ui.MenuItemWidget, ve.ui.OptionWidget );
/* Static Properties */
ve.ui.MenuItemWidget.static.selectedClass = 've-ui-icon-check';

View file

@ -17,6 +17,7 @@
* @param {Mixed} data Option data
* @param {Object} [config] Config options
* @cfg {jQuery|string} [label] Option label
* @cfg {string} [icon] Symbolic name of icon
* @cfg {boolean} [selected=false] Select option
* @cfg {boolean} [highlighted=false] Highlight option
* @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
@ -44,6 +45,13 @@ ve.ui.OptionWidget = function VeUiOptionWidget( data, config ) {
.append( this.$label );
this.setSelected( config.selected );
this.setHighlighted( config.highlighted );
// Options
if ( config.icon ) {
this.$icon = this.$$( '<div>' )
.addClass( 've-ui-optionWidget-icon ve-ui-icon-' + config.icon )
.appendTo( this.$ );
}
};
/* Inheritance */
@ -56,12 +64,8 @@ ve.mixinClass( ve.ui.OptionWidget, ve.ui.LabeledElement );
ve.ui.OptionWidget.static.tagName = 'li';
ve.ui.OptionWidget.static.selectedClass = 've-ui-optionWidget-selected';
ve.ui.OptionWidget.static.selectable = true;
ve.ui.OptionWidget.static.highlightedClass = 've-ui-optionWidget-highlighted';
ve.ui.OptionWidget.static.highlightable = true;
/* Methods */
@ -117,9 +121,9 @@ ve.ui.OptionWidget.prototype.setSelected = function ( state ) {
if ( !this.disabled && this.constructor.static.selectable ) {
this.selected = !!state;
if ( this.selected ) {
this.$.addClass( this.constructor.static.selectedClass );
this.$.addClass( 've-ui-optionWidget-selected' );
} else {
this.$.removeClass( this.constructor.static.selectedClass );
this.$.removeClass( 've-ui-optionWidget-selected' );
}
}
return this;
@ -136,9 +140,9 @@ ve.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
if ( !this.disabled && this.constructor.static.highlightable ) {
this.highlighted = !!state;
if ( this.highlighted ) {
this.$.addClass( this.constructor.static.highlightedClass );
this.$.addClass( 've-ui-optionWidget-highlighted' );
} else {
this.$.removeClass( this.constructor.static.highlightedClass );
this.$.removeClass( 've-ui-optionWidget-highlighted' );
}
}
return this;
@ -154,9 +158,9 @@ ve.ui.OptionWidget.prototype.flash = function ( done ) {
var $this = this.$;
if ( !this.disabled && this.constructor.static.highlightable ) {
$this.removeClass( this.constructor.static.highlightedClass );
$this.removeClass( 've-ui-optionWidget-highlighted' );
setTimeout( ve.bind( function () {
$this.addClass( this.constructor.static.highlightedClass );
$this.addClass( 've-ui-optionWidget-highlighted' );
if ( done ) {
setTimeout( done, 100 );
}

View file

@ -14,7 +14,6 @@
* @constructor
* @param {Mixed} data Item data
* @param {Object} [config] Config options
* @cfg {string} [icon] Symbolic name of icon
* @cfg {number} [level] Indentation level
* @cfg {boolean} [moveable] Allow modification from outline controls
*/
@ -31,9 +30,6 @@ ve.ui.OutlineItemWidget = function VeUiOutlineItemWidget( data, config ) {
// Initialization
this.$.addClass( 've-ui-outlineItemWidget' );
if ( config.icon ) {
this.$.addClass( 've-ui-icon-' + config.icon );
}
this.setLevel( config.level );
};