jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/328676 )
Change subject: RC filters: AJAX and pushState/popState
......................................................................
RC filters: AJAX and pushState/popState
Selecting/unselecting a filter now refreshes the results list using AJAX.
Also added pushState to update the URL, and popstate handling
to make the back button work.
Bug: T153949
Change-Id: I8c1ec557ccfe4b1d20aaaab3ef0d3182a1993f24
---
M resources/Resources.php
A resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
M resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
M resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
M resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js
A
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
A resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CheckboxInputWidget.js
M
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
M resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js
M resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
A resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
11 files changed, 313 insertions(+), 79 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/resources/Resources.php b/resources/Resources.php
index 7961139..02487ea 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -1757,12 +1757,16 @@
'resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js',
'resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js',
'resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js',
+
'resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js',
+
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CheckboxInputWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FiltersListWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterGroupWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js',
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js',
+
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js',
+
'resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js',
'resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js',
'resources/src/mediawiki.rcfilters/mw.rcfilters.init.js',
],
@@ -1820,6 +1824,7 @@
'rcfilters-filter-categorization-description',
'rcfilters-filter-logactions-label',
'rcfilters-filter-logactions-description',
+ 'recentchanges-noresult',
],
'dependencies' => [
'oojs-ui',
diff --git
a/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
new file mode 100644
index 0000000..edb6744
--- /dev/null
+++
b/resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.ChangesListViewModel.js
@@ -0,0 +1,59 @@
+( function ( mw ) {
+ /**
+ * View model for the changes list
+ *
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ */
+ mw.rcfilters.dm.ChangesListViewModel = function
MwRcfiltersDmChangesListViewModel() {
+ // Mixin constructor
+ OO.EventEmitter.call( this );
+
+ this.valid = true;
+ };
+
+ /* Initialization */
+ OO.initClass( mw.rcfilters.dm.ChangesListViewModel );
+ OO.mixinClass( mw.rcfilters.dm.ChangesListViewModel, OO.EventEmitter );
+
+ /* Events */
+
+ /**
+ * @event invalidate
+ *
+ * The list of changes is now invalid (out of date)
+ */
+
+ /**
+ * @event update
+ * @param {jQuery|string} changesListContent
+ *
+ * The list of change is now up to date
+ */
+
+ /* Methods */
+
+ /**
+ * Invalidate the list of changes
+ *
+ * @fires invalidate
+ */
+ mw.rcfilters.dm.ChangesListViewModel.prototype.invalidate = function ()
{
+ if ( this.valid ) {
+ this.valid = false;
+ this.emit( 'invalidate' );
+ }
+ };
+
+ /**
+ * Update the model with an updated list of changes
+ *
+ * @param {jQuery|string} changesListContent
+ */
+ mw.rcfilters.dm.ChangesListViewModel.prototype.update = function (
changesListContent ) {
+ this.valid = true;
+ this.emit( 'update', changesListContent );
+ };
+
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
index 28d9f28..88f32b4 100644
--- a/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
+++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
@@ -1,13 +1,14 @@
-( function ( mw ) {
+( function ( mw, $ ) {
/**
* Controller for the filters in Recent Changes
*
- * @param {mw.rcfilters.dm.FiltersViewModel} model View model
+ * @param {mw.rcfilters.dm.FiltersViewModel} filtersModel Filters view
model
+ * @param {mw.rcfilters.dm.ChangesListViewModel} changesListModel
Changes list view model
*/
- mw.rcfilters.Controller = function MwRcfiltersController( model ) {
- this.model = model;
- // TODO: When we are ready, update the URL when a filter is
updated
- // this.model.connect( this, { itemUpdate: 'updateURL' } );
+ mw.rcfilters.Controller = function MwRcfiltersController( filtersModel,
changesListModel ) {
+ this.filtersModel = filtersModel;
+ this.changesListModel = changesListModel;
+ this.requestCounter = 0;
};
/* Initialization */
@@ -17,13 +18,18 @@
* Initialize the filter and parameter states
*/
mw.rcfilters.Controller.prototype.initialize = function () {
+ this.updateFromURL();
+ };
+
+ /**
+ * Update the model state based on the URL parameters.
+ */
+ mw.rcfilters.Controller.prototype.updateFromURL = function () {
var uri = new mw.Uri();
- // Give the model a full parameter state from which to
- // update the filters
- this.model.updateFilters(
+ this.filtersModel.updateFilters(
// Translate the url params to filter select states
- this.model.getFiltersFromParameters( uri.query )
+ this.filtersModel.getFiltersFromParameters( uri.query )
);
};
@@ -31,14 +37,18 @@
* Reset to default filters
*/
mw.rcfilters.Controller.prototype.resetToDefaults = function () {
- this.model.setFiltersToDefaults();
+ this.filtersModel.setFiltersToDefaults();
+ this.updateURL();
+ this.updateChangesList();
};
/**
* Empty all selected filters
*/
mw.rcfilters.Controller.prototype.emptyFilters = function () {
- this.model.emptyAllFilters();
+ this.filtersModel.emptyAllFilters();
+ this.updateURL();
+ this.updateChangesList();
};
/**
@@ -51,7 +61,9 @@
var obj = {};
obj[ filterName ] = isSelected;
- this.model.updateFilters( obj );
+ this.filtersModel.updateFilters( obj );
+ this.updateURL();
+ this.updateChangesList();
};
/**
@@ -64,9 +76,44 @@
// TODO: Clean up the list of filters; perhaps 'falsy' filters
// shouldn't appear at all? Or compare to existing query string
// and see if current state of a specific filter is needed?
- uri.extend( this.model.getParametersFromFilters() );
+ uri.extend( this.filtersModel.getParametersFromFilters() );
// Update the URL itself
window.history.pushState( { tag: 'rcfilters' }, document.title,
uri.toString() );
};
-}( mediaWiki ) );
+
+ /**
+ * Fetch the list of changes from the server for the current filters
+ *
+ * @returns {jQuery.Promise} Promise object that will resolve with the
changes list
+ */
+ mw.rcfilters.Controller.prototype.fetchChangesList = function () {
+ var uri = new mw.Uri(),
+ requestId = ++this.requestCounter,
+ latestRequest = function () {
+ return requestId === this.requestCounter;
+ }.bind( this );
+ uri.extend( this.filtersModel.getParametersFromFilters() );
+ return $.ajax( uri.toString(), { contentType: 'html' } )
+ .then( function ( html ) {
+ return latestRequest() ?
+ $( $.parseHTML( html ) ).find(
'.mw-changeslist' ).first().contents() :
+ null;
+ } ).then( null, function () {
+ return latestRequest() ? 'NO_RESULTS' : null;
+ } );
+ };
+
+ /**
+ * Update the list of changes and notify the model
+ */
+ mw.rcfilters.Controller.prototype.updateChangesList = function () {
+ this.changesListModel.invalidate();
+ this.fetchChangesList()
+ .always( function ( changesListContent ) {
+ if ( changesListContent ) {
+ this.changesListModel.update(
changesListContent );
+ }
+ }.bind( this ) );
+ };
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
index 94fc959..ef0489c 100644
--- a/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
+++ b/resources/src/mediawiki.rcfilters/mw.rcfilters.init.js
@@ -9,13 +9,23 @@
var rcfilters = {
/** */
init: function () {
- var model = new mw.rcfilters.dm.FiltersViewModel(),
- controller = new mw.rcfilters.Controller( model
),
+ var filtersModel = new
mw.rcfilters.dm.FiltersViewModel(),
+ changesListModel = new
mw.rcfilters.dm.ChangesListViewModel(),
+ controller = new mw.rcfilters.Controller(
filtersModel, changesListModel ),
$overlay = $( '<div>' )
.addClass( 'mw-rcfilters-ui-overlay' ),
- widget = new
mw.rcfilters.ui.FilterWrapperWidget( controller, model, { $overlay: $overlay }
);
+ filtersWidget = new
mw.rcfilters.ui.FilterWrapperWidget(
+ controller, filtersModel, { $overlay:
$overlay } );
- model.initializeFilters( {
+ // eslint-disable-next-line no-new
+ new mw.rcfilters.ui.ChangesListWrapperWidget(
+ changesListModel, $( '.mw-changeslist,
.mw-changeslist-empty' ) );
+
+ // eslint-disable-next-line no-new
+ new mw.rcfilters.ui.FormWrapperWidget(
+ changesListModel, $( '.rcoptions form' ) );
+
+ filtersModel.initializeFilters( {
registration: {
title: mw.msg(
'rcfilters-filtergroup-registration' ),
type: 'send_unselected_if_any',
@@ -149,7 +159,7 @@
}
} );
- $( '.rcoptions' ).before( widget.$element );
+ $( '.rcoptions' ).before( filtersWidget.$element );
$( 'body' ).append( $overlay );
// Initialize values
@@ -179,7 +189,7 @@
name = 'hidemyself';
}
// This span corresponds to a filter that's in
our model, so remove it
- if ( model.getItemByName( name ) ) {
+ if ( filtersModel.getItemByName( name ) ) {
// HACK: Remove the text node after the
span.
// If there isn't one, we're at the
end, so remove the text node before the span.
// This would be unnecessary if we
added separators with CSS.
@@ -193,31 +203,9 @@
}
} );
- $( '.rcoptions form' ).submit( function () {
- var $form = $( this );
-
- // Get current filter values
- $.each( model.getParametersFromFilters(),
function ( paramName, paramValue ) {
- var $existingInput = $form.find(
'input[name=' + paramName + ']' );
- // Check if the hidden input already
exists
- // This happens if the parameter was
already given
- // on load
- if ( $existingInput.length ) {
- // Update the value
- $existingInput.val( paramValue
);
- } else {
- // Append hidden fields with
filter values
- $form.append(
- $( '<input>' )
- .attr( 'type',
'hidden' )
- .attr( 'name',
paramName )
- .val(
paramValue )
- );
- }
- } );
-
- // Continue the submission process
- return true;
+ window.addEventListener( 'popstate', function () {
+ controller.updateFromURL();
+ controller.updateChangesList();
} );
}
};
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js
index 547db1b..ca47f16 100644
--- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js
+++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CapsuleItemWidget.js
@@ -7,11 +7,12 @@
* @mixins OO.ui.mixin.PopupElement
*
* @constructor
+ * @param {mw.rcfilters.Controller} controller
* @param {mw.rcfilters.dm.FilterItem} model Item model
* @param {Object} config Configuration object
* @cfg {jQuery} [$overlay] A jQuery object serving as overlay for
popups
*/
- mw.rcfilters.ui.CapsuleItemWidget = function
MwRcfiltersUiCapsuleItemWidget( model, config ) {
+ mw.rcfilters.ui.CapsuleItemWidget = function
MwRcfiltersUiCapsuleItemWidget( controller, model, config ) {
var $popupContent = $( '<div>' )
.addClass( 'mw-rcfilters-ui-capsuleItemWidget-popup' ),
descLabelWidget = new OO.ui.LabelWidget();
@@ -19,6 +20,7 @@
// Configuration initialization
config = config || {};
+ this.controller = controller;
this.model = model;
this.$overlay = config.$overlay || this.$element;
this.positioned = false;
@@ -45,6 +47,8 @@
// Events
this.model.connect( this, { update: 'onModelUpdate' } );
+
+ this.closeButton.connect( this, { click:
'onCapsuleRemovedByUser' } );
// Initialization
this.$overlay.append( this.popup.$element );
@@ -86,4 +90,11 @@
}
}
};
+
+ /**
+ * Respond to the user removing the capsule with the close button
+ */
+ mw.rcfilters.ui.CapsuleItemWidget.prototype.onCapsuleRemovedByUser =
function () {
+ this.controller.updateFilter( this.model.getName(), false );
+ };
}( mediaWiki, jQuery ) );
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
new file mode 100644
index 0000000..f929eb2
--- /dev/null
+++
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ChangesListWrapperWidget.js
@@ -0,0 +1,60 @@
+( function ( mw ) {
+ /**
+ * List of changes
+ *
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.PendingElement
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.ChangesListViewModel} model View model
+ * @param {jQuery} $changesListRoot Root element of the changes list to
attach to
+ * @param {Object} config Configuration object
+ */
+ mw.rcfilters.ui.ChangesListWrapperWidget = function
MwRcfiltersUiChangesListWrapperWidget( model, $changesListRoot, config ) {
+ config = config || {};
+
+ // Parent
+ mw.rcfilters.ui.ChangesListWrapperWidget.parent.call( this,
$.extend( {}, config, {
+ $element: $changesListRoot
+ } ) );
+ // Mixin constructors
+ OO.ui.mixin.PendingElement.call( this, config );
+
+ this.model = model;
+
+ // Events
+ this.model.connect( this, {
+ invalidate: 'onModelInvalidate',
+ update: 'onModelUpdate'
+ } );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.rcfilters.ui.ChangesListWrapperWidget, OO.ui.Widget
);
+ OO.mixinClass( mw.rcfilters.ui.ChangesListWrapperWidget,
OO.ui.mixin.PendingElement );
+
+ /**
+ * Respond to model invalidate
+ */
+ mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelInvalidate =
function () {
+ this.pushPending();
+ };
+
+ /**
+ * Respond to model update
+ *
+ * @param {jQuery|string} changesListContent The content of the updated
changes list
+ */
+ mw.rcfilters.ui.ChangesListWrapperWidget.prototype.onModelUpdate =
function ( changesListContent ) {
+ var isEmpty = changesListContent === 'NO_RESULTS';
+ this.$element.toggleClass( 'mw-changeslist', !isEmpty );
+ this.$element.toggleClass( 'mw-changeslist-empty', isEmpty );
+ this.$element.empty().append(
+ isEmpty ?
+ document.createTextNode( mw.message(
'recentchanges-noresult' ).text() ) :
+ changesListContent
+ );
+ this.popPending();
+ };
+}( mediaWiki ) );
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CheckboxInputWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CheckboxInputWidget.js
new file mode 100644
index 0000000..86b3b11
--- /dev/null
+++
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.CheckboxInputWidget.js
@@ -0,0 +1,41 @@
+( function ( mw ) {
+ /**
+ * A widget representing a single toggle filter
+ *
+ * @extends OO.ui.CheckboxInputWidget
+ *
+ * @constructor
+ * @param {Object} config Configuration object
+ */
+ mw.rcfilters.ui.CheckboxInputWidget = function
MwRcfiltersUiCheckboxInputWidget( config ) {
+ config = config || {};
+
+ // Parent
+ mw.rcfilters.ui.CheckboxInputWidget.parent.call( this, config );
+
+ // Event
+ this.$input.on( 'change', this.onUserChange.bind( this ) );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.rcfilters.ui.CheckboxInputWidget,
OO.ui.CheckboxInputWidget );
+
+ /* Events */
+
+ /**
+ * @event userChange
+ * @param {boolean} Current state of the checkbox
+ *
+ * The user has checked or unchecked this checkbox
+ */
+
+ /* Methods */
+
+ /**
+ * Respond to checkbox change by a user and emit 'userChange'.
+ */
+ mw.rcfilters.ui.CheckboxInputWidget.prototype.onUserChange = function
() {
+ this.emit( 'userChange', this.$input.prop( 'checked' ) );
+ };
+}( mediaWiki ) );
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
index bf80cd6..56303d5 100644
---
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
+++
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterCapsuleMultiselectWidget.js
@@ -154,7 +154,11 @@
return;
}
- return new mw.rcfilters.ui.CapsuleItemWidget( item, { $overlay:
this.$overlay } );
+ return new mw.rcfilters.ui.CapsuleItemWidget(
+ this.controller,
+ item,
+ { $overlay: this.$overlay }
+ );
};
/**
@@ -203,23 +207,6 @@
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.onFocusForPopup =
function () {
// HACK can be removed once I21b8cff4048 is merged in oojs-ui
this.focus();
- };
-
- /**
- * @inheritdoc
- */
- mw.rcfilters.ui.FilterCapsuleMultiselectWidget.prototype.removeItems =
function ( items ) {
- var filterData = {};
-
- // Parent
-
mw.rcfilters.ui.FilterCapsuleMultiselectWidget.parent.prototype.removeItems.call(
this, items );
-
- items.forEach( function ( itemWidget ) {
- filterData[ itemWidget.getData() ] = false;
- } );
-
- // Update the model
- this.model.updateFilters( filterData );
};
/**
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js
index f353051..f9829d4 100644
--- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js
+++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterItemWidget.js
@@ -22,7 +22,7 @@
this.controller = controller;
this.model = model;
- this.checkboxWidget = new OO.ui.CheckboxInputWidget( {
+ this.checkboxWidget = new mw.rcfilters.ui.CheckboxInputWidget( {
value: this.model.getName(),
selected: this.model.isSelected()
} );
@@ -46,7 +46,7 @@
} );
// Event
- this.checkboxWidget.connect( this, { change: 'onCheckboxChange'
} );
+ this.checkboxWidget.connect( this, { userChange:
'onCheckboxChange' } );
this.model.connect( this, { update: 'onModelUpdate' } );
this.$element
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
index c863f2f..315ca86 100644
---
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
+++
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterWrapperWidget.js
@@ -8,7 +8,7 @@
* @constructor
* @param {mw.rcfilters.Controller} controller Controller
* @param {mw.rcfilters.dm.FiltersViewModel} model View model
- * @param {Object} config Configuration object
+ * @param {Object} [config] Configuration object
* @cfg {Object} [filters] A definition of the filter groups in this
list
* @cfg {jQuery} [$overlay] A jQuery object serving as overlay for
popups
*/
@@ -23,8 +23,6 @@
this.controller = controller;
this.model = model;
this.$overlay = config.$overlay || this.$element;
-
- this.filtersInCapsule = [];
this.filterPopup = new mw.rcfilters.ui.FiltersListWidget(
this.controller,
@@ -92,14 +90,5 @@
wrapper.capsule.addItemByName(
filterItem.getName() );
}
} );
- };
-
- /**
- * Add a capsule item by its filter name
- *
- * @param {string} itemName Filter name
- */
- mw.rcfilters.ui.FilterWrapperWidget.prototype.addCapsuleItemFromName =
function ( itemName ) {
- this.capsule.addItemByName( [ itemName ] );
};
}( mediaWiki ) );
diff --git
a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
new file mode 100644
index 0000000..2513b07
--- /dev/null
+++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FormWrapperWidget.js
@@ -0,0 +1,47 @@
+( function ( mw ) {
+ /**
+ * Wrapper for the RC form with hide/show links
+ *
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {mw.rcfilters.dm.ChangesListViewModel} model Changes list
view model
+ * @param {jQuery} $formRoot Root element of the form to attach to
+ * @param {Object} config Configuration object
+ */
+ mw.rcfilters.ui.FormWrapperWidget = function
MwRcfiltersUiFormWrapperWidget( model, $formRoot, config ) {
+ config = config || {};
+
+ // Parent
+ mw.rcfilters.ui.FormWrapperWidget.parent.call( this, $.extend(
{}, config, {
+ $element: $formRoot
+ } ) );
+
+ this.model = model;
+ this.$submitButton = this.$element.find( 'input[type=submit]' );
+
+ // Events
+ this.model.connect( this, {
+ invalidate: 'onModelInvalidate',
+ update: 'onModelUpdate'
+ } );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.rcfilters.ui.FormWrapperWidget, OO.ui.Widget );
+
+ /**
+ * Respond to model invalidate
+ */
+ mw.rcfilters.ui.FormWrapperWidget.prototype.onModelInvalidate =
function () {
+ this.$submitButton.prop( 'disabled', true );
+ };
+
+ /**
+ * Respond to model update
+ */
+ mw.rcfilters.ui.FormWrapperWidget.prototype.onModelUpdate = function ()
{
+ this.$submitButton.prop( 'disabled', false );
+ };
+}( mediaWiki ) );
--
To view, visit https://gerrit.wikimedia.org/r/328676
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I8c1ec557ccfe4b1d20aaaab3ef0d3182a1993f24
Gerrit-PatchSet: 16
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Sbisson <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits