-/* eslint-disable no-use-before-define */
( function ( $, mw, OO ) {
'use strict';
var ApiSandbox, Util, WidgetMethods, Validators,
moduleInfoCache = {},
baseRequestParams;
+ /**
+ * A wrapper for a widget that provides an enable/disable button
+ *
+ * @class
+ * @private
+ * @constructor
+ * @param {OO.ui.Widget} widget
+ * @param {Object} [config] Configuration options
+ */
+ function OptionalWidget( widget, config ) {
+ var k;
+
+ config = config || {};
+
+ this.widget = widget;
+ this.$cover = config.$cover ||
+ $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-cover' );
+ this.checkbox = new OO.ui.CheckboxInputWidget( config.checkbox )
+ .on( 'change', this.onCheckboxChange, [], this );
+
+ OptionalWidget[ 'super' ].call( this, config );
+
+ // Forward most methods for convenience
+ for ( k in this.widget ) {
+ if ( $.isFunction( this.widget[ k ] ) && !this[ k ] ) {
+ this[ k ] = this.widget[ k ].bind( this.widget );
+ }
+ }
+
+ this.$cover.on( 'click', this.onOverlayClick.bind( this ) );
+
+ this.$element
+ .addClass( 'mw-apisandbox-optionalWidget' )
+ .append(
+ this.$cover,
+ $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-fields' ).append(
+ $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-widget' ).append(
+ widget.$element
+ ),
+ $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-checkbox' ).append(
+ this.checkbox.$element
+ )
+ )
+ );
+
+ this.setDisabled( widget.isDisabled() );
+ }
+ OO.inheritClass( OptionalWidget, OO.ui.Widget );
+ OptionalWidget.prototype.onCheckboxChange = function ( checked ) {
+ this.setDisabled( !checked );
+ };
+ OptionalWidget.prototype.onOverlayClick = function () {
+ this.setDisabled( false );
+ if ( $.isFunction( this.widget.focus ) ) {
+ this.widget.focus();
+ }
+ };
+ OptionalWidget.prototype.setDisabled = function ( disabled ) {
+ OptionalWidget[ 'super' ].prototype.setDisabled.call( this, disabled );
+ this.widget.setDisabled( this.isDisabled() );
+ this.checkbox.setSelected( !this.isDisabled() );
+ this.$cover.toggle( this.isDisabled() );
+ return this;
+ };
+
WidgetMethods = {
textInputWidget: {
getApiValue: function () {
* @return {OO.ui.Widget}
*/
createWidgetForParameter: function ( pi, opts ) {
- var widget, innerWidget, finalWidget, items, $button, $content, func,
- multiMode = 'none';
+ var widget, innerWidget, finalWidget, items, $content, func,
+ multiModeButton = null,
+ multiModeInput = null,
+ multiModeAllowed = false;
opts = opts || {};
$.extend( widget, WidgetMethods.textInputWidget );
$.extend( widget, WidgetMethods.passwordWidget );
widget.setValidation( Validators.generic );
- multiMode = 'enter';
+ multiModeAllowed = true;
+ multiModeInput = widget;
break;
case 'integer':
if ( Util.apiBool( pi.enforcerange ) ) {
widget.setRange( pi.min || -Infinity, pi.max || Infinity );
}
- multiMode = 'enter';
+ multiModeAllowed = true;
+ multiModeInput = widget;
break;
case 'limit':
pi.apiSandboxMax = mw.config.get( 'apihighlimits' ) ? pi.highmax : pi.max;
widget.paramInfo = pi;
$.extend( widget, WidgetMethods.textInputWidget );
- multiMode = 'enter';
+ multiModeAllowed = true;
+ multiModeInput = widget;
break;
case 'timestamp':
widget.paramInfo = pi;
$.extend( widget, WidgetMethods.textInputWidget );
$.extend( widget, WidgetMethods.dateTimeInputWidget );
- multiMode = 'indicator';
+ multiModeAllowed = true;
break;
case 'upload':
break;
}
- if ( Util.apiBool( pi.multi ) && multiMode !== 'none' ) {
+ if ( Util.apiBool( pi.multi ) && multiModeAllowed ) {
innerWidget = widget;
- switch ( multiMode ) {
- case 'enter':
- $content = innerWidget.$element;
- break;
-
- case 'indicator':
- $button = innerWidget.$indicator;
- $button.css( 'cursor', 'pointer' );
- $button.attr( 'tabindex', 0 );
- $button.parent().append( $button );
- innerWidget.setIndicator( 'next' );
- $content = innerWidget.$element;
- break;
-
- default:
- throw new Error( 'Unknown multiMode "' + multiMode + '"' );
- }
+
+ multiModeButton = new OO.ui.ButtonWidget( {
+ label: mw.message( 'apisandbox-add-multi' ).text()
+ } );
+ $content = innerWidget.$element.add( multiModeButton.$element );
widget = new OO.ui.PopupTagMultiselectWidget( {
allowArbitrary: true,
$overlay: true,
popup: {
classes: [ 'mw-apisandbox-popup' ],
+ padded: true,
$content: $content
}
} );
return false;
}
};
- switch ( multiMode ) {
- case 'enter':
- innerWidget.connect( null, { enter: func } );
- break;
-
- case 'indicator':
- $button.on( {
- click: func,
- keypress: function ( e ) {
- if ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) {
- func();
- }
- }
- } );
- break;
+
+ if ( multiModeInput ) {
+ multiModeInput.on( 'enter', func );
}
+ multiModeButton.on( 'click', func );
}
if ( Util.apiBool( pi.required ) || opts.nooptional ) {
ApiSandbox.updateUI();
}
- // If the hashchange event exists, use it. Otherwise, fake it.
- // And, of course, IE has to be dumb.
- if ( 'onhashchange' in window &&
- ( document.documentMode === undefined || document.documentMode >= 8 )
- ) {
- $( window ).on( 'hashchange', ApiSandbox.loadFromHash );
- } else {
- setInterval( function () {
- if ( oldhash !== location.hash ) {
- ApiSandbox.loadFromHash();
- }
- }, 1000 );
- }
+ $( window ).on( 'hashchange', ApiSandbox.loadFromHash );
$content
.empty()
deferreds = [],
paramsAreForced = !!params,
displayParams = {},
+ tokenWidgets = [],
checkPages = [ pages.main ];
// Blur any focused widget before submit, because
params = {};
while ( checkPages.length ) {
page = checkPages.shift();
- deferreds.push( page.apiCheckValid() );
+ if ( page.tokenWidget ) {
+ tokenWidgets.push( page.tokenWidget );
+ }
+ deferreds = deferreds.concat( page.apiCheckValid() );
page.getQueryParams( params, displayParams );
subpages = page.getSubpages();
for ( i = 0; i < subpages.length; i++ ) {
}
$.when.apply( $, deferreds ).done( function () {
- var formatItems, menu, selectedLabel;
+ var formatItems, menu, selectedLabel, deferred, actions, errorCount;
+
+ // Count how many times `value` occurs in `array`.
+ function countValues( value, array ) {
+ var count, i;
+ count = 0;
+ for ( i = 0; i < array.length; i++ ) {
+ if ( array[ i ] === value ) {
+ count++;
+ }
+ }
+ return count;
+ }
- if ( $.inArray( false, arguments ) !== -1 ) {
- windowManager.openWindow( 'errorAlert', {
- title: Util.parseMsg( 'apisandbox-submit-invalid-fields-title' ),
- message: Util.parseMsg( 'apisandbox-submit-invalid-fields-message' ),
- actions: [
- {
- action: 'accept',
- label: OO.ui.msg( 'ooui-dialog-process-dismiss' ),
- flags: 'primary'
+ errorCount = countValues( false, arguments );
+ if ( errorCount > 0 ) {
+ actions = [
+ {
+ action: 'accept',
+ label: OO.ui.msg( 'ooui-dialog-process-dismiss' ),
+ flags: 'primary'
+ }
+ ];
+ if ( tokenWidgets.length ) {
+ // Check all token widgets' validity separately
+ deferred = $.when.apply( $, tokenWidgets.map( function ( w ) {
+ return w.apiCheckValid();
+ } ) );
+
+ deferred.done( function () {
+ // If only the tokens are invalid, offer to fix them
+ var tokenErrorCount = countValues( false, arguments );
+ if ( tokenErrorCount === errorCount ) {
+ delete actions[ 0 ].flags;
+ actions.push( {
+ action: 'fix',
+ label: mw.message( 'apisandbox-results-fixtoken' ).text(),
+ flags: 'primary'
+ } );
}
- ]
+ } );
+ } else {
+ deferred = $.Deferred().resolve();
+ }
+ deferred.always( function () {
+ windowManager.openWindow( 'errorAlert', {
+ title: Util.parseMsg( 'apisandbox-submit-invalid-fields-title' ),
+ message: Util.parseMsg( 'apisandbox-submit-invalid-fields-message' ),
+ actions: actions
+ } ).closed.then( function ( data ) {
+ if ( data && data.action === 'fix' ) {
+ ApiSandbox.fixTokenAndResend();
+ }
+ } );
} );
return;
}
/**
* Check that all widgets on the page are in a valid state.
*
- * @return {boolean}
+ * @return {jQuery.Promise[]} One promise for each widget, resolved with `false` if invalid
*/
ApiSandbox.PageLayout.prototype.apiCheckValid = function () {
- var that = this;
+ var promises, that = this;
if ( this.paramInfo === null ) {
- return $.Deferred().resolve( false ).promise();
+ return [];
} else {
- return $.when.apply( $, $.map( this.widgets, function ( widget ) {
+ promises = $.map( this.widgets, function ( widget ) {
return widget.apiCheckValid();
- } ) ).then( function () {
+ } );
+ $.when.apply( $, promises ).then( function () {
that.apiIsValid = $.inArray( false, arguments ) === -1;
if ( that.getOutlineItem() ) {
that.getOutlineItem().setIcon( that.apiIsValid || suppressErrors ? null : 'alert' );
that.apiIsValid || suppressErrors ? '' : mw.message( 'apisandbox-alert-page' ).plain()
);
}
- return $.Deferred().resolve( that.apiIsValid ).promise();
} );
+ return promises;
}
};
return ret;
};
- /**
- * A wrapper for a widget that provides an enable/disable button
- *
- * @class
- * @private
- * @constructor
- * @param {OO.ui.Widget} widget
- * @param {Object} [config] Configuration options
- */
- function OptionalWidget( widget, config ) {
- var k;
-
- config = config || {};
-
- this.widget = widget;
- this.$cover = config.$cover ||
- $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-cover' );
- this.checkbox = new OO.ui.CheckboxInputWidget( config.checkbox )
- .on( 'change', this.onCheckboxChange, [], this );
-
- OptionalWidget[ 'super' ].call( this, config );
-
- // Forward most methods for convenience
- for ( k in this.widget ) {
- if ( $.isFunction( this.widget[ k ] ) && !this[ k ] ) {
- this[ k ] = this.widget[ k ].bind( this.widget );
- }
- }
-
- this.$cover.on( 'click', this.onOverlayClick.bind( this ) );
-
- this.$element
- .addClass( 'mw-apisandbox-optionalWidget' )
- .append(
- this.$cover,
- $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-fields' ).append(
- $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-widget' ).append(
- widget.$element
- ),
- $( '<div>' ).addClass( 'mw-apisandbox-optionalWidget-checkbox' ).append(
- this.checkbox.$element
- )
- )
- );
-
- this.setDisabled( widget.isDisabled() );
- }
- OO.inheritClass( OptionalWidget, OO.ui.Widget );
- OptionalWidget.prototype.onCheckboxChange = function ( checked ) {
- this.setDisabled( !checked );
- };
- OptionalWidget.prototype.onOverlayClick = function () {
- this.setDisabled( false );
- if ( $.isFunction( this.widget.focus ) ) {
- this.widget.focus();
- }
- };
- OptionalWidget.prototype.setDisabled = function ( disabled ) {
- OptionalWidget[ 'super' ].prototype.setDisabled.call( this, disabled );
- this.widget.setDisabled( this.isDisabled() );
- this.checkbox.setSelected( !this.isDisabled() );
- this.$cover.toggle( this.isDisabled() );
- return this;
- };
-
$( ApiSandbox.init );
module.exports = ApiSandbox;