/*!
- * OOjs UI v0.1.0-pre (49b64bdba7)
+ * OOjs UI v0.1.0-pre (880100c45e)
* 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-09-15T22:18:37Z
+ * Date: 2014-09-23T22:28:43Z
*/
( function ( OO ) {
* @return {number} Content height
*/
OO.ui.Window.prototype.getContentHeight = function () {
+ // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements
+ var bodyHeight, oldHeight = this.$frame[0].style.height;
+ this.$frame[0].style.height = '1px';
+ bodyHeight = this.getBodyHeight();
+ this.$frame[0].style.height = oldHeight;
+
return Math.round(
// Add buffer for border
( this.$frame.outerHeight() - this.$frame.innerHeight() ) +
// Use combined heights of children
- ( this.$head.outerHeight( true ) + this.getBodyHeight() + this.$foot.outerHeight( true ) )
+ ( this.$head.outerHeight( true ) + bodyHeight + this.$foot.outerHeight( true ) )
);
};
/**
* Get the height of the dialog contents.
*
+ * When this function is called, the dialog will temporarily have been resized
+ * to height=1px, so .scrollHeight measurements can be taken accurately.
+ *
* @return {number} Height of content
*/
OO.ui.Window.prototype.getBodyHeight = function () {
* @inheritdoc
*
* @param {Object} [data] Dialog opening data
- * @param {jQuery|string|Function|null} [data.label] Dialog label, omit to use #static-label
+ * @param {jQuery|string|Function|null} [data.title] Dialog title, omit to use #static-title
* @param {Object[]} [data.actions] List of OO.ui.ActionWidget configuration options for each
* action item, omit to use #static-actions
*/
manager.opening.notify( { state: 'setup' } );
setTimeout( function () {
win.ready( data ).then( function () {
- manager.updateWindowSize( win );
manager.opening.notify( { state: 'ready' } );
manager.opening = null;
manager.opened = $.Deferred();
};
/**
- * Set the ideal size.
+ * Set the ideal size. These are the dimensions the element will have when it's not being clipped.
*
* @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
* @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
this.idealWidth = width;
this.idealHeight = height;
+
+ if ( !this.clipping ) {
+ // Update dimensions
+ this.$clippable.css( { width: width, height: height } );
+ }
+ // While clipping, idealWidth and idealHeight are not considered
};
/**
* @param {Object} [config] Configuration options
* @cfg {string} [action] Symbolic action name
* @cfg {string[]} [modes] Symbolic mode names
+ * @cfg {boolean} [framed=false] Render button with a frame
*/
OO.ui.ActionWidget = function OoUiActionWidget( config ) {
// Config intialization
* @abstract
* @class
* @extends OO.ui.Widget
+ * @mixins OO.ui.FlaggedElement
*
* @constructor
* @param {Object} [config] Configuration options
// Parent constructor
OO.ui.InputWidget.super.call( this, config );
+ // Mixin constructors
+ OO.ui.FlaggedElement.call( this, config );
+
// Properties
this.$input = this.getInputElement( config );
this.value = '';
/* Setup */
OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.FlaggedElement );
/* Events */
* @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
+ * @cfg {RegExp|string} [validate] Regular expression (or symbolic name referencing
+ * one, see #static-validationPatterns)
*/
OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
// Configuration initialization
this.multiline = !!config.multiline;
this.autosize = !!config.autosize;
this.maxRows = config.maxRows !== undefined ? config.maxRows : 10;
+ this.validate = config.validate || null;
// Events
- this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
+ this.$input.on( {
+ keypress: OO.ui.bind( this.onKeyPress, this ),
+ blur: OO.ui.bind( this.setValidityFlag, 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 ) );
OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IndicatorElement );
OO.mixinClass( OO.ui.TextInputWidget, OO.ui.PendingElement );
+/* Static properties */
+
+OO.ui.TextInputWidget.static.validationPatterns = {
+ 'non-empty': /.+/,
+ integer: /^\d+$/
+};
+
/* Events */
/**
// Parent method
OO.ui.TextInputWidget.super.prototype.setValue.call( this, value );
+ this.setValidityFlag();
this.adjustSize();
return this;
};
return this;
};
+/**
+ * Sets the 'invalid' flag appropriately.
+ */
+OO.ui.TextInputWidget.prototype.setValidityFlag = function () {
+ this.isValid().done( OO.ui.bind( function ( valid ) {
+ this.setFlags( { invalid: !valid } );
+ }, this ) );
+};
+
+/**
+ * Returns whether or not the current value is considered valid, according to the
+ * supplied validation pattern.
+ *
+ * @return {jQuery.Deferred}
+ */
+OO.ui.TextInputWidget.prototype.isValid = function () {
+ var validationRegexp;
+ if ( this.validate instanceof RegExp ) {
+ validationRegexp = this.validate;
+ } else {
+ validationRegexp = this.constructor.static.validationPatterns[this.validate];
+ }
+ return $.Deferred().resolve( !!this.getValue().match( validationRegexp ) ).promise();
+};
+
/**
* Text input with a menu of optional values.
*
this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
}
+ // Reevaluate clipping state since we've relocated and resized the popup
+ this.clip();
+
return this;
};
var change = visible !== this.isVisible();
+ if ( change && visible ) {
+ // Make sure the width is set before the parent method runs.
+ // After this we have to call this.position(); again to actually
+ // position ourselves correctly.
+ this.position();
+ }
+
// Parent method
OO.ui.TextInputMenuWidget.super.prototype.toggle.call( this, visible );
this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
}
}
+
return this;
};
}
this.$element.css( dimensions );
this.setIdealSize( $container.width() );
+ // We updated the position, so re-evaluate the clipping state
+ this.clip();
return this;
};