/*!
- * OOjs UI v0.1.0-pre (51f513f9d3)
+ * OOjs UI v0.1.0-pre (944c47c5fe)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-08-20T00:59:55Z
+ * Date: 2014-08-21T00:23:52Z
*/
.oo-ui-dialog-content > .oo-ui-window-head,
.oo-ui-dialog-content > .oo-ui-window-body,
border-bottom-right-radius: 0.3em;
}
+.oo-ui-comboBoxWidget-handle {
+ border: solid 1px rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+}
+
+.oo-ui-comboBoxWidget-handle:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-comboBoxWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator,
+.oo-ui-comboBoxWidget-empty .oo-ui-textInputWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+ cursor: default;
+ opacity: 0.2;
+}
+
.oo-ui-inlineMenuWidget-handle {
border: solid 1px rgba(0, 0, 0, 0.1);
border-radius: 0.25em;
border-color: #ddd;
}
+.oo-ui-textInputWidget .oo-ui-iconedElement-icon,
+.oo-ui-textInputWidget .oo-ui-indicatedElement-indicator {
+ opacity: 0.8;
+}
+
+.oo-ui-textInputWidget.oo-ui-iconedElement input,
+.oo-ui-textInputWidget.oo-ui-iconedElement textarea {
+ padding-left: 2em;
+}
+
+.oo-ui-textInputWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+ width: 2em;
+ background-position: right center;
+}
+
+.oo-ui-textInputWidget.oo-ui-indicatedElement input,
+.oo-ui-textInputWidget.oo-ui-indicatedElement textarea {
+ padding-right: 1.5em;
+}
+
+.oo-ui-textInputWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+ width: 1.5em;
+ background-position: left center;
+}
+
.oo-ui-toggleSwitchWidget {
background: #eeeeee;
background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #dddddd), color-stop(100%, #ffffff));
/*!
- * OOjs UI v0.1.0-pre (51f513f9d3)
+ * OOjs UI v0.1.0-pre (944c47c5fe)
* https://www.mediawiki.org/wiki/OOjs_UI
*
* Copyright 2011–2014 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-08-20T00:59:55Z
+ * Date: 2014-08-21T00:23:52Z
*/
( function ( OO ) {
* @return {jQuery.Promise} Promise resolved when styles have loaded
*/
OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, timeout ) {
- var i, numSheets, styleNode, newNode, timeoutID, pollNodeId, $pendingPollNodes,
+ var i, numSheets, styleNode, styleText, newNode, timeoutID, pollNodeId, $pendingPollNodes,
$pollNodes = $( [] ),
// Fake font-family value
fontFamily = 'oo-ui-frame-transplantStyles-loaded',
+ nextIndex = parentDoc.oouiFrameTransplantStylesNextIndex || 0,
deferred = $.Deferred();
for ( i = 0, numSheets = parentDoc.styleSheets.length; i < numSheets; i++ ) {
if ( styleNode.disabled ) {
continue;
}
+
if ( styleNode.nodeName.toLowerCase() === 'link' ) {
- // External stylesheet
- // Create a node with a unique ID that we're going to monitor to see when the CSS
- // has loaded
- pollNodeId = 'oo-ui-frame-transplantStyles-loaded-' + i;
- $pollNodes = $pollNodes.add( $( '<div>', frameDoc )
- .attr( 'id', pollNodeId )
- .appendTo( frameDoc.body )
- );
+ // External stylesheet; use @import
+ styleText = '@import url(' + styleNode.href + ');';
+ } else {
+ // Internal stylesheet; just copy the text
+ styleText = styleNode.textContent;
+ }
- // Add <style>@import url(...); #pollNodeId { font-family: ... }</style>
- // The font-family rule will only take effect once the @import finishes
- newNode = frameDoc.createElement( 'style' );
- newNode.textContent = '@import url(' + styleNode.href + ');\n' +
- '#' + pollNodeId + ' { font-family: ' + fontFamily + '; }';
+ // Create a node with a unique ID that we're going to monitor to see when the CSS
+ // has loaded
+ if ( styleNode.oouiFrameTransplantStylesId ) {
+ // If we're nesting transplantStyles operations and this node already has
+ // a CSS rule to wait for loading, reuse it
+ pollNodeId = styleNode.oouiFrameTransplantStylesId;
} else {
- // Not an external stylesheet, or no polling required; just copy the node over
- // Can't use importNode here because that breaks in IE
- newNode = frameDoc.createElement( 'style' );
- newNode.textContent = styleNode.textContent;
+ // Otherwise, create a new ID
+ pollNodeId = 'oo-ui-frame-transplantStyles-loaded-' + nextIndex;
+ nextIndex++;
+
+ // Add #pollNodeId { font-family: ... } to the end of the stylesheet / after the @import
+ // The font-family rule will only take effect once the @import finishes
+ styleText += '\n' + '#' + pollNodeId + ' { font-family: ' + fontFamily + '; }';
}
+
+ // Create a node with id=pollNodeId
+ $pollNodes = $pollNodes.add( $( '<div>', frameDoc )
+ .attr( 'id', pollNodeId )
+ .appendTo( frameDoc.body )
+ );
+
+ // Add our modified CSS as a <style> tag
+ newNode = frameDoc.createElement( 'style' );
+ newNode.textContent = styleText;
+ newNode.oouiFrameTransplantStylesId = pollNodeId;
frameDoc.head.appendChild( newNode );
}
+ frameDoc.oouiFrameTransplantStylesNextIndex = nextIndex;
// Poll every 100ms until all external stylesheets have loaded
$pendingPollNodes = $pollNodes;
/* Methods */
+/**
+ * Check if there are no items.
+ *
+ * @return {boolean} Group is empty
+ */
+OO.ui.GroupElement.prototype.isEmpty = function () {
+ return !this.items.length;
+};
+
/**
* Get items.
*
*
* @class
* @extends OO.ui.InputWidget
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.IndicatedElement
*
* @constructor
* @param {Object} [config] Configuration options
* @cfg {string} [placeholder] Placeholder text
- * @cfg {string} [icon] Symbolic name of icon
* @cfg {boolean} [multiline=false] Allow multiple lines of text
* @cfg {boolean} [autosize=false] Automatically resize to fit content
* @cfg {boolean} [maxRows=10] Maximum number of rows to make visible when autosizing
*/
OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
- var widget = this;
- config = $.extend( { maxRows: 10 }, config );
+ // Configuration initialization
+ config = config || {};
// Parent constructor
OO.ui.TextInputWidget.super.call( this, config );
+ // Mixin constructors
+ OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+ OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
+
// Properties
this.pending = 0;
this.multiline = !!config.multiline;
this.autosize = !!config.autosize;
- this.maxRows = config.maxRows;
+ this.maxRows = config.maxRows !== undefined ? config.maxRows : 10;
// Events
this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
this.$element.on( 'DOMNodeInsertedIntoDocument', OO.ui.bind( this.onElementAttach, this ) );
+ this.$icon.on( 'mousedown', OO.ui.bind( this.onIconMouseDown, this ) );
+ this.$indicator.on( 'mousedown', OO.ui.bind( this.onIndicatorMouseDown, this ) );
// Initialization
- this.$element.addClass( 'oo-ui-textInputWidget' );
- if ( config.icon ) {
- this.$element.addClass( 'oo-ui-textInputWidget-decorated' );
- this.$element.append(
- this.$( '<span>' )
- .addClass( 'oo-ui-textInputWidget-icon oo-ui-icon-' + config.icon )
- .mousedown( function () {
- widget.$input[0].focus();
- return false;
- } )
- );
- }
+ this.$element
+ .addClass( 'oo-ui-textInputWidget' )
+ .append( this.$icon, this.$indicator );
if ( config.placeholder ) {
this.$input.attr( 'placeholder', config.placeholder );
}
/* Setup */
OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IndicatedElement );
/* Events */
* @event enter
*/
+/**
+ * User clicks the icon.
+ *
+ * @event icon
+ */
+
+/**
+ * User clicks the indicator.
+ *
+ * @event indicator
+ */
+
/* Methods */
+/**
+ * Handle icon mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
+ * @fires icon
+ */
+OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
+ if ( e.which === 1 ) {
+ this.$input[0].focus();
+ this.emit( 'icon' );
+ return false;
+ }
+};
+
+/**
+ * Handle indicator mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
+ * @fires indicator
+ */
+OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
+ if ( e.which === 1 ) {
+ this.$input[0].focus();
+ this.emit( 'indicator' );
+ return false;
+ }
+};
+
/**
* Handle key press events.
*
return this;
};
+/**
+ * Text input with a menu of optional values.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} [menu] Configuration options to pass to menu widget
+ * @cfg {Object} [input] Configuration options to pass to input widget
+ */
+OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.ComboBoxWidget.super.call( this, config );
+
+ // Properties
+ this.input = new OO.ui.TextInputWidget( $.extend(
+ { $: this.$, indicator: 'down', disabled: this.isDisabled() },
+ config.input
+ ) );
+ this.menu = new OO.ui.MenuWidget( $.extend(
+ { $: this.$, widget: this, input: this.input, disabled: this.isDisabled() },
+ config.menu
+ ) );
+
+ // Events
+ this.input.connect( this, {
+ change: 'onInputChange',
+ indicator: 'onInputIndicator',
+ enter: 'onInputEnter'
+ } );
+ this.menu.connect( this, {
+ choose: 'onMenuChoose',
+ add: 'onMenuItemsChange',
+ remove: 'onMenuItemsChange'
+ } );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-comboBoxWidget' ).append(
+ this.input.$element,
+ this.menu.$element
+ );
+ this.onMenuItemsChange();
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ComboBoxWidget, OO.ui.Widget );
+
+/* Methods */
+
+/**
+ * Handle input change events.
+ *
+ * @param {string} value New value
+ */
+OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
+ var match = this.menu.getItemFromData( value );
+
+ this.menu.selectItem( match );
+
+ if ( !this.isDisabled() ) {
+ this.menu.toggle( true );
+ }
+};
+
+/**
+ * Handle input indicator events.
+ */
+OO.ui.ComboBoxWidget.prototype.onInputIndicator = function () {
+ if ( !this.isDisabled() ) {
+ this.menu.toggle();
+ }
+};
+
+/**
+ * Handle input enter events.
+ */
+OO.ui.ComboBoxWidget.prototype.onInputEnter = function () {
+ if ( !this.isDisabled() ) {
+ this.menu.toggle( false );
+ }
+};
+
+/**
+ * Handle menu choose events.
+ *
+ * @param {OO.ui.OptionWidget} item Chosen item
+ */
+OO.ui.ComboBoxWidget.prototype.onMenuChoose = function ( item ) {
+ if ( item ) {
+ this.input.setValue( item.getData() );
+ }
+};
+
+/**
+ * Handle menu item change events.
+ */
+OO.ui.ComboBoxWidget.prototype.onMenuItemsChange = function () {
+ this.$element.toggleClass( 'oo-ui-comboBoxWidget-empty', this.menu.isEmpty() );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
+ // Parent method
+ OO.ui.ComboBoxWidget.super.prototype.setDisabled.call( this, disabled );
+
+ if ( this.input ) {
+ this.input.setDisabled( this.isDisabled() );
+ }
+ if ( this.menu ) {
+ this.menu.setDisabled( this.isDisabled() );
+ }
+
+ return this;
+};
+
/**
* Label widget.
*
* @inheritdoc
*/
OO.ui.MenuWidget.prototype.toggle = function ( visible ) {
- visible = !!visible && !!this.items.length;
+ visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
var i, len,
change = visible !== this.isVisible();