Trevor Parscal has uploaded a new change for review. https://gerrit.wikimedia.org/r/99457
Change subject: Update OOJS UI to v0.1.0-pre (d3ce971b6c) ...................................................................... Update OOJS UI to v0.1.0-pre (d3ce971b6c) Change-Id: Ibaa14d20af212987e9abf5bf12668992e5a80da2 --- M modules/oojs-ui/oojs-ui.js M modules/oojs-ui/oojs-ui.svg.css 2 files changed, 599 insertions(+), 345 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor refs/changes/57/99457/1 diff --git a/modules/oojs-ui/oojs-ui.js b/modules/oojs-ui/oojs-ui.js index f952bd3..51ba5a8 100644 --- a/modules/oojs-ui/oojs-ui.js +++ b/modules/oojs-ui/oojs-ui.js @@ -1,12 +1,12 @@ /*! - * OOJS UI v0.1.0-pre (e5ef1e5b28) + * OOJS UI v0.1.0-pre (d3ce971b6c) * https://www.mediawiki.org/wiki/OOJS * * Copyright 2011-2013 OOJS Team and other contributors. * Released under the MIT license * http://oojs.mit-license.org * - * Date: Mon Nov 25 2013 10:40:32 GMT+0000 (GMT) + * Date: Thu Dec 05 2013 11:44:05 GMT-0800 (PST) */ ( function () { @@ -83,10 +83,6 @@ var messages = { // Label text for button to exit from dialog 'ooui-dialog-action-close': 'Close', - // TODO remove me - 'ooui-inspector-close-tooltip': 'Close', - // TODO remove me - 'ooui-inspector-remove-tooltip': 'Remove', // Tool tip for a button that moves items in a list down one place 'ooui-outline-control-move-down': 'Move item down', // Tool tip for a button that moves items in a list up one place @@ -615,6 +611,10 @@ * frame's document. It then polls the document to see when all styles have loaded, and once they * have, invokes the callback. * + * If the styles still haven't loaded after a long time (5 seconds by default), we give up waiting + * and invoke the callback anyway. This protects against cases like a display: none; iframe in + * Firefox, where the styles won't load until the iframe becomes visible. + * * For details of how we arrived at the strategy used in this function, see #load. * * @static @@ -623,9 +623,10 @@ * @param {HTMLDocument} parentDoc Document to transplant styles from * @param {HTMLDocument} frameDoc Document to transplant styles to * @param {Function} [callback] Callback to execute once styles have loaded + * @param {number} [timeout=5000] How long to wait before giving up (in ms). If 0, never give up. */ -OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, callback ) { - var i, numSheets, styleNode, newNode, timeout, pollNodeId, $pendingPollNodes, +OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, callback, timeout ) { + var i, numSheets, styleNode, newNode, timeoutID, pollNodeId, $pendingPollNodes, $pollNodes = $( [] ), // Fake font-family value fontFamily = 'oo-ui-frame-transplantStyles-loaded'; @@ -657,7 +658,7 @@ if ( callback ) { // Poll every 100ms until all external stylesheets have loaded $pendingPollNodes = $pollNodes; - timeout = setTimeout( function pollExternalStylesheets() { + timeoutID = setTimeout( function pollExternalStylesheets() { while ( $pendingPollNodes.length > 0 && $pendingPollNodes.eq( 0 ).css( 'font-family' ) === fontFamily @@ -667,12 +668,26 @@ if ( $pendingPollNodes.length === 0 ) { // We're done! - $pollNodes.remove(); - callback(); + if ( timeoutID !== null ) { + timeoutID = null; + $pollNodes.remove(); + callback(); + } } else { - timeout = setTimeout( pollExternalStylesheets, 100 ); + timeoutID = setTimeout( pollExternalStylesheets, 100 ); } }, 100 ); + // ...but give up after a while + if ( timeout !== 0 ) { + setTimeout( function () { + if ( timeoutID ) { + clearTimeout( timeoutID ); + timeoutID = null; + $pollNodes.remove(); + callback(); + } + }, timeout || 5000 ); + } } }; @@ -1763,12 +1778,19 @@ * * @constructor * @param {jQuery} $group Container node, assigned to #$group + * @param {Object} [config] Configuration options + * @cfg {Object.<string,string>} [aggregations] Events to aggregate, keyed by item event name */ -OO.ui.GroupElement = function OoUiGroupElement( $group ) { +OO.ui.GroupElement = function OoUiGroupElement( $group, config ) { + // Configuration + config = config || {}; + // Properties this.$group = $group; this.items = []; this.$items = this.$( [] ); + this.aggregate = !$.isEmptyObject( config.aggregations ); + this.aggregations = config.aggregations || {}; }; /* Methods */ @@ -1792,7 +1814,7 @@ * @chainable */ OO.ui.GroupElement.prototype.addItems = function ( items, index ) { - var i, len, item, currentIndex, + var i, len, item, event, events, currentIndex, $items = this.$( [] ); for ( i = 0, len = items.length; i < len; i++ ) { @@ -1808,6 +1830,13 @@ } } // Add the item + if ( this.aggregate ) { + events = {}; + for ( event in this.aggregations ) { + events[event] = [ 'emit', this.aggregations[event], item ]; + } + item.connect( this, events ); + } $items = $items.add( item.$element ); } @@ -1837,12 +1866,20 @@ * @chainable */ OO.ui.GroupElement.prototype.removeItems = function ( items ) { - var i, len, item, index; + var i, len, item, index, event, events; + // Remove specific items for ( i = 0, len = items.length; i < len; i++ ) { item = items[i]; index = this.items.indexOf( item ); if ( index !== -1 ) { + if ( this.aggregate ) { + events = {}; + for ( event in this.aggregations ) { + events[event] = 'emit'; + } + item.disconnect( this, events ); + } this.items.splice( index, 1 ); item.$element.detach(); this.$items = this.$items.not( item.$element ); @@ -1861,11 +1898,7 @@ * @chainable */ OO.ui.GroupElement.prototype.clearItems = function () { - this.items = []; - this.$items.detach(); - this.$items = this.$( [] ); - - return this; + return this.removeItems( this.items ); }; /** * Element containing an icon. @@ -3109,10 +3142,13 @@ * * @constructor * @param {Object} [config] Configuration options - * @param {boolean} [config.attachPagesPanel] Whether or not to attach pagesPanel to this.$element on - * initialization. + * @cfg {boolean} [continuous=false] Show all pages, one after another + * @cfg {boolean} [autoFocus=false] Focus on the first focusable element when changing to a page + * @cfg {boolean} [outlined=false] Show an outline + * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages + * @cfg {Object[]} [adders List of adders for controls, each with name, icon and title properties */ -OO.ui.PagedLayout = function OoUiPagedLayout( config ) { +OO.ui.BookletLayout = function OoUiBookletLayout( config ) { // Initialize configuration config = config || {}; @@ -3120,67 +3156,274 @@ OO.ui.Layout.call( this, config ); // Properties - this.attached = !!config.attachPagesPanel; this.currentPageName = null; this.pages = {}; - this.pagesPanel = new OO.ui.StackPanelLayout( { '$': this.$ } ); + this.scrolling = false; + this.selecting = false; + this.stackLayout = new OO.ui.StackLayout( { '$': this.$, 'continuous': !!config.continuous } ); + this.scrollingTimeout = null; + this.onStackLayoutDebouncedScrollHandler = + OO.ui.bind( this.onStackLayoutDebouncedScroll, this ); + this.autoFocus = !!config.autoFocus; + this.outlined = !!config.outlined; + if ( this.outlined ) { + this.editable = !!config.editable; + this.adders = config.adders || null; + this.outlineControlsWidget = null; + this.outlineWidget = new OO.ui.OutlineWidget( { '$': this.$ } ); + this.outlinePanel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } ); + this.gridLayout = new OO.ui.GridLayout( + [this.outlinePanel, this.stackLayout], { '$': this.$, 'widths': [1, 2] } + ); + if ( this.editable ) { + this.outlineControlsWidget = new OO.ui.OutlineControlsWidget( + this.outlineWidget, { '$': this.$, 'adders': this.adders } + ); + } + } + + // Events + this.stackLayout.connect( this, { 'set': 'onStackLayoutSet' } ); + if ( this.outlined ) { + this.outlineWidget.connect( this, { 'select': 'onOutlineWidgetSelect' } ); + this.stackLayout.$element.on( 'scroll', OO.ui.bind( this.onStackLayoutScroll, this ) ); + } // Initialization - this.$element.addClass( 'oo-ui-pagedLayout' ); - this.pagesPanel.$element.addClass( 'oo-ui-pagedLayout-pagesPanel' ); - - if ( this.attached ) { - this.$element.append( this.pagesPanel.$element ); + this.$element.addClass( 'oo-ui-bookletLayout' ); + this.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' ); + if ( this.outlined ) { + this.outlinePanel.$element + .addClass( 'oo-ui-bookletLayout-outlinePanel' ) + .append( this.outlineWidget.$element ); + if ( this.editable ) { + this.outlinePanel.$element + .addClass( 'oo-ui-bookletLayout-outlinePanel-editable' ) + .append( this.outlineControlsWidget.$element ); + } + this.$element.append( this.gridLayout.$element ); + } else { + this.$element.append( this.stackLayout.$element ); } }; /* Inheritance */ -OO.inheritClass( OO.ui.PagedLayout, OO.ui.Layout ); +OO.inheritClass( OO.ui.BookletLayout, OO.ui.Layout ); /* Events */ /** * @event add * @param {string} name The name of the page added. - * @param {OO.ui.PanelLayout} page The page panel. + * @param {OO.ui.PageLayout} page The page panel. */ /** * @event remove - * @param {OO.ui.PanelLayout[]} pages An array of page panels that were removed. + * @param {OO.ui.PageLayout[]} pages An array of page panels that were removed. */ /** * @event set - * @param {OO.ui.PanelLayout} page The page panel that is now the current page. + * @param {OO.ui.PageLayout} page The page panel that is now the current page. */ /* Methods */ + +/** + * Handle stack layout scroll events. + * + * @method + * @param {jQuery.Event} e Scroll event + */ +OO.ui.BookletLayout.prototype.onStackLayoutScroll = function () { + if ( !this.selecting ) { + this.scrolling = true; + if ( !this.scrollingTimeout ) { + this.scrollingTimeout = setTimeout( this.onStackLayoutDebouncedScrollHandler, 100 ); + } + } +}; + +OO.ui.BookletLayout.prototype.onStackLayoutDebouncedScroll = function () { + var i, len, name, top, height, $item, visible, + items = this.stackLayout.getItems(), + middle = this.stackLayout.$element.height() / 2; + + for ( i = 0, len = items.length; i < len; i++ ) { + $item = items[i].$element; + top = $item.position().top; + height = $item.height(); + if ( top < middle && top + height > middle ) { + visible = items[i]; + break; + } + } + if ( visible ) { + for ( name in this.pages ) { + if ( this.pages[name] === items[i] ) { + break; + } + } + if ( name !== this.currentPageName ) { + this.setPage( name ); + } + } + this.scrolling = false; + this.scrollingTimeout = null; +}; + +/** + * Handle stack layout set events. + * + * @method + * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel + */ +OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) { + if ( page ) { + this.selecting = true; + if ( this.scrolling ) { + if ( this.autoFocus ) { + page.$element.find( ':input:first' ).focus(); + } + this.selecting = false; + } else { + page.scrollElementIntoView( { 'complete': OO.ui.bind( function () { + if ( this.autoFocus ) { + page.$element.find( ':input:first' ).focus(); + } + this.selecting = false; + }, this ) } ); + } + } +}; + +/** + * Handle outline widget select events. + * + * @method + * @param {OO.ui.OptionWidget|null} item Selected item + */ +OO.ui.BookletLayout.prototype.onOutlineWidgetSelect = function ( item ) { + if ( item && !this.scrolling ) { + this.setPage( item.getData() ); + } +}; + +/** + * Check if booklet has an outline. + * + * @method + * @returns {boolean} Booklet is outlined + */ +OO.ui.BookletLayout.prototype.isOutlined = function () { + return this.outlined; +}; + +/** + * Check if booklet has editing controls. + * + * @method + * @returns {boolean} Booklet is outlined + */ +OO.ui.BookletLayout.prototype.isEditable = function () { + return this.editable; +}; + +/** + * Get the outline widget. + * + * @method + * @returns {OO.ui.OutlineWidget} Outline widget + */ +OO.ui.BookletLayout.prototype.getOutline = function () { + return this.outlineWidget; +}; + +/** + * Get the outline controls widget. If the outline is not editable, null is returned. + * + * @method + * @returns {OO.ui.OutlineControlsWidget|null} The outline controls widget. + */ +OO.ui.BookletLayout.prototype.getOutlineControls = function () { + return this.outlineControlsWidget; +}; + +/** + * Get a page by name. + * + * @method + * @param {string} name Symbolic name of page + * @returns {OO.ui.PageLayout|undefined} Page, if found + */ +OO.ui.BookletLayout.prototype.getPage = function ( name ) { + return this.pages[name]; +}; + +/** + * Get the current page name. + * + * @method + * @returns {string|null} Current page name + */ +OO.ui.BookletLayout.prototype.getPageName = function () { + return this.currentPageName; +}; /** * Add a page to the layout. * * @method * @param {string} name Symbolic name of page - * @param {Object} [config] Condifugration options - * @param {number} [config.index] Specific index to insert page at - * @param {jQuery} [config.$content] Page content + * @param {OO.ui.PageLayout} page Page to add + * @param {number} index Specific index to insert page at * @fires add * @chainable */ -OO.ui.PagedLayout.prototype.addPage = function ( name, config ) { - var page = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } ); - - config = config || {}; - - if ( config.$content ) { - page.$element.append( config.$content ); +OO.ui.BookletLayout.prototype.addPage = function ( name, page, index ) { + if ( this.outlined ) { + this.outlineWidget.addItems( + [ + new OO.ui.OutlineItemWidget( name, { + '$': this.$, + 'label': page.getLabel() || name, + 'level': page.getLevel(), + 'icon': page.getIcon(), + 'moveable': page.isMovable() + } ) + ], + index + ); + this.updateOutlineWidget(); } - this.pages[name] = page; - this.pagesPanel.addItems( [ page ], config.index ); + this.stackLayout.addItems( [ page ], index ); this.emit( 'add', name, page ); + return this; +}; + +/** + * Remove a page from the layout. + * + * @method + * @fires remove + * @chainable + */ +OO.ui.BookletLayout.prototype.removePage = function ( name ) { + var page = this.pages[name]; + + if ( page ) { + if ( this.outlined ) { + this.outlineWidget.removeItems( [ this.outlineWidget.getItemFromData( name ) ] ); + this.updateOutlineWidget(); + } + page = [ page ]; + delete this.pages[name]; + this.stackLayout.removeItems( page ); + this.emit( 'remove', page ); + } return this; }; @@ -3192,55 +3435,16 @@ * @fires remove * @chainable */ -OO.ui.PagedLayout.prototype.clearPages = function () { - var pages = this.pagesPanel.getItems(); +OO.ui.BookletLayout.prototype.clearPages = function () { + var pages = this.stackLayout.getItems(); + if ( this.outlined ) { + this.outlineWidget.clearItems(); + } this.currentPageName = null; this.pages = {}; - this.pagesPanel.clearItems(); + this.stackLayout.clearItems(); this.emit( 'remove', pages ); - - return this; -}; - -/** - * Get a page by name. - * - * @method - * @param {string} name Symbolic name of page - * @returns {OO.ui.PanelLayout|undefined} Page, if found - */ -OO.ui.PagedLayout.prototype.getPage = function ( name ) { - return this.pages[name]; -}; - - -/** - * Get the current page name. - * - * @method - * @returns {string|null} Current page name - */ -OO.ui.PagedLayout.prototype.getPageName = function () { - return this.currentPageName; -}; - -/** - * Remove a page from the layout. - * - * @method - * @fires remove - * @chainable - */ -OO.ui.PagedLayout.prototype.removePage = function ( name ) { - var page = this.pages[name]; - - if ( page ) { - page = [ page ]; - delete this.pages[name]; - this.pagesPanel.removeItems( page ); - this.emit( 'remove', page ); - } return this; }; @@ -3252,187 +3456,17 @@ * @fires set * @param {string} name Symbolic name of page */ -OO.ui.PagedLayout.prototype.setPage = function ( name ) { +OO.ui.BookletLayout.prototype.setPage = function ( name ) { var page = this.pages[name]; + if ( this.outlined && name !== this.outlineWidget.getSelectedItem().getData() ) { + this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) ); + } if ( page ) { this.currentPageName = name; - this.pagesPanel.showItem( page ); + this.stackLayout.setItem( page ); this.emit( 'set', page ); } -}; -/** - * Layout containing a series of pages and an outline controlling their visibility. - * - * The outline takes up the left third, the pages taking up the remaining two-thirds on the right. - * - * @class - * @extends OO.ui.PagedLayout - * - * @constructor - * @param {Object} [config] Configuration options - * @param {boolean} [config.editable] Show controls for adding, removing and reordering items in - * the outline - * @param {Object[]} [config.adders] List of adders for controls, each an object with name, icon - * and title properties - */ -OO.ui.PagedOutlineLayout = function OoUiPagedOutlineLayout( config ) { - // Initialize configuration - config = config || {}; - config.attachPagesPanel = false; - - // Parent constructor - OO.ui.PagedLayout.call( this, config ); - - // Properties - this.adders = config.adders || null; - this.editable = !!config.editable; - this.outlineControlsWidget = null; - this.outlinePanel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } ); - this.outlineWidget = new OO.ui.OutlineWidget( { '$': this.$ } ); - this.gridLayout = new OO.ui.GridLayout( - [this.outlinePanel, this.pagesPanel], { '$': this.$, 'widths': [1, 2] } - ); - - if ( this.editable ) { - this.outlineControlsWidget = new OO.ui.OutlineControlsWidget( - this.outlineWidget, { '$': this.$, 'adders': this.adders } - ); - } - - // Events - this.outlineWidget.connect( this, { 'select': 'onPageOutlineSelect' } ); - this.pagesPanel.connect( this, { 'set': 'onPagedLayoutSet' } ); - - // Initialization - this.outlinePanel.$element - .addClass( 'oo-ui-pagedOutlineLayout-outlinePanel' ) - .append( this.outlineWidget.$element ); - - if ( this.editable ) { - this.outlinePanel.$element - .addClass( 'oo-ui-pagedOutlineLayout-outlinePanel-editable' ) - .append( this.outlineControlsWidget.$element ); - } - - this.$element - .addClass( 'oo-ui-pagedOutlineLayout' ) - .append( this.gridLayout.$element ); -}; - -/* Inheritance */ - -OO.inheritClass( OO.ui.PagedOutlineLayout, OO.ui.PagedLayout ); - -/* Methods */ - -/** - * Add a page to the layout. - * - * @method - * @param {string} name Symbolic name of page - * @param {Object} [config] Condifugration options - * @param {jQuery|string} [config.label=name] Page label - * @param {string} [config.icon] Symbolic name of icon - * @param {number} [config.level=0] Indentation level - * @param {number} [config.index] Specific index to insert page at - * @param {jQuery} [config.$content] Page content - * @param {jQuery} [config.moveable] Allow page to be moved in the outline - * @chainable - */ -OO.ui.PagedOutlineLayout.prototype.addPage = function ( name, config ) { - config = config || {}; - - this.outlineWidget.addItems( - [ - new OO.ui.OutlineItemWidget( name, { - '$': this.$, - 'label': config.label || name, - 'level': config.level || 0, - 'icon': config.icon, - 'moveable': config.moveable - } ) - ], - config.index - ); - - this.updateOutlineWidget(); - - // Parent method - return OO.ui.PagedLayout.prototype.addPage.call( this, name, config ); -}; - -/** - * Clear all pages. - * - * @method - * @chainable - */ -OO.ui.PagedOutlineLayout.prototype.clearPages = function () { - this.outlineWidget.clearItems(); - - // Parent method - return OO.ui.PagedLayout.prototype.clearPages.call( this ); -}; - -/** - * Get the outline widget. - * - * @method - * @returns {OO.ui.OutlineWidget} The outline widget. - */ -OO.ui.PagedOutlineLayout.prototype.getOutline = function () { - return this.outlineWidget; -}; - -/** - * Get the outline controls widget. If the outline is not editable, null is returned. - * - * @method - * @returns {OO.ui.OutlineControlsWidget|null} The outline controls widget. - */ -OO.ui.PagedOutlineLayout.prototype.getOutlineControls = function () { - return this.outlineControlsWidget; -}; - -/** - * Handle PagedLayout set events. - * - * @method - * @param {OO.ui.PanelLayout} page The page panel that is now the current panel. - */ -OO.ui.PagedOutlineLayout.prototype.onPagedLayoutSet = function ( page ) { - page.$element.find( ':input:first' ).focus(); -}; - -/** - * Handle outline select events. - * - * @method - * @param {OO.ui.OptionWidget} item Selected item - */ -OO.ui.PagedOutlineLayout.prototype.onPageOutlineSelect = function ( item ) { - if ( item ) { - OO.ui.PagedLayout.prototype.setPage.call( this, item.getData() ); - } -}; - -/** - * Remove a page. - * - * @method - * @chainable - */ -OO.ui.PagedOutlineLayout.prototype.removePage = function ( name ) { - var page = this.pages[name]; - - if ( page ) { - this.outlineWidget.removeItems( [ this.outlineWidget.getItemFromData( name ) ] ); - this.updateOutlineWidget(); - } - - // Parent method - return OO.ui.PagedLayout.prototype.removePage.call( this, name ); }; /** @@ -3441,22 +3475,13 @@ * @method * @chainable */ -OO.ui.PagedOutlineLayout.prototype.updateOutlineWidget = function () { +OO.ui.BookletLayout.prototype.updateOutlineWidget = function () { // Auto-select first item when nothing is selected anymore if ( !this.outlineWidget.getSelectedItem() ) { this.outlineWidget.selectItem( this.outlineWidget.getFirstSelectableItem() ); } return this; -}; - -/** - * @inheritdoc - */ -OO.ui.PagedOutlineLayout.prototype.setPage = function ( name ) { - if ( name !== this.outlineWidget.getSelectedItem().getData() ) { - this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) ); - } }; /** * Layout that expands to cover the entire area of its parent, with optional scrolling and padding. @@ -3494,6 +3519,74 @@ OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout ); /** + * Page within an OO.ui.BookletLayout. + * + * @class + * @extends OO.ui.PanelLayout + * + * @constructor + * @param {Object} [config] Configuration options + * @param {string} [icon=''] Symbolic name of icon to display in outline + * @param {string} [label=''] Label to display in outline + * @param {number} [level=0] Indentation level of item in outline + * @param {boolean} [movable=false] Page should be movable using outline controls + */ +OO.ui.PageLayout = function OoUiPageLayout( config ) { + // Configuration initialization + config = $.extend( { 'scrollable': true }, config ); + + // Parent constructor + OO.ui.PanelLayout.call( this, config ); + + // Properties + this.icon = config.icon || ''; + this.label = config.label || ''; + this.level = config.level || 0; + this.movable = !!config.movable; +}; + +/* Inheritance */ + +OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout ); + +/* Methods */ + +/** + * Get page icon. + * + * @returns {string} Symbolic name of icon + */ +OO.ui.PageLayout.prototype.getIcon = function () { + return this.icon; +}; + +/** + * Get page label. + * + * @returns {string} Label text + */ +OO.ui.PageLayout.prototype.getLabel = function () { + return this.label; +}; + +/** + * Get outline item indentation level. + * + * @returns {number} Indentation level + */ +OO.ui.PageLayout.prototype.getLevel = function () { + return this.level; +}; + +/** + * Check if page is movable using outline controls. + * + * @returns {boolean} Page is movable + */ +OO.ui.PageLayout.prototype.isMovable = function () { + return this.movable; +}; +/** * Layout containing a series of mutually exclusive pages. * * @class @@ -3502,9 +3595,10 @@ * * @constructor * @param {Object} [config] Configuration options + * @cfg {boolean} [continuous=false] Show all pages, one after another * @cfg {string} [icon=''] Symbolic icon name */ -OO.ui.StackPanelLayout = function OoUiStackPanelLayout( config ) { +OO.ui.StackLayout = function OoUiStackLayout( config ) { // Config initialization config = $.extend( { 'scrollable': true }, config ); @@ -3516,16 +3610,27 @@ // Properties this.currentItem = null; + this.continuous = !!config.continuous; // Initialization - this.$element.addClass( 'oo-ui-stackPanelLayout' ); + this.$element.addClass( 'oo-ui-stackLayout' ); + if ( this.continuous ) { + this.$element.addClass( 'oo-ui-stackLayout-continuous' ); + } }; /* Inheritance */ -OO.inheritClass( OO.ui.StackPanelLayout, OO.ui.PanelLayout ); +OO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout ); -OO.mixinClass( OO.ui.StackPanelLayout, OO.ui.GroupElement ); +OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement ); + +/* Events */ + +/** + * @event set + * @param {OO.ui.PanelLayout|null} [item] Current item + */ /* Methods */ @@ -3539,17 +3644,12 @@ * @param {number} [index] Index to insert items after * @chainable */ -OO.ui.StackPanelLayout.prototype.addItems = function ( items, index ) { - var i, len; - - for ( i = 0, len = items.length; i < len; i++ ) { - if ( !this.currentItem ) { - this.showItem( items[i] ); - } else { - items[i].$element.hide(); - } - } +OO.ui.StackLayout.prototype.addItems = function ( items, index ) { OO.ui.GroupElement.prototype.addItems.call( this, items, index ); + + if ( !this.currentItem && items.length ) { + this.setItem( items[0] ); + } return this; }; @@ -3563,12 +3663,12 @@ * @param {OO.ui.PanelLayout[]} items Items to remove * @chainable */ -OO.ui.StackPanelLayout.prototype.removeItems = function ( items ) { +OO.ui.StackLayout.prototype.removeItems = function ( items ) { OO.ui.GroupElement.prototype.removeItems.call( this, items ); if ( items.indexOf( this.currentItem ) !== -1 ) { this.currentItem = null; if ( !this.currentItem && this.items.length ) { - this.showItem( this.items[0] ); + this.setItem( this.items[0] ); } } @@ -3583,7 +3683,7 @@ * @method * @chainable */ -OO.ui.StackPanelLayout.prototype.clearItems = function () { +OO.ui.StackLayout.prototype.clearItems = function () { this.currentItem = null; OO.ui.GroupElement.prototype.clearItems.call( this ); @@ -3599,10 +3699,19 @@ * @param {OO.ui.PanelLayout} item Item to show * @chainable */ -OO.ui.StackPanelLayout.prototype.showItem = function ( item ) { - this.$items.hide(); - item.$element.show(); +OO.ui.StackLayout.prototype.setItem = function ( item ) { + if ( !this.continuous ) { + this.$items.css( 'display', '' ); + } + if ( this.items.indexOf( item ) !== -1 ) { + if ( !this.continuous ) { + item.$element.css( 'display', 'block' ); + } + } else { + item = null; + } this.currentItem = item; + this.emit( 'set', item ); return this; }; @@ -4087,14 +4196,16 @@ // Properties this.$input = this.getInputElement( config ); this.value = ''; - this.readonly = false; + this.readOnly = false; this.inputFilter = config.inputFilter; // Events this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) ); // Initialization - this.$input.attr( 'name', config.name ); + this.$input + .attr( 'name', config.name ) + .prop( 'disabled', this.disabled ); this.setReadOnly( config.readOnly ); this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input ); this.setValue( config.value ); @@ -4230,6 +4341,112 @@ this.$input.prop( 'readonly', this.readOnly ); return this; }; + +/** + * @inheritdoc + */ +OO.ui.InputWidget.prototype.setDisabled = function ( state ) { + OO.ui.Widget.prototype.setDisabled.call( this, state ); + if ( this.$input ) { + this.$input.prop( 'disabled', this.disabled ); + } + return this; +};/** + * Creates an OO.ui.CheckboxInputWidget object. + * + * @class + * @extends OO.ui.InputWidget + * + * @constructor + * @param {Object} [config] Configuration options + */ +OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) { + config = config || {}; + + // Parent constructor + OO.ui.InputWidget.call( this, config ); + + this.value = false; + + // Initialization + this.$element.addClass( 'oo-ui-checkboxInputWidget' ); +}; + +/* Inheritance */ + +OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget ); + +/* Events */ + +/* Methods */ + +/** + * Get input element. + * + * @returns {jQuery} Input element + */ +OO.ui.CheckboxInputWidget.prototype.getInputElement = function () { + return this.$( '<input type="checkbox" />' ); +}; + +/** + * Get checked state of the checkbox + * + * @returns {boolean} If the checkbox is checked + */ +OO.ui.CheckboxInputWidget.prototype.getValue = function () { + return this.value; +}; + +/** + * Set value + */ +OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) { + if ( this.value !== value ) { + this.value = !!value; + this.$element.attr( 'checked', this.value ); + this.emit( 'change', this.value ); + } +}; + +/** + * @inheritdoc + */ +OO.ui.CheckboxInputWidget.prototype.onEdit = function () { + if ( !this.disabled ) { + // Allow the stack to clear so the value will be updated + setTimeout( OO.ui.bind( function () { + this.setValue( this.$input.attr( 'checked' ) ); + }, this ) ); + } +};/** + * Creates an OO.ui.CheckboxWidget object. + * + * @class + * @extends OO.ui.CheckboxInputWidget + * @mixins OO.ui.LabeledElement + * + * @constructor + * @param {Object} [config] Configuration options + * @cfg {string} [label=''] Label + */ +OO.ui.CheckboxWidget = function OoUiCheckboxWidget( config ) { + config = config || {}; + + // Parent constructors + OO.ui.CheckboxInputWidget.call( this, config ); + OO.ui.LabeledElement.call( this, this.$( '<span>' ) , config ); + + this.$( '<label>' ).append( this.$input, this.$label ).appendTo( this.$element ); + + // Initialization + this.$element.addClass( 'oo-ui-checkboxWidget' ); +}; + +/* Inheritance */ + +OO.inheritClass( OO.ui.CheckboxWidget, OO.ui.CheckboxInputWidget ); +OO.mixinClass( OO.ui.CheckboxWidget, OO.ui.LabeledElement ); /** * Creates an OO.ui.InputLabelWidget object. * @@ -6203,7 +6420,7 @@ * @returns {jQuery} Input element */ OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) { - return config.multiline ? this.$( '<textarea>' ) : this.$( '<input>' ).attr( 'type', 'text' ); + return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' ); }; /* Methods */ @@ -6367,7 +6584,7 @@ // Configuration initialization config = $.extend( { 'onLabel': OO.ui.msg( 'ooui-toggle-on' ), - 'offLabel': OO.ui.msg( 'ooui-toggle-on' ) + 'offLabel': OO.ui.msg( 'ooui-toggle-off' ) }, config ); // Parent constructor @@ -6425,7 +6642,7 @@ * @param {jQuery.Event} e Mouse down event */ OO.ui.ToggleWidget.prototype.onMouseDown = function ( e ) { - if ( e.which === 1 ) { + if ( !this.disabled && e.which === 1 ) { this.dragging = true; this.dragStart = e.pageX; this.$( this.$.context ).on( { diff --git a/modules/oojs-ui/oojs-ui.svg.css b/modules/oojs-ui/oojs-ui.svg.css index 3301808..5368772 100644 --- a/modules/oojs-ui/oojs-ui.svg.css +++ b/modules/oojs-ui/oojs-ui.svg.css @@ -1,12 +1,12 @@ /*! - * OOJS UI v0.1.0-pre-svg (e5ef1e5b28) + * OOJS UI v0.1.0-pre-svg (d3ce971b6c) * https://www.mediawiki.org/wiki/OOJS * * Copyright 2011-2013 OOJS Team and other contributors. * Released under the MIT license * http://oojs.mit-license.org * - * Date: Mon Nov 25 2013 10:40:32 GMT+0000 (GMT) + * Date: Thu Dec 05 2013 11:44:05 GMT-0800 (PST) */ /*csslint vendor-prefix:false */ @@ -199,46 +199,6 @@ margin: 0.25em 0.25em; } -/* OO.ui.PagedLayout */ - -.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout { - padding: 1.5em; - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout-scrollable { - overflow-y: auto; -} - -.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout-padded { - padding: 2em; -} - -/* OO.ui.PagedOutlineLayout */ - -.oo-ui-pagedOutlineLayout-outlinePanel { - border-right: solid 1px #ddd; -} - -.oo-ui-pagedOutlineLayout-outlinePanel-editable .oo-ui-outlineWidget { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 3em; - overflow-y: auto; -} - -.oo-ui-pagedOutlineLayout-outlinePanel .oo-ui-outlineControlsWidget { - position: absolute; - bottom: 0; - left: 0; - right: 0; - box-shadow: 0 0 0.25em rgba(0,0,0,0.25); -} /* OO.ui.LabeledElement */ .oo-ui-labeledElement-label { @@ -289,8 +249,12 @@ .oo-ui-fieldsetLayout { border: none; - margin: 0 0 1.75em 0; + margin: 0; padding: 0; +} + +.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout { + margin-top: 2em; } .oo-ui-fieldsetLayout-labeled { @@ -306,6 +270,60 @@ padding-left: 1.75em; background-position: left center; background-repeat: no-repeat; +} + +/* OO.ui.BookletLayout */ + +.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout { + padding: 1.5em; + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable { + overflow-y: auto; +} + +.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded { + padding: 2em; +} + +.oo-ui-bookletLayout-outlinePanel { + border-right: solid 1px #ddd; +} + +.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 3em; + overflow-y: auto; +} + +.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget { + position: absolute; + bottom: 0; + left: 0; + right: 0; + box-shadow: 0 0 0.25em rgba(0,0,0,0.25); +} + +.oo-ui-stackLayout > .oo-ui-panelLayout { + display: none; +} + +.oo-ui-stackLayout-continuous > .oo-ui-panelLayout { + display: block; + position: relative; + margin-bottom: 1em; + box-shadow: 0 0 0.5em rgba(0,0,0,0.25); +} + +.oo-ui-stackLayout-continuous > .oo-ui-panelLayout:last-child { + margin-bottom: 0; } /* OO.ui.PopupTool */ @@ -1094,6 +1112,21 @@ background-repeat: no-repeat; } +/* OO.ui.CheckboxWidget */ +.oo-ui-checkboxWidget .oo-ui-labeledElement-label { + display: inline-block; + vertical-align: middle; + padding-left: 0.5em; +} + +.oo-ui-checkboxWidget input { + vertical-align: middle; +} + +.oo-ui-checkboxWidget.oo-ui-widget-disabled .oo-ui-labeledElement-label { + opacity: 0.5; +} + /* OO.ui.MenuWidget */ .oo-ui-menuWidget { @@ -1259,6 +1292,10 @@ transition: background-color 200ms; } +.oo-ui-toggleWidget.oo-ui-widget-disabled { + opacity: 0.5; +} + .oo-ui-toggleWidget-slide { position: absolute; top: 0; @@ -1316,7 +1353,7 @@ background-image: linear-gradient(top, #ffffff 0%, #f0f0f0 100%); } -.oo-ui-toggleWidget:hover, +.oo-ui-toggleWidget:not(.oo-ui-widget-disabled):hover, .oo-ui-toggleWidget-dragging, .oo-ui-toggleWidget:hover .oo-ui-toggleWidget-grip, .oo-ui-toggleWidget-dragging .oo-ui-toggleWidget-grip { -- To view, visit https://gerrit.wikimedia.org/r/99457 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibaa14d20af212987e9abf5bf12668992e5a80da2 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/VisualEditor Gerrit-Branch: master Gerrit-Owner: Trevor Parscal <[email protected]> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
