/**
* JS for campaign editor (handled by Special:CentralNotice)
*
* This file is part of the CentralNotice Extension to MediaWiki
* https://www.mediawiki.org/wiki/Extension:CentralNotice
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
( function () {
var stepSize = 1,
mixinDefs = mw.config.get( 'wgCentralNoticeCampaignMixins' ),
mixinParamsTemplate = mw.template.get(
'ext.centralNotice.adminUi.campaignManager',
'campaignMixinParamControls.mustache'
),
$form, $submitBtn,
MixinCustomUiController, MixinCustomWidget,
ErrorStateTracker,
mixinCustomUiControllerFactory = new OO.Factory(),
errorStateTracker, eventBus, assignedBanners,
BUCKET_LABELS = [ 'A', 'B', 'C', 'D' ]; // TODO Fix for configs with more buckets
/* Event bus */
/**
* eventBus: A simple object for subscribing to and emitting events.
*/
/**
* @event bucket-change
*
* The control for the number of buckets in the campaign has changed.
* @param {number} numBuckets
*/
/**
* @event assigned-banners-change
*
* The controls for banner assignment (bucket assignments and banner removal
* checkboxes) have changed. Note: This event does not fire when a checkbox for
* adding a banner is checked.
*/
/**
* @event error-state
*
* An error state is set or removed
* @param {string} errorKey
* @param {boolean} state true to set error, false to clear one.
*/
eventBus = new OO.EventEmitter();
/* MixinCustomUiController */
// Note: the following code uses two completely distinct meanings of
// "mixin". One is "campaign mixin", bits of JS code that can run in the
// browsers of users in specific campaigns. The other is the OOjs concept
// of mixin, that is, a bit of functionality that can be added to a
// javascript class. For example, the MixinCustomWidget class provides a
// bit of UI for a campaign mixin, and it mixes in, in the OOjs sense,
// functionality from OO.ui.mixin.GroupElement.
/**
* Base class for custom campaign mixin UI controllers.
*
* Provides facilities for setting hidden form input elements for mixin parameter
* values. This lets custom mixins provide interactive interfaces that are not input
* elements, and send data to the server via these hidden inputs.
*
* Note: Subclasses are expected to be singletons.
*
* @abstract
* @class MixinCustomUiController
* @constructor
*/
MixinCustomUiController = function () {
// Declare the abstract property here, but don't force it to null, in case the
// subclass decides to set it before calling the constructor.
/**
* The element of the corresponding MixinCustomWidget.
*
* @abstract
* @property {jQuery}
*/
this.$widgetElement = this.$widgetElement || null;
};
OO.initClass( MixinCustomUiController );
/**
* The name of the campaign mixin that this control group sets the parameters for.
*
* @abstract
* @inheritable
* @static
* @property {string}
*/
MixinCustomUiController.static.name = null;
/**
* Initialize the controller with the data provided.
*
* @method
* @abstract
* @param {Object} data Object in which properties and their values are mixin
* parameter names and values. Format should coordinate with the format sent
* to the client via the 'mixin-param-values' data value on the checkbox that
* enables the mixin.
*/
MixinCustomUiController.prototype.init = null;
/**
* Set the (string-encoded) value of a mixin parameter via a hidden input element.
*
* @param {string} name The name of the parameter.
* @param {string} value The value (formatted as appropriate for form submission).
*/
MixinCustomUiController.prototype.setParam = function ( name, value ) {
var $input = this.getParamInputEl( name, true );
$input.val( value );
};
/**
* Remove a mixin parameter's hidden input element, if it exists.
*
* @param {string} name The name of the parameter
*/
MixinCustomUiController.prototype.removeParam = function ( name ) {
var $input = this.getParamInputEl( name, false );
if ( $input.length ) {
$input.remove();
}
};
/**
* Get the hidden input element for a mixin parameter, if it exists. If requested,
* create it if it doesn't exist.
*
* @private
* @param {string} name The name of the parameter
* @param {boolean} create Create the element if it doesn't exist
* @return {jQuery|null}
*/
MixinCustomUiController.prototype.getParamInputEl = function ( name, create ) {
var inputName = makeNoticeMixinControlName( this.constructor.static.name, name ),
$input = $form.find( 'input[name="' + inputName + '"]' );
if ( create && !( $input.length ) ) {
$input = $( '' ).attr( {
name: inputName,
type: 'hidden'
} );
$form.append( $input );
}
return $input;
};
/* MixinCustomWidget */
/**
* Base class for custom campaign mixin widgets.
*
* @abstract
* @class MixinCustomWidget
* @extends OO.ui.Widget
* @mixes OO.ui.mixin.GroupWidget
* @constructor
*
* @param {MixinCustomUiController} controller
* @param {Object} [config] Configuration options
*/
MixinCustomWidget = function ( controller, config ) {
var $element = $( '